From fc51201451a8dc06f64f11ffaf252afc6666632b Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Mon, 5 Apr 2021 15:35:49 +0100 Subject: [PATCH] New upstream version 1.50.0+dfsg1 --- Cargo.lock | 301 +- Cargo.toml | 3 + RELEASES.md | 122 +- compiler/rustc_arena/src/lib.rs | 84 +- compiler/rustc_ast/src/ast.rs | 69 +- compiler/rustc_ast/src/attr/mod.rs | 31 + compiler/rustc_ast/src/lib.rs | 1 - compiler/rustc_ast/src/mut_visit.rs | 41 +- compiler/rustc_ast/src/token.rs | 23 +- compiler/rustc_ast/src/tokenstream.rs | 13 +- compiler/rustc_ast/src/util/comments.rs | 58 +- compiler/rustc_ast/src/util/comments/tests.rs | 14 +- compiler/rustc_ast/src/visit.rs | 7 +- compiler/rustc_ast_lowering/src/expr.rs | 56 +- compiler/rustc_ast_lowering/src/item.rs | 30 +- compiler/rustc_ast_lowering/src/lib.rs | 114 +- .../rustc_ast_passes/src/ast_validation.rs | 8 +- compiler/rustc_ast_passes/src/feature_gate.rs | 14 +- compiler/rustc_ast_passes/src/lib.rs | 1 + compiler/rustc_ast_pretty/src/pprust/state.rs | 25 +- compiler/rustc_attr/src/builtin.rs | 6 +- compiler/rustc_builtin_macros/src/assert.rs | 52 +- .../src/cfg_accessible.rs | 11 +- .../src/deriving/debug.rs | 5 +- .../src/deriving/generic/mod.rs | 25 +- .../rustc_builtin_macros/src/deriving/mod.rs | 29 +- .../src/format_foreign.rs | 16 +- .../src/global_allocator.rs | 22 +- .../src/standard_library_imports.rs | 6 +- compiler/rustc_builtin_macros/src/test.rs | 40 +- compiler/rustc_codegen_cranelift/Cargo.lock | 104 +- compiler/rustc_codegen_cranelift/Cargo.toml | 4 +- compiler/rustc_codegen_cranelift/Readme.md | 6 +- compiler/rustc_codegen_cranelift/build.sh | 25 +- .../build_sysroot/Cargo.lock | 20 +- .../build_sysroot/alloc_system/lib.rs | 6 +- .../build_sysroot/build_sysroot.sh | 13 +- .../build_sysroot/prepare_sysroot_src.sh | 12 +- .../example/mini_core.rs | 2 +- .../example/std_example.rs | 1 + ...022-core-Disable-not-compiling-tests.patch | 8 +- compiler/rustc_codegen_cranelift/prepare.sh | 1 + .../rustc_codegen_cranelift/rust-toolchain | 2 +- .../rustc_codegen_cranelift/scripts/cargo.sh | 8 +- .../rustc_codegen_cranelift/scripts/config.sh | 19 +- .../rustc_codegen_cranelift/scripts/rustup.sh | 38 +- .../scripts/test_bootstrap.sh | 6 +- .../rustc_codegen_cranelift/scripts/tests.sh | 30 +- .../rustc_codegen_cranelift/src/abi/mod.rs | 18 +- .../rustc_codegen_cranelift/src/analyze.rs | 2 +- .../rustc_codegen_cranelift/src/archive.rs | 6 +- .../src/atomic_shim.rs | 3 +- compiler/rustc_codegen_cranelift/src/base.rs | 78 +- .../src/bin/cg_clif.rs | 18 +- .../rustc_codegen_cranelift/src/common.rs | 6 +- .../rustc_codegen_cranelift/src/constant.rs | 15 +- .../src/debuginfo/emit.rs | 7 +- .../src/debuginfo/mod.rs | 2 +- .../src/debuginfo/unwind.rs | 4 +- .../src/discriminant.rs | 31 +- .../rustc_codegen_cranelift/src/driver/aot.rs | 9 +- .../rustc_codegen_cranelift/src/driver/jit.rs | 16 +- .../rustc_codegen_cranelift/src/driver/mod.rs | 26 +- .../src/intrinsics/mod.rs | 84 +- .../src/intrinsics/simd.rs | 65 +- .../rustc_codegen_cranelift/src/main_shim.rs | 2 +- .../src/pretty_clif.rs | 2 +- compiler/rustc_codegen_cranelift/src/trap.rs | 12 + .../src/value_and_place.rs | 32 +- compiler/rustc_codegen_llvm/src/abi.rs | 146 +- compiler/rustc_codegen_llvm/src/asm.rs | 4 + compiler/rustc_codegen_llvm/src/attributes.rs | 49 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 21 +- compiler/rustc_codegen_llvm/src/back/write.rs | 83 +- compiler/rustc_codegen_llvm/src/base.rs | 6 +- compiler/rustc_codegen_llvm/src/context.rs | 8 - .../src/coverageinfo/mapgen.rs | 385 +- .../src/coverageinfo/mod.rs | 54 +- .../src/debuginfo/create_scope_map.rs | 2 +- .../src/debuginfo/metadata.rs | 30 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 115 +- compiler/rustc_codegen_llvm/src/lib.rs | 17 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 18 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 12 + compiler/rustc_codegen_llvm/src/llvm_util.rs | 31 +- compiler/rustc_codegen_llvm/src/type_of.rs | 12 +- compiler/rustc_codegen_ssa/src/back/link.rs | 250 +- compiler/rustc_codegen_ssa/src/back/write.rs | 36 +- compiler/rustc_codegen_ssa/src/base.rs | 7 +- .../rustc_codegen_ssa/src/coverageinfo/ffi.rs | 8 +- .../src/debuginfo/type_names.rs | 15 +- compiler/rustc_codegen_ssa/src/lib.rs | 27 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 8 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 38 +- .../rustc_codegen_ssa/src/mir/constant.rs | 10 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 107 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 88 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 10 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/place.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 13 +- .../rustc_codegen_ssa/src/target_features.rs | 13 + .../rustc_codegen_ssa/src/traits/backend.rs | 4 +- .../rustc_data_structures/src/fingerprint.rs | 59 + compiler/rustc_data_structures/src/functor.rs | 82 + .../src/graph/iterate/mod.rs | 2 - .../src/graph/scc/mod.rs | 387 +- .../src/graph/scc/tests.rs | 72 + compiler/rustc_data_structures/src/lib.rs | 19 +- .../rustc_data_structures/src/profiling.rs | 22 + .../src/sorted_map/index_map.rs | 3 +- compiler/rustc_data_structures/src/sso/map.rs | 2 +- .../ty => rustc_data_structures/src}/steal.rs | 11 +- compiler/rustc_driver/src/lib.rs | 63 +- compiler/rustc_driver/src/pretty.rs | 5 - compiler/rustc_error_codes/src/error_codes.rs | 4 +- .../src/error_codes/E0198.md | 2 +- .../src/error_codes/E0212.md | 35 + .../src/error_codes/E0321.md | 2 +- .../src/error_codes/E0390.md | 5 +- .../src/error_codes/E0546.md | 27 + .../src/error_codes/E0567.md | 4 +- .../src/error_codes/E0568.md | 4 +- .../src/error_codes/E0591.md | 20 +- .../src/error_codes/E0744.md | 19 +- compiler/rustc_errors/src/diagnostic.rs | 27 +- .../rustc_errors/src/diagnostic_builder.rs | 58 +- compiler/rustc_errors/src/emitter.rs | 17 + compiler/rustc_expand/src/base.rs | 20 +- compiler/rustc_expand/src/build.rs | 26 +- compiler/rustc_expand/src/config.rs | 45 + compiler/rustc_expand/src/expand.rs | 413 +- compiler/rustc_expand/src/lib.rs | 3 - compiler/rustc_expand/src/mbe/macro_parser.rs | 38 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 3 +- compiler/rustc_expand/src/placeholders.rs | 11 +- compiler/rustc_expand/src/proc_macro.rs | 52 +- compiler/rustc_feature/src/active.rs | 14 +- compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_feature/src/lib.rs | 18 +- compiler/rustc_feature/src/removed.rs | 5 +- compiler/rustc_feature/src/tests.rs | 23 + compiler/rustc_hir/src/arena.rs | 3 +- compiler/rustc_hir/src/def.rs | 11 +- compiler/rustc_hir/src/hir.rs | 69 +- compiler/rustc_hir/src/intravisit.rs | 44 +- compiler/rustc_hir/src/itemlikevisit.rs | 4 +- compiler/rustc_hir/src/stable_hash_impls.rs | 19 +- compiler/rustc_hir/src/target.rs | 25 +- compiler/rustc_hir_pretty/src/lib.rs | 30 +- .../src/persist/dirty_clean.rs | 6 +- .../src/persist/file_format.rs | 12 +- .../rustc_incremental/src/persist/load.rs | 38 +- .../rustc_incremental/src/persist/save.rs | 2 +- compiler/rustc_index/src/bit_set.rs | 1 - compiler/rustc_index/src/lib.rs | 1 - .../src/infer/canonical/canonicalizer.rs | 27 +- .../rustc_infer/src/infer/canonical/mod.rs | 6 +- .../src/infer/canonical/query_response.rs | 29 +- .../src/infer/canonical/substitute.rs | 14 +- compiler/rustc_infer/src/infer/combine.rs | 18 +- .../src/infer/error_reporting/mod.rs | 46 +- .../infer/error_reporting/need_type_info.rs | 38 +- .../nice_region_error/different_lifetimes.rs | 4 +- .../nice_region_error/find_anon_type.rs | 8 +- .../nice_region_error/placeholder_error.rs | 9 +- .../nice_region_error/static_impl_trait.rs | 4 +- .../trait_impl_difference.rs | 2 +- .../error_reporting/nice_region_error/util.rs | 14 +- .../src/infer/error_reporting/note.rs | 2 +- compiler/rustc_infer/src/infer/fudge.rs | 2 +- .../src/infer/higher_ranked/mod.rs | 21 +- .../src/infer/lexical_region_resolve/mod.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 31 +- .../rustc_infer/src/infer/nll_relate/mod.rs | 11 +- .../src/infer/outlives/obligations.rs | 4 +- .../rustc_infer/src/infer/outlives/verify.rs | 4 +- compiler/rustc_infer/src/infer/resolve.rs | 13 +- .../src/traits/structural_impls.rs | 6 +- compiler/rustc_infer/src/traits/util.rs | 4 +- compiler/rustc_interface/Cargo.toml | 2 +- compiler/rustc_interface/src/interface.rs | 9 +- compiler/rustc_interface/src/lib.rs | 2 +- compiler/rustc_interface/src/passes.rs | 17 +- .../rustc_interface/src/proc_macro_decls.rs | 2 + compiler/rustc_interface/src/queries.rs | 20 +- compiler/rustc_interface/src/tests.rs | 7 +- compiler/rustc_interface/src/util.rs | 36 +- compiler/rustc_lexer/src/lib.rs | 10 +- compiler/rustc_lexer/src/unescape.rs | 2 +- compiler/rustc_lint/Cargo.toml | 1 + compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/context.rs | 21 +- compiler/rustc_lint/src/internal.rs | 46 +- compiler/rustc_lint/src/levels.rs | 176 +- compiler/rustc_lint/src/lib.rs | 8 +- compiler/rustc_lint/src/nonstandard_style.rs | 58 +- compiler/rustc_lint/src/panic_fmt.rs | 151 + .../rustc_lint/src/redundant_semicolon.rs | 21 +- compiler/rustc_lint/src/types.rs | 24 +- compiler/rustc_lint/src/unused.rs | 8 +- compiler/rustc_lint_defs/src/builtin.rs | 101 +- compiler/rustc_lint_defs/src/lib.rs | 24 +- compiler/rustc_llvm/build.rs | 36 +- .../llvm-wrapper/CoverageMappingWrapper.cpp | 52 +- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 58 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 23 +- compiler/rustc_llvm/src/lib.rs | 3 +- compiler/rustc_macros/src/lib.rs | 2 +- compiler/rustc_macros/src/query.rs | 2 +- compiler/rustc_macros/src/symbols.rs | 189 +- compiler/rustc_macros/src/symbols/tests.rs | 102 + compiler/rustc_macros/src/type_foldable.rs | 18 +- compiler/rustc_metadata/src/creader.rs | 11 +- .../rustc_metadata/src/foreign_modules.rs | 7 +- compiler/rustc_metadata/src/lib.rs | 1 - compiler/rustc_metadata/src/link_args.rs | 7 +- compiler/rustc_metadata/src/native_libs.rs | 7 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 183 +- .../src/rmeta/decoder/cstore_impl.rs | 28 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 63 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 + compiler/rustc_middle/Cargo.toml | 1 + compiler/rustc_middle/src/arena.rs | 5 +- .../rustc_middle/src/dep_graph/dep_node.rs | 28 +- compiler/rustc_middle/src/dep_graph/mod.rs | 20 +- .../rustc_middle/src/hir/map/collector.rs | 27 +- compiler/rustc_middle/src/hir/map/mod.rs | 69 +- compiler/rustc_middle/src/hir/place.rs | 63 +- compiler/rustc_middle/src/ich/impls_ty.rs | 15 +- compiler/rustc_middle/src/infer/canonical.rs | 33 +- compiler/rustc_middle/src/lib.rs | 3 +- compiler/rustc_middle/src/lint.rs | 57 +- compiler/rustc_middle/src/macros.rs | 18 +- compiler/rustc_middle/src/middle/cstore.rs | 8 +- compiler/rustc_middle/src/middle/limits.rs | 3 +- compiler/rustc_middle/src/middle/privacy.rs | 10 +- compiler/rustc_middle/src/middle/region.rs | 6 +- compiler/rustc_middle/src/middle/stability.rs | 80 +- compiler/rustc_middle/src/mir/coverage.rs | 6 +- .../rustc_middle/src/mir/interpret/error.rs | 2 +- .../rustc_middle/src/mir/interpret/mod.rs | 1 - .../rustc_middle/src/mir/interpret/queries.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 76 +- compiler/rustc_middle/src/mir/predecessors.rs | 2 +- compiler/rustc_middle/src/mir/query.rs | 11 +- compiler/rustc_middle/src/mir/tcx.rs | 9 + .../rustc_middle/src/mir/type_foldable.rs | 126 +- compiler/rustc_middle/src/mir/visit.rs | 159 +- compiler/rustc_middle/src/query/mod.rs | 29 +- compiler/rustc_middle/src/traits/mod.rs | 11 +- compiler/rustc_middle/src/traits/select.rs | 2 +- .../src/traits/structural_impls.rs | 6 +- compiler/rustc_middle/src/ty/_match.rs | 2 +- compiler/rustc_middle/src/ty/binding.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 19 +- compiler/rustc_middle/src/ty/consts/kind.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 125 +- compiler/rustc_middle/src/ty/erase_regions.rs | 10 +- compiler/rustc_middle/src/ty/error.rs | 10 +- compiler/rustc_middle/src/ty/flags.rs | 20 +- compiler/rustc_middle/src/ty/fold.rs | 203 +- .../src/ty/inhabitedness/def_id_forest.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 14 +- compiler/rustc_middle/src/ty/layout.rs | 363 +- compiler/rustc_middle/src/ty/list.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 312 +- .../src/ty/normalize_erasing_regions.rs | 6 +- compiler/rustc_middle/src/ty/print/mod.rs | 6 +- compiler/rustc_middle/src/ty/print/pretty.rs | 175 +- compiler/rustc_middle/src/ty/query/mod.rs | 4 +- .../src/ty/query/on_disk_cache.rs | 224 +- .../rustc_middle/src/ty/query/plumbing.rs | 9 +- compiler/rustc_middle/src/ty/relate.rs | 32 +- .../rustc_middle/src/ty/structural_impls.rs | 216 +- compiler/rustc_middle/src/ty/sty.rs | 309 +- compiler/rustc_middle/src/ty/subst.rs | 20 +- compiler/rustc_middle/src/ty/util.rs | 46 +- compiler/rustc_mir/Cargo.toml | 4 + .../src/borrow_check/diagnostics/mod.rs | 31 +- .../borrow_check/diagnostics/region_errors.rs | 2 +- .../borrow_check/diagnostics/region_name.rs | 8 +- compiler/rustc_mir/src/borrow_check/mod.rs | 42 +- .../src/borrow_check/region_infer/mod.rs | 24 +- .../borrow_check/region_infer/opaque_types.rs | 6 +- .../rustc_mir/src/borrow_check/renumber.rs | 8 +- .../borrow_check/type_check/input_output.rs | 2 +- .../src/borrow_check/type_check/mod.rs | 96 +- .../src/borrow_check/universal_regions.rs | 24 +- compiler/rustc_mir/src/const_eval/error.rs | 2 + .../rustc_mir/src/const_eval/eval_queries.rs | 65 +- compiler/rustc_mir/src/const_eval/machine.rs | 100 +- .../src/dataflow/drop_flag_effects.rs | 2 +- .../rustc_mir/src/dataflow/impls/liveness.rs | 2 +- .../rustc_mir/src/interpret/eval_context.rs | 57 +- compiler/rustc_mir/src/interpret/intern.rs | 30 +- .../rustc_mir/src/interpret/intrinsics.rs | 85 +- .../src/interpret/intrinsics/type_name.rs | 2 +- compiler/rustc_mir/src/interpret/machine.rs | 20 +- compiler/rustc_mir/src/interpret/step.rs | 6 +- .../rustc_mir/src/interpret/terminator.rs | 2 +- compiler/rustc_mir/src/interpret/traits.rs | 15 +- compiler/rustc_mir/src/interpret/util.rs | 15 +- compiler/rustc_mir/src/interpret/validity.rs | 20 +- compiler/rustc_mir/src/lib.rs | 1 + .../rustc_mir/src/monomorphize/collector.rs | 8 +- .../src/monomorphize/partitioning/default.rs | 2 +- .../src/monomorphize/polymorphize.rs | 10 +- compiler/rustc_mir/src/shim.rs | 29 +- .../transform/check_const_item_mutation.rs | 8 +- .../src/transform/check_consts/ops.rs | 3 +- .../src/transform/check_consts/qualifs.rs | 8 +- .../src/transform/check_consts/validation.rs | 72 +- .../rustc_mir/src/transform/check_unsafety.rs | 165 +- .../src/transform/const_debuginfo.rs | 102 + .../rustc_mir/src/transform/const_prop.rs | 8 +- .../src/transform/coverage/counters.rs | 5 +- .../rustc_mir/src/transform/coverage/debug.rs | 106 +- .../rustc_mir/src/transform/coverage/graph.rs | 70 +- .../rustc_mir/src/transform/coverage/mod.rs | 112 +- .../rustc_mir/src/transform/coverage/query.rs | 37 +- .../rustc_mir/src/transform/coverage/spans.rs | 170 +- .../transform/coverage/test_macros/Cargo.toml | 9 + .../transform/coverage/test_macros/src/lib.rs | 6 + .../rustc_mir/src/transform/coverage/tests.rs | 714 + .../src/transform/early_otherwise_branch.rs | 38 +- compiler/rustc_mir/src/transform/generator.rs | 6 +- compiler/rustc_mir/src/transform/inline.rs | 95 +- .../rustc_mir/src/transform/instcombine.rs | 28 +- .../src/transform/lower_intrinsics.rs | 119 + .../rustc_mir/src/transform/match_branches.rs | 5 + compiler/rustc_mir/src/transform/mod.rs | 6 +- .../transform/multiple_return_terminators.rs | 5 + compiler/rustc_mir/src/transform/nrvo.rs | 10 +- .../rustc_mir/src/transform/promote_consts.rs | 58 +- .../src/transform/remove_unneeded_drops.rs | 6 + .../rustc_mir/src/transform/simplify_try.rs | 43 +- .../src/transform/unreachable_prop.rs | 6 + compiler/rustc_mir/src/transform/validate.rs | 15 +- .../rustc_mir/src/util/borrowck_errors.rs | 7 +- compiler/rustc_mir/src/util/generic_graph.rs | 70 + .../rustc_mir/src/util/generic_graphviz.rs | 8 +- compiler/rustc_mir/src/util/graphviz.rs | 149 +- compiler/rustc_mir/src/util/mod.rs | 5 +- compiler/rustc_mir/src/util/pretty.rs | 32 +- .../src/build/expr/as_operand.rs | 4 +- .../src/build/expr/as_place.rs | 351 +- .../src/build/expr/as_rvalue.rs | 89 +- .../src/build/expr/category.rs | 2 +- .../rustc_mir_build/src/build/expr/into.rs | 17 +- .../rustc_mir_build/src/build/matches/mod.rs | 79 +- .../rustc_mir_build/src/build/matches/test.rs | 11 + compiler/rustc_mir_build/src/build/mod.rs | 46 +- compiler/rustc_mir_build/src/build/scope.rs | 42 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 203 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 4 + compiler/rustc_mir_build/src/thir/mod.rs | 11 +- .../src/thir/pattern/_match.rs | 2285 - .../src/thir/pattern/check_match.rs | 171 +- .../src/thir/pattern/deconstruct_pat.rs | 1427 + .../rustc_mir_build/src/thir/pattern/mod.rs | 3 +- .../src/thir/pattern/usefulness.rs | 1070 + compiler/rustc_parse/src/lexer/mod.rs | 7 +- .../src/lexer/unescape_error_reporting.rs | 9 +- compiler/rustc_parse/src/lib.rs | 62 +- compiler/rustc_parse/src/parser/attr.rs | 19 +- .../rustc_parse/src/parser/diagnostics.rs | 28 +- compiler/rustc_parse/src/parser/expr.rs | 38 +- compiler/rustc_parse/src/parser/generics.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 48 +- compiler/rustc_parse/src/parser/mod.rs | 133 +- .../rustc_parse/src/parser/nonterminal.rs | 27 +- compiler/rustc_parse/src/parser/pat.rs | 50 +- compiler/rustc_parse/src/parser/path.rs | 122 +- compiler/rustc_parse/src/parser/stmt.rs | 128 +- compiler/rustc_parse/src/parser/ty.rs | 105 +- compiler/rustc_passes/Cargo.toml | 1 + compiler/rustc_passes/src/check_attr.rs | 351 +- compiler/rustc_passes/src/check_const.rs | 5 +- compiler/rustc_passes/src/dead.rs | 38 +- compiler/rustc_passes/src/diagnostic_items.rs | 18 +- compiler/rustc_passes/src/entry.rs | 6 +- compiler/rustc_passes/src/hir_id_validator.rs | 12 + compiler/rustc_passes/src/intrinsicck.rs | 2 +- compiler/rustc_passes/src/lang_items.rs | 2 + compiler/rustc_passes/src/layout_test.rs | 1 + compiler/rustc_passes/src/lib.rs | 3 + compiler/rustc_passes/src/liveness.rs | 337 +- .../rustc_passes/src/liveness/rwu_table.rs | 144 + compiler/rustc_passes/src/naked_functions.rs | 322 + compiler/rustc_passes/src/reachable.rs | 6 +- compiler/rustc_passes/src/stability.rs | 48 +- compiler/rustc_plugin_impl/src/build.rs | 2 + compiler/rustc_privacy/src/lib.rs | 67 +- .../src/dep_graph/dep_node.rs | 20 +- .../rustc_query_system/src/dep_graph/graph.rs | 925 +- .../rustc_query_system/src/dep_graph/mod.rs | 2 + .../rustc_query_system/src/dep_graph/query.rs | 18 +- .../src/dep_graph/serialized.rs | 7 +- compiler/rustc_query_system/src/query/job.rs | 6 +- .../rustc_resolve/src/build_reduced_graph.rs | 44 +- compiler/rustc_resolve/src/diagnostics.rs | 9 +- compiler/rustc_resolve/src/imports.rs | 48 +- compiler/rustc_resolve/src/late.rs | 65 +- .../rustc_resolve/src/late/diagnostics.rs | 34 +- compiler/rustc_resolve/src/late/lifetimes.rs | 4 +- compiler/rustc_resolve/src/lib.rs | 33 +- compiler/rustc_resolve/src/macros.rs | 160 +- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_save_analysis/src/sig.rs | 6 +- compiler/rustc_serialize/src/json.rs | 2 +- compiler/rustc_session/src/config.rs | 222 +- compiler/rustc_session/src/lib.rs | 1 + compiler/rustc_session/src/options.rs | 47 +- compiler/rustc_session/src/parse.rs | 6 +- compiler/rustc_session/src/session.rs | 51 +- .../rustc_span/src/analyze_source_file.rs | 4 +- .../util => rustc_span/src}/lev_distance.rs | 23 +- .../src}/lev_distance/tests.rs | 17 +- compiler/rustc_span/src/lib.rs | 8 +- compiler/rustc_span/src/source_map.rs | 6 +- compiler/rustc_span/src/symbol.rs | 115 +- compiler/rustc_symbol_mangling/src/legacy.rs | 4 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/test.rs | 6 +- compiler/rustc_symbol_mangling/src/v0.rs | 43 +- compiler/rustc_target/src/abi/call/mips64.rs | 6 +- compiler/rustc_target/src/abi/call/mod.rs | 61 +- compiler/rustc_target/src/abi/call/riscv.rs | 4 +- compiler/rustc_target/src/abi/call/x86.rs | 9 +- compiler/rustc_target/src/asm/mod.rs | 70 +- compiler/rustc_target/src/asm/wasm.rs | 46 + compiler/rustc_target/src/lib.rs | 1 + .../src/spec/aarch64_apple_ios_macabi.rs | 31 + .../src/spec/aarch64_unknown_cloudabi.rs | 16 - .../src/spec/aarch64_unknown_none.rs | 1 - .../spec/aarch64_unknown_none_softfloat.rs | 1 - compiler/rustc_target/src/spec/apple_base.rs | 5 +- .../rustc_target/src/spec/apple_sdk_base.rs | 4 +- .../src/spec/armebv7r_none_eabi.rs | 1 - .../src/spec/armebv7r_none_eabihf.rs | 1 - .../spec/armv5te_unknown_linux_uclibceabi.rs | 20 + .../src/spec/armv7_unknown_cloudabi_eabihf.rs | 18 - .../rustc_target/src/spec/armv7a_none_eabi.rs | 4 - .../src/spec/armv7a_none_eabihf.rs | 1 - .../rustc_target/src/spec/armv7r_none_eabi.rs | 1 - .../src/spec/armv7r_none_eabihf.rs | 1 - .../rustc_target/src/spec/avr_gnu_base.rs | 1 - .../rustc_target/src/spec/cloudabi_base.rs | 36 - .../rustc_target/src/spec/fuchsia_base.rs | 1 - .../src/spec/i686_unknown_cloudabi.rs | 20 - .../src/spec/mipsel_unknown_none.rs | 1 - compiler/rustc_target/src/spec/mod.rs | 70 +- .../rustc_target/src/spec/msp430_none_elf.rs | 1 - .../rustc_target/src/spec/tests/tests_impl.rs | 15 + compiler/rustc_target/src/spec/thumb_base.rs | 1 - .../rustc_target/src/spec/uefi_msvc_base.rs | 9 - compiler/rustc_target/src/spec/wasm32_wasi.rs | 1 - .../rustc_target/src/spec/windows_gnu_base.rs | 4 + .../src/spec/x86_64_pc_windows_gnu.rs | 5 +- .../src/spec/x86_64_unknown_cloudabi.rs | 19 - .../src/spec/x86_64_uwp_windows_gnu.rs | 5 +- .../rustc_trait_selection/src/autoderef.rs | 6 +- compiler/rustc_trait_selection/src/infer.rs | 8 +- .../rustc_trait_selection/src/opaque_types.rs | 34 +- .../src/traits/auto_trait.rs | 9 +- .../src/traits/chalk_fulfill.rs | 8 +- .../src/traits/codegen.rs | 8 +- .../src/traits/coherence.rs | 7 +- .../src/traits/const_evaluatable.rs | 14 +- .../src/traits/error_reporting/mod.rs | 62 +- .../error_reporting/on_unimplemented.rs | 6 +- .../src/traits/error_reporting/suggestions.rs | 190 +- .../src/traits/fulfill.rs | 18 +- .../rustc_trait_selection/src/traits/misc.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 26 +- .../src/traits/object_safety.rs | 42 +- .../src/traits/project.rs | 56 +- .../src/traits/query/dropck_outlives.rs | 6 +- .../src/traits/query/evaluate_obligation.rs | 2 +- .../src/traits/query/normalize.rs | 13 +- .../src/traits/query/outlives_bounds.rs | 4 +- .../src/traits/query/type_op/custom.rs | 2 +- .../src/traits/query/type_op/mod.rs | 8 +- .../src/traits/select/candidate_assembly.rs | 17 +- .../src/traits/select/confirmation.rs | 104 +- .../src/traits/select/mod.rs | 90 +- .../src/traits/specialize/mod.rs | 8 +- .../src/traits/structural_match.rs | 53 +- .../rustc_trait_selection/src/traits/util.rs | 16 +- .../rustc_trait_selection/src/traits/wf.rs | 8 +- compiler/rustc_traits/src/chalk/db.rs | 16 +- compiler/rustc_traits/src/chalk/lowering.rs | 161 +- compiler/rustc_traits/src/chalk/mod.rs | 2 +- compiler/rustc_traits/src/dropck_outlives.rs | 2 +- .../src/implied_outlives_bounds.rs | 2 +- .../src/normalize_erasing_regions.rs | 14 +- compiler/rustc_traits/src/type_op.rs | 4 +- .../{rustc_ty => rustc_ty_utils}/Cargo.toml | 2 +- .../src/common_traits.rs | 0 .../src/instance.rs | 10 +- .../{rustc_ty => rustc_ty_utils}/src/lib.rs | 0 .../src/needs_drop.rs | 10 +- .../{rustc_ty => rustc_ty_utils}/src/ty.rs | 4 +- compiler/rustc_type_ir/Cargo.toml | 14 + compiler/rustc_type_ir/src/lib.rs | 204 + compiler/rustc_typeck/src/astconv/errors.rs | 4 +- compiler/rustc_typeck/src/astconv/generics.rs | 214 +- compiler/rustc_typeck/src/astconv/mod.rs | 293 +- compiler/rustc_typeck/src/bounds.rs | 30 +- compiler/rustc_typeck/src/check/_match.rs | 36 +- compiler/rustc_typeck/src/check/callee.rs | 8 +- compiler/rustc_typeck/src/check/cast.rs | 14 +- compiler/rustc_typeck/src/check/check.rs | 140 +- compiler/rustc_typeck/src/check/closure.rs | 58 +- compiler/rustc_typeck/src/check/coercion.rs | 10 +- .../rustc_typeck/src/check/compare_method.rs | 25 +- compiler/rustc_typeck/src/check/demand.rs | 66 +- compiler/rustc_typeck/src/check/dropck.rs | 4 +- .../rustc_typeck/src/check/expectation.rs | 6 +- compiler/rustc_typeck/src/check/expr.rs | 46 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 194 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 10 +- .../rustc_typeck/src/check/fn_ctxt/mod.rs | 2 +- .../src/check/fn_ctxt/suggestions.rs | 4 +- .../rustc_typeck/src/check/gather_locals.rs | 9 +- .../src/check/generator_interior.rs | 18 +- compiler/rustc_typeck/src/check/inherited.rs | 2 +- compiler/rustc_typeck/src/check/intrinsic.rs | 59 +- .../rustc_typeck/src/check/method/confirm.rs | 89 +- compiler/rustc_typeck/src/check/method/mod.rs | 8 +- .../rustc_typeck/src/check/method/probe.rs | 63 +- .../rustc_typeck/src/check/method/suggest.rs | 126 +- compiler/rustc_typeck/src/check/mod.rs | 17 +- compiler/rustc_typeck/src/check/op.rs | 14 +- compiler/rustc_typeck/src/check/pat.rs | 20 +- compiler/rustc_typeck/src/check/regionck.rs | 2 +- compiler/rustc_typeck/src/check/upvar.rs | 755 +- compiler/rustc_typeck/src/check/wfcheck.rs | 69 +- compiler/rustc_typeck/src/check/writeback.rs | 74 +- compiler/rustc_typeck/src/check_unused.rs | 4 + .../src/coherence/inherent_impls.rs | 59 +- .../src/coherence/inherent_impls_overlap.rs | 177 +- compiler/rustc_typeck/src/coherence/orphan.rs | 2 + .../rustc_typeck/src/coherence/unsafety.rs | 2 + compiler/rustc_typeck/src/collect.rs | 50 +- compiler/rustc_typeck/src/collect/type_of.rs | 4 +- .../src/constrained_generic_params.rs | 6 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 116 +- compiler/rustc_typeck/src/impl_wf_check.rs | 2 + .../src/impl_wf_check/min_specialization.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 21 +- .../rustc_typeck/src/mem_categorization.rs | 6 +- .../src/outlives/implicit_infer.rs | 2 + compiler/rustc_typeck/src/outlives/mod.rs | 6 +- compiler/rustc_typeck/src/outlives/test.rs | 1 + .../rustc_typeck/src/variance/constraints.rs | 14 +- compiler/rustc_typeck/src/variance/terms.rs | 14 +- compiler/rustc_typeck/src/variance/test.rs | 1 + config.toml.example | 13 + git-commit-hash | 2 +- library/alloc/Cargo.toml | 2 + library/alloc/src/alloc.rs | 62 +- library/alloc/src/alloc/tests.rs | 4 +- library/alloc/src/boxed.rs | 167 +- library/alloc/src/collections/btree/append.rs | 17 +- library/alloc/src/collections/btree/map.rs | 96 +- .../alloc/src/collections/btree/map/entry.rs | 16 +- .../alloc/src/collections/btree/map/tests.rs | 202 +- .../collections/btree/map/tests/ord_chaos.rs | 81 + library/alloc/src/collections/btree/mem.rs | 1 + .../alloc/src/collections/btree/navigate.rs | 23 +- library/alloc/src/collections/btree/node.rs | 909 +- .../alloc/src/collections/btree/node/tests.rs | 42 +- library/alloc/src/collections/btree/remove.rs | 230 +- library/alloc/src/collections/btree/search.rs | 22 +- library/alloc/src/collections/btree/set.rs | 36 +- .../alloc/src/collections/btree/set/tests.rs | 32 +- library/alloc/src/collections/btree/split.rs | 32 +- library/alloc/src/collections/linked_list.rs | 62 - library/alloc/src/collections/mod.rs | 6 +- .../src/collections/vec_deque/into_iter.rs | 57 + .../alloc/src/collections/vec_deque/iter.rs | 159 + .../src/collections/vec_deque/iter_mut.rs | 128 + .../alloc/src/collections/vec_deque/macros.rs | 19 + .../{vec_deque.rs => vec_deque/mod.rs} | 519 +- .../src/collections/vec_deque/pair_slices.rs | 66 + .../src/collections/vec_deque/ring_slices.rs | 56 + library/alloc/src/lib.rs | 8 +- library/alloc/src/macros.rs | 4 + library/alloc/src/raw_vec.rs | 37 +- library/alloc/src/raw_vec/tests.rs | 10 +- library/alloc/src/rc.rs | 18 +- library/alloc/src/slice.rs | 103 +- library/alloc/src/str.rs | 2 +- library/alloc/src/string.rs | 2 +- library/alloc/src/sync.rs | 16 +- library/alloc/src/vec.rs | 663 +- library/alloc/tests/heap.rs | 8 +- library/alloc/tests/str.rs | 101 +- library/alloc/tests/vec.rs | 6 +- library/alloc/tests/vec_deque.rs | 7 + library/backtrace/.github/workflows/main.yml | 23 +- library/backtrace/Cargo.toml | 8 +- library/backtrace/ci/android-sdk.sh | 9 - .../docker/s390x-unknown-linux-gnu/Dockerfile | 17 + library/backtrace/ci/run-docker.sh | 1 + library/backtrace/crates/as-if-std/Cargo.toml | 6 +- .../crates/cpp_smoke_test/tests/smoke.rs | 1 - library/backtrace/crates/dylib-dep/src/lib.rs | 2 + library/backtrace/src/backtrace/dbghelp.rs | 10 - library/backtrace/src/backtrace/libunwind.rs | 24 +- library/backtrace/src/backtrace/mod.rs | 1 + library/backtrace/src/capture.rs | 8 +- library/backtrace/src/lib.rs | 6 +- library/backtrace/src/print.rs | 4 +- library/backtrace/src/symbolize/dbghelp.rs | 12 +- library/backtrace/src/symbolize/gimli.rs | 116 +- library/backtrace/src/symbolize/gimli/coff.rs | 12 +- library/backtrace/src/symbolize/gimli/elf.rs | 10 +- .../backtrace/src/symbolize/gimli/macho.rs | 173 +- .../backtrace/src/symbolize/libbacktrace.rs | 12 +- library/backtrace/src/symbolize/miri.rs | 2 + library/backtrace/src/symbolize/mod.rs | 33 +- library/backtrace/src/symbolize/noop.rs | 2 + library/backtrace/tests/concurrent-panics.rs | 7 +- library/core/src/alloc/layout.rs | 66 +- library/core/src/alloc/mod.rs | 77 +- library/core/src/array/iter.rs | 6 +- library/core/src/array/mod.rs | 72 +- library/core/src/bool.rs | 4 +- library/core/src/cell.rs | 15 +- library/core/src/char/methods.rs | 43 +- library/core/src/cmp.rs | 120 +- library/core/src/fmt/mod.rs | 32 +- library/core/src/future/pending.rs | 2 +- library/core/src/future/poll_fn.rs | 8 +- library/core/src/future/ready.rs | 2 +- library/core/src/intrinsics.rs | 76 +- library/core/src/iter/adapters/chain.rs | 3 +- library/core/src/iter/adapters/cloned.rs | 139 + library/core/src/iter/adapters/copied.rs | 155 + library/core/src/iter/adapters/cycle.rs | 87 + library/core/src/iter/adapters/enumerate.rs | 238 + library/core/src/iter/adapters/filter.rs | 152 + library/core/src/iter/adapters/filter_map.rs | 150 + library/core/src/iter/adapters/flatten.rs | 10 +- library/core/src/iter/adapters/fuse.rs | 7 +- library/core/src/iter/adapters/inspect.rs | 167 + library/core/src/iter/adapters/map.rs | 213 + library/core/src/iter/adapters/map_while.rs | 101 + library/core/src/iter/adapters/mod.rs | 2861 +- library/core/src/iter/adapters/peekable.rs | 342 + library/core/src/iter/adapters/rev.rs | 137 + library/core/src/iter/adapters/scan.rs | 111 + library/core/src/iter/adapters/skip.rs | 199 + library/core/src/iter/adapters/skip_while.rs | 126 + library/core/src/iter/adapters/step_by.rs | 235 + library/core/src/iter/adapters/take.rs | 209 + library/core/src/iter/adapters/take_while.rs | 139 + library/core/src/iter/adapters/zip.rs | 9 +- library/core/src/iter/mod.rs | 68 +- library/core/src/iter/sources.rs | 630 +- library/core/src/iter/sources/empty.rs | 92 + library/core/src/iter/sources/from_fn.rs | 78 + library/core/src/iter/sources/once.rs | 99 + library/core/src/iter/sources/once_with.rs | 109 + library/core/src/iter/sources/repeat.rs | 93 + library/core/src/iter/sources/repeat_with.rs | 98 + library/core/src/iter/sources/successors.rs | 66 + library/core/src/iter/traits/iterator.rs | 4 +- library/core/src/lib.rs | 21 +- library/core/src/macros/mod.rs | 34 +- library/core/src/marker.rs | 15 +- library/core/src/mem/maybe_uninit.rs | 189 +- library/core/src/num/f32.rs | 61 + library/core/src/num/f64.rs | 61 + library/core/src/num/int_macros.rs | 20 +- library/core/src/num/nonzero.rs | 74 + library/core/src/num/uint_macros.rs | 26 +- library/core/src/num/wrapping.rs | 2 + library/core/src/ops/control_flow.rs | 14 + library/core/src/ops/index.rs | 2 +- library/core/src/option.rs | 6 +- library/core/src/panic.rs | 2 +- library/core/src/panicking.rs | 2 +- library/core/src/ptr/const_ptr.rs | 10 +- library/core/src/ptr/mod.rs | 8 +- library/core/src/ptr/mut_ptr.rs | 28 +- library/core/src/ptr/non_null.rs | 4 +- library/core/src/result.rs | 4 +- library/core/src/slice/memchr.rs | 8 +- library/core/src/slice/mod.rs | 60 +- library/core/src/str/converts.rs | 3 +- library/core/src/str/mod.rs | 18 +- library/core/src/str/validations.rs | 2 +- library/core/src/sync/atomic.rs | 161 +- library/core/src/task/ready.rs | 19 +- library/core/src/task/wake.rs | 3 +- library/core/src/unicode/mod.rs | 23 +- library/core/tests/ascii.rs | 53 + library/core/tests/atomic.rs | 85 +- library/core/tests/bool.rs | 84 + library/core/tests/cmp.rs | 71 + library/core/tests/iter.rs | 23 + library/core/tests/lib.rs | 10 + library/core/tests/macros.rs | 14 + library/core/tests/mem.rs | 138 + library/core/tests/nonzero.rs | 104 +- library/core/tests/num/i128.rs | 1 + library/core/tests/num/int_macros.rs | 6 +- library/core/tests/num/mod.rs | 2 + library/core/tests/num/nan.rs | 1 - library/core/tests/num/u128.rs | 1 + library/core/tests/num/uint_macros.rs | 6 +- library/core/tests/num/wrapping.rs | 233 + library/core/tests/ops.rs | 81 +- library/core/tests/option.rs | 10 + library/core/tests/ptr.rs | 15 +- library/core/tests/result.rs | 38 + library/core/tests/unicode.rs | 5 + library/panic_abort/src/lib.rs | 2 +- library/panic_unwind/src/lib.rs | 1 - library/proc_macro/src/bridge/client.rs | 15 +- library/proc_macro/src/bridge/scoped_cell.rs | 3 +- library/proc_macro/src/lib.rs | 12 +- library/proc_macro/tests/test.rs | 10 +- library/rtstartup/rsbegin.rs | 7 +- library/rtstartup/rsend.rs | 5 +- library/rustc-std-workspace-core/README.md | 12 +- library/std/Cargo.toml | 10 +- library/std/build.rs | 70 +- library/std/src/alloc.rs | 22 +- library/std/src/backtrace.rs | 11 +- library/std/src/backtrace/tests.rs | 4 + library/std/src/collections/hash/map.rs | 18 +- library/std/src/error.rs | 4 +- library/std/src/f32.rs | 42 +- library/std/src/f64.rs | 42 +- library/std/src/ffi/c_str.rs | 2 +- library/std/src/ffi/os_str.rs | 4 +- library/std/src/fs.rs | 28 +- library/std/src/fs/tests.rs | 3 + library/std/src/io/buffered/bufwriter.rs | 59 +- library/std/src/io/buffered/linewritershim.rs | 8 +- library/std/src/io/buffered/mod.rs | 45 + library/std/src/io/copy.rs | 88 + library/std/src/io/impls.rs | 18 +- library/std/src/io/mod.rs | 39 +- library/std/src/io/stdio.rs | 185 +- library/std/src/io/tests.rs | 2 +- library/std/src/io/util.rs | 73 +- library/std/src/keyword_docs.rs | 34 +- library/std/src/lib.rs | 16 +- library/std/src/macros.rs | 1 + library/std/src/net/ip.rs | 56 +- library/std/src/net/ip/tests.rs | 6 + library/std/src/net/tcp.rs | 2 +- library/std/src/net/udp.rs | 2 +- library/std/src/num/tests.rs | 6 +- library/std/src/panicking.rs | 12 +- library/std/src/path/tests.rs | 8 +- library/std/src/prelude/mod.rs | 25 +- library/std/src/primitive_docs.rs | 13 +- library/std/src/process.rs | 3 +- library/std/src/sync/mpsc/blocking.rs | 6 +- library/std/src/sync/mpsc/oneshot.rs | 14 +- library/std/src/sync/mpsc/shared.rs | 11 +- library/std/src/sync/mpsc/stream.rs | 9 +- library/std/src/sync/once.rs | 18 +- library/std/src/sys/cloudabi/abi/bitflags.rs | 47 - library/std/src/sys/cloudabi/abi/cloudabi.rs | 2954 -- library/std/src/sys/cloudabi/abi/mod.rs | 3 - library/std/src/sys/cloudabi/args.rs | 7 - library/std/src/sys/cloudabi/condvar.rs | 149 - library/std/src/sys/cloudabi/io.rs | 47 - library/std/src/sys/cloudabi/mod.rs | 68 - library/std/src/sys/cloudabi/mutex.rs | 153 - library/std/src/sys/cloudabi/os.rs | 26 - library/std/src/sys/cloudabi/rwlock.rs | 215 - library/std/src/sys/cloudabi/shims/args.rs | 35 - library/std/src/sys/cloudabi/shims/env.rs | 9 - library/std/src/sys/cloudabi/shims/fs.rs | 308 - library/std/src/sys/cloudabi/shims/mod.rs | 19 - library/std/src/sys/cloudabi/shims/net.rs | 326 - library/std/src/sys/cloudabi/shims/os.rs | 86 - library/std/src/sys/cloudabi/shims/pipe.rs | 38 - library/std/src/sys/cloudabi/shims/process.rs | 149 - .../std/src/sys/cloudabi/stack_overflow.rs | 5 - library/std/src/sys/cloudabi/stdio.rs | 66 - library/std/src/sys/cloudabi/thread.rs | 118 - library/std/src/sys/cloudabi/time.rs | 82 - library/std/src/sys/hermit/fs.rs | 4 +- library/std/src/sys/mod.rs | 13 +- library/std/src/sys/sgx/abi/mem.rs | 12 + library/std/src/sys/sgx/abi/mod.rs | 8 +- library/std/src/sys/sgx/alloc.rs | 46 +- library/std/src/sys/sgx/ext/io.rs | 39 +- library/std/src/sys/sgx/net.rs | 6 +- .../std/src/sys/sgx/waitqueue/spin_mutex.rs | 2 +- library/std/src/sys/unix/ext/fs.rs | 6 +- library/std/src/sys/unix/ext/net.rs | 1768 - library/std/src/sys/unix/ext/net/addr.rs | 226 + library/std/src/sys/unix/ext/net/ancillary.rs | 664 + library/std/src/sys/unix/ext/net/datagram.rs | 897 + library/std/src/sys/unix/ext/net/listener.rs | 319 + library/std/src/sys/unix/ext/net/mod.rs | 54 + library/std/src/sys/unix/ext/net/raw_fd.rs | 40 + library/std/src/sys/unix/ext/net/stream.rs | 673 + library/std/src/sys/unix/ext/net/tests.rs | 192 +- library/std/src/sys/unix/ext/ucred.rs | 57 +- library/std/src/sys/unix/ext/ucred/tests.rs | 15 +- library/std/src/sys/unix/fd.rs | 9 +- library/std/src/sys/unix/fd/tests.rs | 2 +- library/std/src/sys/unix/fs.rs | 104 +- library/std/src/sys/unix/kernel_copy.rs | 676 + library/std/src/sys/unix/kernel_copy/tests.rs | 252 + library/std/src/sys/unix/mod.rs | 54 + library/std/src/sys/unix/net.rs | 39 + library/std/src/sys/unix/rand.rs | 15 +- library/std/src/sys/unix/weak.rs | 66 +- library/std/src/sys/unsupported/fs.rs | 2 +- library/std/src/sys/wasi/fs.rs | 20 +- library/std/src/sys/wasm/alloc.rs | 2 +- library/std/src/sys/wasm/mutex_atomics.rs | 2 +- library/std/src/sys/windows/c.rs | 47 + library/std/src/sys/windows/compat.rs | 2 + library/std/src/sys/windows/ext/fs.rs | 12 +- library/std/src/sys/windows/fs.rs | 39 +- library/std/src/sys/windows/mod.rs | 15 + library/std/src/sys/windows/mutex.rs | 6 +- library/std/src/sys/windows/path.rs | 174 +- library/std/src/sys/windows/path/tests.rs | 39 +- .../std/src/sys/windows/thread_local_key.rs | 24 +- library/std/src/sys/windows/thread_parker.rs | 250 + library/std/src/sys_common/condvar/check.rs | 6 +- library/std/src/sys_common/mod.rs | 3 +- library/std/src/sys_common/net.rs | 5 +- .../std/src/sys_common/thread_local_key.rs | 8 +- .../std/src/sys_common/thread_parker/futex.rs | 2 +- .../std/src/sys_common/thread_parker/mod.rs | 2 + .../std/src/thread/available_concurrency.rs | 1 - library/std/src/thread/mod.rs | 6 +- library/std/src/time.rs | 4 - library/std/tests/env.rs | 62 + library/std/tests/run-time-detect.rs | 70 +- .../sleep.rs => library/std/tests/thread.rs | 16 +- library/stdarch/.github/workflows/main.yml | 17 +- library/stdarch/CONTRIBUTING.md | 29 +- library/stdarch/ci/run.sh | 2 + .../crates/assert-instr-macro/build.rs | 2 +- .../crates/assert-instr-macro/src/lib.rs | 6 +- library/stdarch/crates/core_arch/avx512bw.md | 558 + library/stdarch/crates/core_arch/avx512f.md | 1124 +- .../crates/core_arch/src/aarch64/mod.rs | 3 - .../core_arch/src/aarch64/neon/generated.rs | 88 + .../crates/core_arch/src/aarch64/neon/mod.rs | 1100 +- .../core_arch/src/{aarch64 => arm}/crypto.rs | 58 +- .../stdarch/crates/core_arch/src/arm/mod.rs | 5 + .../core_arch/src/arm/neon/generated.rs | 700 + .../core_arch/src/arm/neon/load_tests.rs | 208 + .../crates/core_arch/src/arm/neon/mod.rs | 6716 ++- .../src/arm/neon/shift_and_insert_tests.rs | 89 + .../crates/core_arch/src/core_arch_docs.md | 2 +- library/stdarch/crates/core_arch/src/lib.rs | 2 +- library/stdarch/crates/core_arch/src/mod.rs | 1 + library/stdarch/crates/core_arch/src/simd.rs | 393 + .../stdarch/crates/core_arch/src/x86/avx.rs | 22 +- .../stdarch/crates/core_arch/src/x86/avx2.rs | 144 +- .../crates/core_arch/src/x86/avx512bitalg.rs | 760 + .../crates/core_arch/src/x86/avx512bw.rs | 13881 +++++ .../crates/core_arch/src/x86/avx512cd.rs | 1170 + .../crates/core_arch/src/x86/avx512f.rs | 42922 +++++++++++----- .../crates/core_arch/src/x86/avx512gfni.rs | 1567 + .../crates/core_arch/src/x86/avx512ifma.rs | 2 +- .../crates/core_arch/src/x86/avx512vaes.rs | 332 + .../core_arch/src/x86/avx512vpclmulqdq.rs | 266 + .../core_arch/src/x86/avx512vpopcntdq.rs | 541 + .../stdarch/crates/core_arch/src/x86/fma.rs | 2 +- .../stdarch/crates/core_arch/src/x86/fxsr.rs | 4 +- .../crates/core_arch/src/x86/macros.rs | 844 + .../stdarch/crates/core_arch/src/x86/mod.rs | 77 +- .../stdarch/crates/core_arch/src/x86/rtm.rs | 4 +- .../stdarch/crates/core_arch/src/x86/sse.rs | 24 +- .../stdarch/crates/core_arch/src/x86/sse2.rs | 20 +- .../stdarch/crates/core_arch/src/x86/sse41.rs | 4 +- .../stdarch/crates/core_arch/src/x86/test.rs | 60 +- .../stdarch/crates/core_arch/src/x86/xsave.rs | 21 +- .../crates/core_arch/src/x86_64/avx512f.rs | 1870 +- .../crates/core_arch/src/x86_64/fxsr.rs | 4 +- .../crates/core_arch/src/x86_64/xsave.rs | 12 +- .../crates/core_arch/tests/cpu-detection.rs | 2 +- .../crates/std_detect/tests/cpu-detection.rs | 2 +- .../std_detect/tests/macro_trailing_commas.rs | 2 +- library/stdarch/crates/stdarch-gen/neon.spec | 103 +- .../stdarch/crates/stdarch-gen/src/main.rs | 7 +- .../crates/stdarch-test/src/disassembly.rs | 117 +- .../stdarch/crates/stdarch-test/src/lib.rs | 8 +- .../stdarch/crates/stdarch-verify/src/lib.rs | 10 +- .../crates/stdarch-verify/tests/arm.rs | 81 +- .../crates/stdarch-verify/tests/mips.rs | 37 +- .../crates/stdarch-verify/tests/x86-intel.rs | 101 +- .../crates/stdarch-verify/x86-intel.xml | 304 +- library/stdarch/examples/hex.rs | 4 +- library/test/Cargo.toml | 2 + library/test/src/bench.rs | 20 +- library/test/src/console.rs | 12 +- library/test/src/formatters/json.rs | 15 +- library/test/src/formatters/pretty.rs | 11 +- library/test/src/formatters/terse.rs | 11 +- library/test/src/helpers/mod.rs | 1 - library/test/src/helpers/sink.rs | 31 - library/test/src/lib.rs | 29 +- library/test/src/tests.rs | 1 + library/test/src/time.rs | 39 +- library/unwind/build.rs | 2 - library/unwind/src/lib.rs | 1 - src/bootstrap/bootstrap.py | 32 +- src/bootstrap/builder.rs | 32 +- src/bootstrap/check.rs | 5 + src/bootstrap/compile.rs | 60 +- src/bootstrap/config.rs | 37 +- src/bootstrap/configure.py | 1 + src/bootstrap/dist.rs | 1055 +- src/bootstrap/doc.rs | 9 + src/bootstrap/download-ci-llvm-stamp | 2 +- src/bootstrap/flags.rs | 37 + src/bootstrap/install.rs | 203 +- src/bootstrap/lib.rs | 14 +- src/bootstrap/native.rs | 4 +- src/bootstrap/sanity.rs | 44 +- src/bootstrap/setup.rs | 5 +- src/bootstrap/tarball.rs | 319 + src/bootstrap/test.rs | 93 +- src/bootstrap/tool.rs | 37 +- .../build-cloudabi-toolchain.sh | 40 - .../dist-various-2/build-solaris-toolchain.sh | 18 +- .../dist-x86_64-freebsd/Dockerfile | 7 +- .../host-x86_64/dist-x86_64-linux/Dockerfile | 9 +- .../Dockerfile | 22 +- .../host-x86_64/x86_64-gnu-nopt/Dockerfile | 5 +- src/ci/github-actions/ci.yml | 4 +- src/ci/pgo.sh | 49 + src/ci/scripts/install-msys2.sh | 4 +- src/doc/book/.github/workflows/main.yml | 6 +- src/doc/book/ci/dictionary.txt | 2 + src/doc/book/dot/trpl15-04.dot | 16 + .../listing-02-04/output.txt | 6 +- .../no-listing-02-without-expect/output.txt | 2 + .../src/main.rs | 2 +- .../output.txt | 2 +- .../output.txt | 2 +- .../output.txt | 4 +- .../output.txt | 27 +- .../output.txt | 2 +- .../output.txt | 2 +- .../output.txt | 4 +- .../output.txt | 2 +- .../listing-04-06/output.txt | 4 +- .../output.txt | 4 +- .../output.txt | 2 +- .../output.txt | 2 +- .../output.txt | 8 +- .../no-listing-19-slice-error/output.txt | 2 +- .../listing-05-11/output.txt | 3 +- .../output.txt | 19 +- .../output-only-01-debug/output.txt | 9 +- .../output.txt | 8 +- .../output.txt | 15 +- .../listing-07-01/src/lib.rs | 4 - .../listing-07-03/output.txt | 18 +- .../listing-07-05/output.txt | 18 +- .../listing-07-07/src/lib.rs | 4 - .../listing-07-08/src/lib.rs | 4 - .../listing-07-11/src/lib.rs | 4 - .../listing-07-12/src/lib.rs | 4 - .../listing-07-13/src/lib.rs | 4 - .../listing-07-17/src/lib.rs | 4 - .../listing-08-07/output.txt | 2 +- .../listing-08-19/output.txt | 8 +- .../output.txt | 4 +- .../listing-09-01/output.txt | 4 +- .../listing-09-04/output.txt | 2 +- .../no-listing-01-panic/output.txt | 2 +- .../output.txt | 4 +- .../output.txt | 8 +- .../listing-10-05/output.txt | 13 +- .../listing-10-07/output.txt | 2 +- .../listing-10-17/output.txt | 2 +- .../listing-10-21/output.txt | 8 +- .../listing-10-24/output.txt | 2 +- .../output.txt | 2 +- .../output.txt | 2 +- .../listing-11-01/src/lib.rs | 4 - .../listing-11-03/output.txt | 2 +- .../listing-11-03/src/lib.rs | 2 - .../listing-11-05/src/lib.rs | 2 - .../listing-11-06/src/lib.rs | 2 - .../listing-11-07/src/lib.rs | 4 - .../listing-11-08/src/lib.rs | 4 - .../listing-11-09/src/lib.rs | 2 - .../listing-11-10/output.txt | 4 +- .../listing-11-10/src/lib.rs | 4 - .../listing-11-12/src/lib.rs | 4 - .../listing-11-13/output.txt | 2 +- .../src/lib.rs | 4 - .../src/lib.rs | 2 - .../output.txt | 2 +- .../src/lib.rs | 2 - .../no-listing-04-bug-in-add-two/output.txt | 2 +- .../no-listing-04-bug-in-add-two/src/lib.rs | 2 - .../no-listing-05-greeter/src/lib.rs | 4 - .../no-listing-06-greeter-with-bug/output.txt | 2 +- .../no-listing-06-greeter-with-bug/src/lib.rs | 2 - .../output.txt | 2 +- .../no-listing-08-guess-with-bug/src/lib.rs | 2 - .../output.txt | 2 +- .../no-listing-10-result-in-tests/src/lib.rs | 5 - .../no-listing-11-ignore-a-test/src/lib.rs | 4 - .../output.txt | 4 +- .../output-only-01-show-output/output.txt | 2 +- .../output-only-04-running-ignored/src/lib.rs | 2 - .../listing-12-07/output.txt | 2 +- .../listing-12-08/output.txt | 2 +- .../listing-12-09/src/main.rs | 2 +- .../listing-12-10/src/main.rs | 2 +- .../listing-12-11/src/main.rs | 2 +- .../listing-12-12/output.txt | 2 + .../listing-12-12/src/main.rs | 2 +- .../listing-12-13/src/lib.rs | 2 +- .../listing-12-14/src/lib.rs | 2 +- .../listing-12-15/src/lib.rs | 4 +- .../listing-12-16/output.txt | 2 +- .../listing-12-16/src/lib.rs | 4 +- .../listing-12-17/src/lib.rs | 2 +- .../listing-12-18/src/lib.rs | 2 +- .../listing-12-19/output.txt | 2 +- .../listing-12-19/src/lib.rs | 2 +- .../listing-12-20/src/lib.rs | 4 +- .../listing-12-21/output.txt | 2 +- .../listing-12-21/src/lib.rs | 4 +- .../listing-12-22/src/lib.rs | 4 +- .../listing-12-23/src/lib.rs | 4 +- .../listing-12-24/src/lib.rs | 2 +- .../src/main.rs | 2 +- .../src/lib.rs | 2 +- .../output.txt | 8 +- .../src/lib.rs | 4 +- .../src/lib.rs | 2 +- .../output-only-04-no-matches/src/lib.rs | 2 +- .../listing-12-23-reproduced/src/lib.rs | 4 +- .../listing-12-24-reproduced/src/lib.rs | 2 +- .../listing-13-08/output.txt | 4 +- .../listing-13-15/src/lib.rs | 2 - .../listing-13-16/src/lib.rs | 2 - .../listing-13-17/output.txt | 4 +- .../listing-13-19/src/lib.rs | 2 - .../listing-13-20/src/lib.rs | 2 - .../listing-13-21/src/lib.rs | 2 - .../listing-13-22/src/lib.rs | 2 - .../listing-13-23/src/lib.rs | 2 - .../listing-13-25/src/lib.rs | 2 +- .../listing-13-27/src/lib.rs | 2 - .../output.txt | 2 +- .../output.txt | 2 +- .../no-listing-03-move-closures/output.txt | 4 +- .../listing-14-03/src/lib.rs | 4 - .../output-only-01-adder-crate/add/Cargo.lock | 5 + .../listing-15-03/output.txt | 13 +- .../listing-15-09/output.txt | 2 +- .../listing-15-15/output.txt | 7 +- .../listing-15-17/output.txt | 2 +- .../listing-15-21/output.txt | 4 +- .../listing-15-22/src/lib.rs | 2 - .../listing-15-23/output.txt | 4 +- .../output.txt | 2 +- .../output.txt | 6 +- .../listing-16-03/output.txt | 2 +- .../listing-16-09/output.txt | 4 +- .../listing-16-11/src/main.rs | 2 +- .../listing-16-13/output.txt | 4 +- .../listing-16-14/output.txt | 19 +- .../output-only-01-move-drop/output.txt | 4 +- .../ch17-oop/listing-17-07/src/lib.rs | 2 - .../ch17-oop/listing-17-10/output.txt | 8 +- .../ch17-oop/listing-17-13/src/lib.rs | 2 - .../ch17-oop/listing-17-14/src/lib.rs | 2 - .../ch17-oop/listing-17-15/src/lib.rs | 2 - .../output.txt | 10 +- .../listing-18-05/output.txt | 6 +- .../listing-18-08/output.txt | 23 +- .../listing-18-10/output.txt | 2 + .../listing-18-25/output.txt | 2 +- .../listing-13-21-reproduced/src/lib.rs | 2 - .../listing-19-05/output.txt | 2 +- .../listing-19-20/output.txt | 4 +- .../output.txt | 5 +- .../no-listing-06-result-alias/src/lib.rs | 2 - .../no-listing-07-never-type/src/lib.rs | 2 - .../no-listing-18-returns-closure/output.txt | 26 +- .../output-only-01-missing-unsafe/output.txt | 2 +- .../ch20-web-server/listing-20-12/output.txt | 6 +- .../ch20-web-server/listing-20-13/src/lib.rs | 2 - .../ch20-web-server/listing-20-15/src/lib.rs | 2 - .../ch20-web-server/listing-20-16/src/lib.rs | 2 - .../ch20-web-server/listing-20-17/output.txt | 2 +- .../ch20-web-server/listing-20-18/src/lib.rs | 2 - .../ch20-web-server/listing-20-19/src/lib.rs | 2 - .../ch20-web-server/listing-20-22/output.txt | 4 +- .../listing-20-25/src/bin/main.rs | 2 - .../ch20-web-server/listing-20-25/src/lib.rs | 4 - .../output.txt | 6 +- .../output.txt | 6 +- .../src/lib.rs | 4 - .../no-listing-03-define-execute/src/lib.rs | 2 - .../output.txt | 12 +- .../src/lib.rs | 2 - .../no-listing-08-final-code/404.html | 11 + .../no-listing-08-final-code/Cargo.lock | 6 + .../no-listing-08-final-code/Cargo.toml | 7 + .../no-listing-08-final-code/hello.html | 11 + .../no-listing-08-final-code/src/bin/main.rs | 46 + .../no-listing-08-final-code/src/lib.rs | 101 + src/doc/book/rust-toolchain | 2 +- src/doc/book/src/ch00-00-introduction.md | 2 +- src/doc/book/src/ch01-02-hello-world.md | 11 +- .../src/ch02-00-guessing-game-tutorial.md | 10 +- src/doc/book/src/ch03-02-data-types.md | 13 +- src/doc/book/src/ch04-01-what-is-ownership.md | 32 +- src/doc/book/src/ch05-01-defining-structs.md | 19 +- ...ng-modules-to-control-scope-and-privacy.md | 4 +- ...referring-to-an-item-in-the-module-tree.md | 8 +- ...g-paths-into-scope-with-the-use-keyword.md | 16 +- src/doc/book/src/ch08-02-strings.md | 2 +- src/doc/book/src/ch08-03-hash-maps.md | 2 +- ...ch09-01-unrecoverable-errors-with-panic.md | 73 +- src/doc/book/src/ch11-01-writing-tests.md | 42 +- src/doc/book/src/ch11-02-running-tests.md | 8 +- src/doc/book/src/ch11-03-test-organization.md | 4 +- ...improving-error-handling-and-modularity.md | 8 +- ...2-04-testing-the-librarys-functionality.md | 2 +- ...2-05-working-with-environment-variables.md | 6 +- src/doc/book/src/ch13-01-closures.md | 5 + src/doc/book/src/ch13-02-iterators.md | 16 +- .../src/ch13-03-improving-our-io-project.md | 14 +- .../src/ch14-02-publishing-to-crates-io.md | 4 +- src/doc/book/src/ch14-03-cargo-workspaces.md | 17 +- .../book/src/ch14-04-installing-binaries.md | 2 +- src/doc/book/src/ch15-01-box.md | 5 +- .../book/src/ch15-05-interior-mutability.md | 2 +- src/doc/book/src/ch15-06-reference-cycles.md | 20 +- src/doc/book/src/ch17-02-trait-objects.md | 2 +- .../book/src/ch17-03-oo-design-patterns.md | 6 +- .../ch18-01-all-the-places-for-patterns.md | 8 +- src/doc/book/src/ch19-01-unsafe-rust.md | 21 +- src/doc/book/src/ch19-04-advanced-types.md | 6 +- src/doc/book/src/ch20-01-single-threaded.md | 2 +- src/doc/book/src/ch20-02-multithreaded.md | 36 +- .../ch20-03-graceful-shutdown-and-cleanup.md | 8 +- src/doc/book/src/img/trpl15-04.svg | 129 +- src/doc/book/src/title-page.md | 2 +- src/doc/book/tools/update-rustc.sh | 17 +- .../embedded-book/src/concurrency/index.md | 9 +- src/doc/nomicon/src/atomics.md | 2 +- src/doc/nomicon/src/destructors.md | 16 +- src/doc/nomicon/src/repr-rust.md | 8 +- src/doc/nomicon/src/vec-final.md | 6 +- .../reference/src/expressions/call-expr.md | 2 +- src/doc/reference/src/introduction.md | 18 +- src/doc/reference/src/items/functions.md | 8 +- src/doc/reference/src/items/unions.md | 23 +- src/doc/reference/src/patterns.md | 8 +- src/doc/reference/src/type-layout.md | 12 +- src/doc/reference/src/types/union.md | 8 +- src/doc/rust-by-example/CODE_OF_CONDUCT.md | 3 +- src/doc/rust-by-example/CONTRIBUTING.md | 1 - src/doc/rust-by-example/README.md | 12 +- src/doc/rust-by-example/book.toml | 2 +- src/doc/rust-by-example/src/cargo/deps.md | 3 +- .../src/custom_types/structs.md | 6 +- .../rust-by-example/src/error/iter_result.md | 3 +- .../src/error/option_unwrap/map.md | 2 +- .../rust-by-example/src/flow_control/for.md | 8 +- .../rust-by-example/src/flow_control/match.md | 5 +- .../destructuring/destructure_pointers.md | 4 + .../destructuring/destructure_structures.md | 2 +- .../src/hello/print/print_debug.md | 2 +- .../src/scope/lifetime/static_lifetime.md | 6 +- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/exploit-mitigations.md | 693 + src/doc/rustc/src/images/image1.png | Bin 0 -> 15293 bytes src/doc/rustc/src/images/image2.png | Bin 0 -> 28772 bytes src/doc/rustc/src/images/image3.png | Bin 0 -> 72412 bytes src/doc/rustc/src/platform-support.md | 16 +- .../source-based-code-coverage.md | 190 +- ...optin-builtin-traits.md => auto-traits.md} | 6 +- .../src/language-features/const-fn.md | 23 +- .../unstable-book/src/library-features/asm.md | 5 + ...nternals.md => internal-output-capture.md} | 2 +- .../src/library-features/set-stdio.md | 5 - src/etc/gdb_providers.py | 72 +- src/etc/lldb_providers.py | 2 +- src/librustdoc/clean/auto_trait.rs | 41 +- src/librustdoc/clean/blanket_impl.rs | 44 +- src/librustdoc/clean/cfg.rs | 12 +- src/librustdoc/clean/inline.rs | 64 +- src/librustdoc/clean/mod.rs | 1565 +- src/librustdoc/clean/simplify.rs | 9 +- src/librustdoc/clean/types.rs | 798 +- src/librustdoc/clean/utils.rs | 170 +- src/librustdoc/config.rs | 173 +- src/librustdoc/core.rs | 214 +- src/librustdoc/docfs.rs | 14 +- src/librustdoc/doctest.rs | 142 +- src/librustdoc/doctest/tests.rs | 103 +- src/librustdoc/doctree.rs | 258 +- src/librustdoc/error.rs | 6 +- src/librustdoc/externalfiles.rs | 18 +- src/librustdoc/fold.rs | 27 +- src/librustdoc/formats/cache.rs | 150 +- src/librustdoc/formats/item_type.rs | 10 +- src/librustdoc/formats/mod.rs | 22 +- src/librustdoc/formats/renderer.rs | 13 +- src/librustdoc/html/escape.rs | 2 +- src/librustdoc/html/format.rs | 117 +- src/librustdoc/html/highlight.rs | 72 +- src/librustdoc/html/highlight/tests.rs | 5 +- src/librustdoc/html/layout.rs | 42 +- src/librustdoc/html/markdown.rs | 412 +- src/librustdoc/html/markdown/tests.rs | 164 +- src/librustdoc/html/mod.rs | 2 +- src/librustdoc/html/render/cache.rs | 34 +- src/librustdoc/html/render/mod.rs | 849 +- src/librustdoc/html/sources.rs | 40 +- src/librustdoc/html/static/main.js | 141 +- src/librustdoc/html/static/noscript.css | 10 + src/librustdoc/html/static/rustdoc.css | 69 +- src/librustdoc/html/static/settings.js | 72 +- src/librustdoc/html/static/themes/ayu.css | 18 +- src/librustdoc/html/static/themes/dark.css | 15 +- src/librustdoc/html/static/themes/light.css | 15 +- src/librustdoc/html/static_files.rs | 72 +- src/librustdoc/html/toc.rs | 12 +- src/librustdoc/json/conversions.rs | 604 + src/librustdoc/json/mod.rs | 239 +- src/librustdoc/json/types.rs | 490 + src/librustdoc/lib.rs | 124 +- src/librustdoc/markdown.rs | 9 +- .../passes/calculate_doc_coverage.rs | 25 +- .../passes/check_code_block_syntax.rs | 6 +- src/librustdoc/passes/collapse_docs.rs | 8 +- .../passes/collect_intra_doc_links.rs | 558 +- src/librustdoc/passes/collect_trait_impls.rs | 78 +- src/librustdoc/passes/doc_test_lints.rs | 41 +- src/librustdoc/passes/html_tags.rs | 18 +- src/librustdoc/passes/mod.rs | 60 +- src/librustdoc/passes/non_autolinks.rs | 11 +- src/librustdoc/passes/propagate_doc_cfg.rs | 6 +- src/librustdoc/passes/strip_hidden.rs | 10 +- src/librustdoc/passes/strip_priv_imports.rs | 4 +- src/librustdoc/passes/strip_private.rs | 4 +- src/librustdoc/passes/stripper.rs | 46 +- src/librustdoc/passes/unindent_comments.rs | 8 +- src/librustdoc/theme.rs | 12 +- src/librustdoc/visit_ast.rs | 368 +- src/librustdoc/visit_lib.rs | 8 +- src/stage0.txt | 6 +- src/test/assembly/asm/wasm-types.rs | 150 + src/test/codegen/abi-efiapi.rs | 1 - ...e-in-reg.rs => arg-return-value-in-reg.rs} | 4 +- src/test/codegen/dllimports/main.rs | 1 - src/test/codegen/enum-discriminant-value.rs | 8 +- src/test/codegen/fewer-names.rs | 20 + src/test/codegen/force-unwind-tables.rs | 1 - src/test/codegen/inline-hint.rs | 31 + src/test/codegen/internalize-closures.rs | 2 +- src/test/codegen/issue-37945.rs | 20 +- src/test/codegen/issue-56927.rs | 1 - src/test/codegen/naked-functions.rs | 54 +- src/test/codegen/naked-noinline.rs | 30 + src/test/codegen/panic-abort-windows.rs | 1 - .../simd-intrinsic-generic-extract-insert.rs | 47 + .../simd-intrinsic-transmute-array.rs | 44 + src/test/codegen/to_vec.rs | 10 + src/test/codegen/transmute-scalar.rs | 85 + src/test/codegen/union-abi.rs | 11 +- src/test/codegen/vec-shrink-panic.rs | 4 +- src/test/compile-fail/consts/issue-55878.rs | 4 +- src/test/compile-fail/issue-52443.rs | 1 - src/test/debuginfo/pretty-std-collections.rs | 5 +- src/test/debuginfo/pretty-std.rs | 4 +- .../struct_point.rs | 2 +- src/test/incremental/auxiliary/issue-79661.rs | 6 + src/test/incremental/auxiliary/issue-79890.rs | 1 + .../change_add_field/struct_point.rs | 2 +- .../struct_point.rs | 2 +- .../struct_point.rs | 2 +- .../struct_point.rs | 2 +- src/test/incremental/hashes/extern_mods.rs | 131 +- .../incremental/issue-49595/issue-49595.rs | 2 +- .../issue-79661-missing-def-path-hash.rs | 14 + .../issue-79890-imported-crates-changed.rs | 7 + .../mir-opt/const-promotion-extern-static.rs | 3 + .../const_debuginfo.main.ConstDebugInfo.diff | 115 + src/test/mir-opt/const_debuginfo.rs | 24 + ...motion_extern_static.BAR.PromoteTemps.diff | 3 + ..._promotion_extern_static.BOP.mir_map.0.mir | 17 + ...motion_extern_static.FOO.PromoteTemps.diff | 3 + .../checked_add.main.ConstProp.diff | 3 - ...l_flow_simplification.hello.ConstProp.diff | 2 +- ...simplification.hello.PreCodegen.before.mir | 2 +- .../const_prop/indirect.main.ConstProp.diff | 3 - .../issue_67019.main.ConstProp.diff | 3 - ...ble_variable_aggregate.main.ConstProp.diff | 3 - ...es_into_variable.main.ConstProp.32bit.diff | 3 - ...es_into_variable.main.ConstProp.64bit.diff | 3 - .../return_place.add.ConstProp.diff | 3 - ...le_literal_propagation.main.ConstProp.diff | 3 - ...rage_graphviz.bar.InstrumentCoverage.0.dot | 2 +- ...age_graphviz.main.InstrumentCoverage.0.dot | 4 +- .../mir-opt/inline/inline-compatibility.rs | 22 +- src/test/mir-opt/inline/inline-generator.rs | 16 + ...patibility.inlined_no_sanitize.Inline.diff | 20 +- ...ibility.inlined_target_feature.Inline.diff | 20 +- ...ibility.not_inlined_c_variadic.Inline.diff | 25 + ...bility.not_inlined_no_sanitize.Inline.diff | 16 +- ...ity.not_inlined_target_feature.Inline.diff | 16 +- .../inline/inline_diverging.h.Inline.diff | 1 + .../inline/inline_generator.main.Inline.diff | 127 + .../inline/inline_shims.drop.Inline.diff | 4 + ...e_deref.do_not_miscompile.InstCombine.diff | 12 +- ...ument_coverage.bar.InstrumentCoverage.diff | 2 +- ...ment_coverage.main.InstrumentCoverage.diff | 10 +- ...e_38669.main.SimplifyCfg-initial.after.mir | 2 +- .../issue_41888.main.ElaborateDrops.after.mir | 4 +- .../issue_73223.main.PreCodegen.32bit.diff | 141 +- .../issue_73223.main.PreCodegen.64bit.diff | 141 +- ..._73223.main.SimplifyArmIdentity.32bit.diff | 294 +- ..._73223.main.SimplifyArmIdentity.64bit.diff | 294 +- ...76432.test.SimplifyComparisonIntegral.diff | 10 +- ....main.SimplifyCfg-promote-consts.after.mir | 2 +- ...trinsics.discriminant.LowerIntrinsics.diff | 128 + ...wer_intrinsics.f_u64.PreCodegen.before.mir | 27 + ...er_intrinsics.f_unit.PreCodegen.before.mir | 28 + ...wer_intrinsics.forget.LowerIntrinsics.diff | 39 + ..._intrinsics.non_const.LowerIntrinsics.diff | 35 + src/test/mir-opt/lower_intrinsics.rs | 73 + ...er_intrinsics.size_of.LowerIntrinsics.diff | 24 + ...ntrinsics.unreachable.LowerIntrinsics.diff | 26 + ...r_intrinsics.wrapping.LowerIntrinsics.diff | 87 + ...s.foo.MatchBranchSimplification.32bit.diff | 2 +- ...s.foo.MatchBranchSimplification.64bit.diff | 2 +- ...mplify_cfg.main.SimplifyCfg-early-opt.diff | 2 +- ...simplify_cfg.main.SimplifyCfg-initial.diff | 2 +- ...ain.SimplifyBranches-after-const-prop.diff | 2 +- ..._locals_fixedpoint.foo.SimplifyLocals.diff | 4 +- ...ves_unused_consts.main.SimplifyLocals.diff | 3 - ...age_live_dead_in_statics.XXX.mir_map.0.mir | 44 + ...reachable.main.UnreachablePropagation.diff | 2 +- ...hable_asm.main.UnreachablePropagation.diff | 2 +- ...ble_asm_2.main.UnreachablePropagation.diff | 2 +- ...diverging.main.UnreachablePropagation.diff | 4 +- src/test/pretty/auto-trait.rs | 2 +- .../pretty/qpath-associated-type-bound.rs | 16 + .../coverage-llvmir-deadcode/Makefile | 11 - .../Makefile | 34 +- .../filecheck.testprog.txt | 5 +- .../testprog.rs | 0 .../coverage-reports-base/Makefile | 143 - .../expected_export_coverage.closure.json | 59 - .../expected_export_coverage.conditions.json | 59 - .../expected_export_coverage.drop_trait.json | 59 - .../expected_export_coverage.generics.json | 59 - .../expected_export_coverage.if.json | 59 - .../expected_export_coverage.if_else.json | 59 - .../expected_export_coverage.inner_items.json | 59 - ...expected_export_coverage.lazy_boolean.json | 59 - ...cted_export_coverage.loop_break_value.json | 59 - ...pected_export_coverage.loops_branches.json | 59 - ...expected_export_coverage.nested_loops.json | 59 - .../expected_export_coverage.partial_eq.json | 59 - .../expected_export_coverage.simple_loop.json | 59 - ...expected_export_coverage.simple_match.json | 59 - ...pected_export_coverage.tight_inf_loop.json | 59 - ...cted_export_coverage.try_error_result.json | 59 - .../expected_export_coverage.while.json | 59 - ...ected_export_coverage.while_early_ret.json | 59 - .../expected_show_coverage.conditions.txt | 69 - .../expected_show_coverage.inner_items.txt | 60 - ...xpected_show_coverage.loop_break_value.txt | 14 - .../expected_show_coverage.loops_branches.txt | 38 - .../expected_show_coverage.partial_eq.txt | 101 - .../expected_show_coverage.simple_loop.txt | 37 - .../expected_show_coverage.simple_match.txt | 46 - ...xpected_show_coverage.try_error_result.txt | 38 - ...xpected_show_coverage_counters.closure.txt | 94 - ...cted_show_coverage_counters.conditions.txt | 238 - ...cted_show_coverage_counters.drop_trait.txt | 22 - ...pected_show_coverage_counters.generics.txt | 48 - .../expected_show_coverage_counters.if.txt | 21 - ...xpected_show_coverage_counters.if_else.txt | 30 - ...ted_show_coverage_counters.inner_items.txt | 60 - ...ed_show_coverage_counters.lazy_boolean.txt | 131 - ...how_coverage_counters.loop_break_value.txt | 6 - ..._show_coverage_counters.loops_branches.txt | 37 - ...ed_show_coverage_counters.nested_loops.txt | 73 - ...cted_show_coverage_counters.partial_eq.txt | 27 - ...ted_show_coverage_counters.simple_loop.txt | 37 - ...ed_show_coverage_counters.simple_match.txt | 57 - ..._show_coverage_counters.tight_inf_loop.txt | 10 - ...how_coverage_counters.try_error_result.txt | 72 - .../expected_show_coverage_counters.while.txt | 18 - ...show_coverage_counters.while_early_ret.txt | 38 - .../coverage-reports-base/prettify_json.py | 9 - .../coverage-reports-deadcode/Makefile | 15 - .../expected_export_coverage.closure.json | 59 - .../expected_export_coverage.conditions.json | 59 - .../expected_export_coverage.drop_trait.json | 59 - .../expected_export_coverage.generics.json | 59 - .../expected_export_coverage.if.json | 59 - .../expected_export_coverage.if_else.json | 59 - .../expected_export_coverage.inner_items.json | 59 - ...expected_export_coverage.lazy_boolean.json | 59 - ...cted_export_coverage.loop_break_value.json | 59 - ...pected_export_coverage.loops_branches.json | 59 - ...expected_export_coverage.nested_loops.json | 59 - .../expected_export_coverage.partial_eq.json | 59 - .../expected_export_coverage.simple_loop.json | 59 - ...expected_export_coverage.simple_match.json | 59 - ...pected_export_coverage.tight_inf_loop.json | 59 - ...cted_export_coverage.try_error_result.json | 59 - .../expected_export_coverage.while.json | 59 - ...ected_export_coverage.while_early_ret.json | 59 - .../expected_show_coverage.closure.txt | 94 - .../expected_show_coverage.conditions.txt | 69 - .../expected_show_coverage.drop_trait.txt | 34 - .../expected_show_coverage.generics.txt | 67 - .../expected_show_coverage.if.txt | 30 - .../expected_show_coverage.if_else.txt | 41 - .../expected_show_coverage.lazy_boolean.txt | 65 - .../expected_show_coverage.nested_loops.txt | 26 - .../expected_show_coverage.partial_eq.txt | 111 - .../expected_show_coverage.tight_inf_loop.txt | 6 - .../expected_show_coverage.while.txt | 6 - ...expected_show_coverage.while_early_ret.txt | 48 - ...xpected_show_coverage_counters.closure.txt | 94 - ...cted_show_coverage_counters.conditions.txt | 238 - ...cted_show_coverage_counters.drop_trait.txt | 22 - ...pected_show_coverage_counters.generics.txt | 48 - .../expected_show_coverage_counters.if.txt | 21 - ...xpected_show_coverage_counters.if_else.txt | 30 - ...ted_show_coverage_counters.inner_items.txt | 60 - ...ed_show_coverage_counters.lazy_boolean.txt | 131 - ...how_coverage_counters.loop_break_value.txt | 6 - ..._show_coverage_counters.loops_branches.txt | 37 - ...ed_show_coverage_counters.nested_loops.txt | 73 - ...cted_show_coverage_counters.partial_eq.txt | 53 - ...ted_show_coverage_counters.simple_loop.txt | 37 - ...ed_show_coverage_counters.simple_match.txt | 57 - ..._show_coverage_counters.tight_inf_loop.txt | 10 - ...how_coverage_counters.try_error_result.txt | 72 - .../expected_show_coverage_counters.while.txt | 18 - ...show_coverage_counters.while_early_ret.txt | 38 - .../coverage-reports/Makefile | 256 + .../expected_show_coverage.abort.txt | 70 + .../expected_show_coverage.assert.txt | 34 + .../expected_show_coverage.async.txt | 135 + .../expected_show_coverage.closure.txt | 76 +- .../expected_show_coverage.conditions.txt | 90 + .../expected_show_coverage.dead_code.txt | 39 + .../expected_show_coverage.doctest.txt | 79 + .../expected_show_coverage.drop_trait.txt | 4 +- .../expected_show_coverage.generics.txt | 32 +- .../expected_show_coverage.if.txt | 14 +- .../expected_show_coverage.if_else.txt | 10 +- .../expected_show_coverage.inner_items.txt | 8 +- .../expected_show_coverage.lazy_boolean.txt | 11 +- ...xpected_show_coverage.loop_break_value.txt | 2 +- .../expected_show_coverage.loops_branches.txt | 6 +- ...xpected_show_coverage.match_or_pattern.txt | 50 + .../expected_show_coverage.nested_loops.txt | 10 +- .../expected_show_coverage.overflow.txt | 64 + .../expected_show_coverage.panic_unwind.txt | 50 + .../expected_show_coverage.partial_eq.txt | 63 + .../expected_show_coverage.simple_loop.txt | 16 +- .../expected_show_coverage.simple_match.txt | 13 +- .../expected_show_coverage.tight_inf_loop.txt | 4 +- ...xpected_show_coverage.try_error_result.txt | 8 +- .../expected_show_coverage.uses_crate.txt | 142 + .../expected_show_coverage.while.txt | 2 +- ...expected_show_coverage.while_early_ret.txt | 9 +- .../expected_show_coverage.yield.txt | 38 + .../coverage-reports/normalize_paths.py | 12 + .../coverage-spanview-base/Makefile | 74 - ...osure#2}.-------.InstrumentCoverage.0.html | 95 - ...osure#3}.-------.InstrumentCoverage.0.html | 95 - ...ure.main.-------.InstrumentCoverage.0.html | 4515 -- ...ons.main.-------.InstrumentCoverage.0.html | 263 - ...ait.main.-------.InstrumentCoverage.0.html | 129 - ...ics.main.-------.InstrumentCoverage.0.html | 177 - .../if.main.-------.InstrumentCoverage.0.html | 178 - ...lse.main.-------.InstrumentCoverage.0.html | 173 - ...-in_func.-------.InstrumentCoverage.0.html | 116 - ...ean.main.-------.InstrumentCoverage.0.html | 229 - ...lue.main.-------.InstrumentCoverage.0.html | 128 - ...ops.main.-------.InstrumentCoverage.0.html | 135 - ...l#0}-new.-------.InstrumentCoverage.0.html | 104 - ...osure#0}.-------.InstrumentCoverage.0.html | 83 - ...osure#0}.-------.InstrumentCoverage.0.html | 82 - ...pl#2}-gt.-------.InstrumentCoverage.0.html | 92 - ...pl#2}-le.-------.InstrumentCoverage.0.html | 92 - ...osure#0}.-------.InstrumentCoverage.0.html | 83 - ...pl#2}-lt.-------.InstrumentCoverage.0.html | 92 - ...tial_cmp.-------.InstrumentCoverage.0.html | 78 - ...pl#6}-ne.-------.InstrumentCoverage.0.html | 81 - ...oop.main.-------.InstrumentCoverage.0.html | 143 - ...tch.main.-------.InstrumentCoverage.0.html | 188 - ...ult.main.-------.InstrumentCoverage.0.html | 128 - .../coverage-spanview-deadcode/Makefile | 11 - ...osure#0}.-------.InstrumentCoverage.0.html | 95 - ...osure#1}.-------.InstrumentCoverage.0.html | 95 - ...ure.main.-------.InstrumentCoverage.0.html | 4515 -- ...ons.main.-------.InstrumentCoverage.0.html | 263 - ...#0}-drop.-------.InstrumentCoverage.0.html | 133 - ...strength.-------.InstrumentCoverage.0.html | 85 - ...#1}-drop.-------.InstrumentCoverage.0.html | 133 - ...-in_func.-------.InstrumentCoverage.0.html | 116 - ...ems.main.-------.InstrumentCoverage.0.html | 187 - ...hes.main.-------.InstrumentCoverage.0.html | 161 - ...l#0}-fmt.-------.InstrumentCoverage.0.html | 104 - ..._eq.main.-------.InstrumentCoverage.0.html | 295 - ...l#1}-cmp.-------.InstrumentCoverage.0.html | 76 - ...pl#2}-ge.-------.InstrumentCoverage.0.html | 92 - ...osure#0}.-------.InstrumentCoverage.0.html | 83 - ...osure#0}.-------.InstrumentCoverage.0.html | 82 - ...osure#0}.-------.InstrumentCoverage.0.html | 82 - ...tial_cmp.-------.InstrumentCoverage.0.html | 78 - ...pl#6}-ne.-------.InstrumentCoverage.0.html | 81 - ...l#7}-fmt.-------.InstrumentCoverage.0.html | 109 - ...oop.main.-------.InstrumentCoverage.0.html | 143 - ...ile.main.-------.InstrumentCoverage.0.html | 81 - ...ret.main.-------.InstrumentCoverage.0.html | 127 - .../coverage-spanview/Makefile | 102 + .../escape_url.py | 0 ...ort.main.-------.InstrumentCoverage.0.html | 109 + ...ht_abort.-------.InstrumentCoverage.0.html | 164 + ...ert.main.-------.InstrumentCoverage.0.html | 104 + ...l_assert.-------.InstrumentCoverage.0.html | 97 + ...sure#0}.-------.InstrumentCoverage.0.html} | 21 +- .../async.c.-------.InstrumentCoverage.0.html | 80 + ...sure#0}.-------.InstrumentCoverage.0.html} | 8 +- .../async.d.-------.InstrumentCoverage.0.html | 74 + ...osure#0}.-------.InstrumentCoverage.0.html | 75 + .../async.e.-------.InstrumentCoverage.0.html | 74 + ...sure#0}.-------.InstrumentCoverage.0.html} | 18 +- ...sure#1}.-------.InstrumentCoverage.0.html} | 24 +- ...osure#2}.-------.InstrumentCoverage.0.html | 84 + ...osure#3}.-------.InstrumentCoverage.0.html | 75 + ...block_on.-------.InstrumentCoverage.0.html | 239 + ...osure#0}.-------.InstrumentCoverage.0.html | 75 + .../async.f.-------.InstrumentCoverage.0.html | 74 + ...osure#0}.-------.InstrumentCoverage.0.html | 75 + ...sync.foo.-------.InstrumentCoverage.0.html | 74 + ...osure#0}.-------.InstrumentCoverage.0.html | 82 + .../async.g.-------.InstrumentCoverage.0.html | 80 + ...osure#0}.-------.InstrumentCoverage.0.html | 82 + ...async.h.-------.InstrumentCoverage.0.html} | 20 +- ...osure#0}.-------.InstrumentCoverage.0.html | 91 + ...async.i.-------.InstrumentCoverage.0.html} | 19 +- ...sync.j-c.-------.InstrumentCoverage.0.html | 92 + ...sync.j-d.-------.InstrumentCoverage.0.html | 75 + ...sync.j-f.-------.InstrumentCoverage.0.html | 75 + .../async.j.-------.InstrumentCoverage.0.html | 108 + .../async.k.-------.InstrumentCoverage.0.html | 80 + .../async.l.-------.InstrumentCoverage.0.html | 80 + ...osure#0}.-------.InstrumentCoverage.0.html | 79 + .../async.m.-------.InstrumentCoverage.0.html | 74 + ...ync.main.-------.InstrumentCoverage.0.html | 190 + ...osure#0}.-------.InstrumentCoverage.0.html | 28 +- ...ure#10}.-------.InstrumentCoverage.0.html} | 30 +- ...ure#11}.-------.InstrumentCoverage.0.html} | 30 +- ...osure#1}.-------.InstrumentCoverage.0.html | 28 +- ...osure#2}.-------.InstrumentCoverage.0.html | 131 + ...osure#3}.-------.InstrumentCoverage.0.html | 93 + ...osure#4}.-------.InstrumentCoverage.0.html | 77 + ...osure#5}.-------.InstrumentCoverage.0.html | 115 + ...sure#6}.-------.InstrumentCoverage.0.html} | 33 +- ...osure#7}.-------.InstrumentCoverage.0.html | 115 + ...sure#8}.-------.InstrumentCoverage.0.html} | 28 +- ...osure#9}.-------.InstrumentCoverage.0.html | 89 + ...ure.main.-------.InstrumentCoverage.0.html | 10921 ++++ ...ons.main.-------.InstrumentCoverage.0.html | 326 + ...ode.main.-------.InstrumentCoverage.0.html | 151 + ...nused_fn.-------.InstrumentCoverage.0.html | 151 + ..._library.-------.InstrumentCoverage.0.html | 151 + ...est.main.-------.InstrumentCoverage.0.html | 127 + ...doctests.-------.InstrumentCoverage.0.html | 173 + ...ait.main.-------.InstrumentCoverage.0.html | 59 +- ...#0}-drop.-------.InstrumentCoverage.0.html | 6 +- ...ics.main.-------.InstrumentCoverage.0.html | 117 +- ...strength.-------.InstrumentCoverage.0.html | 6 +- ...#1}-drop.-------.InstrumentCoverage.0.html | 6 +- .../if.main.-------.InstrumentCoverage.0.html | 147 +- ...lse.main.-------.InstrumentCoverage.0.html | 46 +- ...ait_func.-------.InstrumentCoverage.0.html | 6 +- ...-in_func.-------.InstrumentCoverage.0.html | 203 + ...it_func.-------.InstrumentCoverage.0.html} | 52 +- ...ems.main.-------.InstrumentCoverage.0.html | 45 +- ...ean.main.-------.InstrumentCoverage.0.html | 121 +- ...lue.main.-------.InstrumentCoverage.0.html | 6 +- ...hes.main.-------.InstrumentCoverage.0.html | 6 +- ...l#0}-fmt.-------.InstrumentCoverage.0.html | 25 +- ...ern.main.-------.InstrumentCoverage.0.html | 271 + ...ops.main.-------.InstrumentCoverage.0.html | 88 +- ...low.main.-------.InstrumentCoverage.0.html | 260 + ...overflow.-------.InstrumentCoverage.0.html | 396 + ...ind.main.-------.InstrumentCoverage.0.html | 104 + ...ht_panic.-------.InstrumentCoverage.0.html | 164 + ..._eq.main.-------.InstrumentCoverage.0.html | 6 +- ...l#0}-new.-------.InstrumentCoverage.0.html | 12 +- ...l#1}-cmp.-------.InstrumentCoverage.0.html | 74 + ...osure#0}.-------.InstrumentCoverage.0.html | 4 +- ...osure#0}.-------.InstrumentCoverage.0.html | 2 +- ...pl#2}-ge.-------.InstrumentCoverage.0.html | 4 +- ...osure#0}.-------.InstrumentCoverage.0.html | 4 +- ...osure#0}.-------.InstrumentCoverage.0.html | 2 +- ...pl#2}-gt.-------.InstrumentCoverage.0.html | 4 +- ...osure#0}.-------.InstrumentCoverage.0.html | 4 +- ...osure#0}.-------.InstrumentCoverage.0.html | 2 +- ...pl#2}-le.-------.InstrumentCoverage.0.html | 4 +- ...osure#0}.-------.InstrumentCoverage.0.html | 4 +- ...osure#0}.-------.InstrumentCoverage.0.html | 2 +- ...pl#2}-lt.-------.InstrumentCoverage.0.html | 4 +- ...tial_cmp.-------.InstrumentCoverage.0.html | 74 + ...total_eq.-------.InstrumentCoverage.0.html | 4 +- ...pl#6}-eq.-------.InstrumentCoverage.0.html | 7 +- ...l#6}-ne.-------.InstrumentCoverage.0.html} | 9 +- ...l#7}-fmt.-------.InstrumentCoverage.0.html | 2 +- ...8}-clone.-------.InstrumentCoverage.0.html | 2 +- ...oop.main.-------.InstrumentCoverage.0.html | 206 + ...tch.main.-------.InstrumentCoverage.0.html | 100 +- ...oop.main.-------.InstrumentCoverage.0.html | 17 +- ...ult.call.-------.InstrumentCoverage.0.html | 9 +- ...ult.main.-------.InstrumentCoverage.0.html | 38 +- ...function.-------.InstrumentCoverage.0.html | 119 + ...function.-------.InstrumentCoverage.0.html | 133 + ...function.-------.InstrumentCoverage.0.html | 119 + ...ib_crate.-------.InstrumentCoverage.0.html | 190 + ...function.-------.InstrumentCoverage.0.html | 133 + ...function.-------.InstrumentCoverage.0.html | 113 + ...function.-------.InstrumentCoverage.0.html | 133 + ...function.-------.InstrumentCoverage.0.html | 133 + ...function.-------.InstrumentCoverage.0.html | 133 + ...ate.main.-------.InstrumentCoverage.0.html | 193 + ...ile.main.-------.InstrumentCoverage.0.html | 9 +- ...ret.main.-------.InstrumentCoverage.0.html | 27 +- ...sure#0}.-------.InstrumentCoverage.0.html} | 20 +- ...osure#1}.-------.InstrumentCoverage.0.html | 81 + ...eld.main.-------.InstrumentCoverage.0.html | 138 + src/test/run-make-fulldeps/coverage/abort.rs | 67 + src/test/run-make-fulldeps/coverage/assert.rs | 32 + src/test/run-make-fulldeps/coverage/async.rs | 128 + .../run-make-fulldeps/coverage/closure.rs | 62 + .../coverage/compiletest-ignore-dir | 4 +- .../run-make-fulldeps/coverage/conditions.rs | 20 + .../coverage/coverage_tools.mk | 43 +- .../run-make-fulldeps/coverage/dead_code.rs | 37 + .../run-make-fulldeps/coverage/doctest.rs | 66 + .../run-make-fulldeps/coverage/generics.rs | 6 +- .../run-make-fulldeps/coverage/if_else.rs | 2 +- .../run-make-fulldeps/coverage/inner_items.rs | 2 +- .../coverage/lib/doctest_crate.rs | 9 + .../coverage/lib/used_crate.rs | 104 + .../coverage/loop_break_value.rs | 2 +- .../coverage/loops_branches.rs | 2 +- .../coverage/match_or_pattern.rs | 45 + .../run-make-fulldeps/coverage/overflow.rs | 63 + .../coverage/panic_unwind.rs | 49 + .../run-make-fulldeps/coverage/partial_eq.rs | 70 +- .../coverage/simple_match.rs | 2 +- .../run-make-fulldeps/coverage/uses_crate.rs | 12 + .../coverage/while_early_ret.rs | 5 - src/test/run-make-fulldeps/coverage/yield.rs | 37 + src/test/run-make-fulldeps/issue-19371/foo.rs | 1 - .../run-make-fulldeps/libtest-json/Makefile | 6 +- .../libtest-json/output-default.json | 2 +- .../libtest-json/output-stdout-success.json | 2 +- .../run-make-fulldeps/separate-link/Makefile | 6 + src/test/run-make-fulldeps/simd-ffi/simd.rs | 2 +- .../run-make-fulldeps/split-dwarf/Makefile | 8 + src/test/run-make-fulldeps/split-dwarf/foo.rs | 1 + .../run-make-fulldeps/target-specs/foo.rs | 2 +- src/test/run-make/fmt-write-bloat/Makefile | 25 + src/test/run-make/fmt-write-bloat/main.rs | 32 + src/test/run-pass-valgrind/exit-flushes.rs | 1 - src/test/rustdoc-js/basic.rs | 2 +- src/test/rustdoc-js/doc-alias-filter-out.rs | 2 - src/test/rustdoc-js/doc-alias-filter.rs | 2 - src/test/rustdoc-js/doc-alias-whitespace.rs | 2 - src/test/rustdoc-js/doc-alias.rs | 2 - src/test/rustdoc-js/summaries.js | 21 + src/test/rustdoc-js/summaries.rs | 18 + src/test/rustdoc-json/check_missing_items.py | 187 + src/test/rustdoc-json/compare.py | 129 + src/test/rustdoc-json/nested.expected | 196 + src/test/rustdoc-json/nested.rs | 7 + src/test/rustdoc-json/structs.expected | 456 + src/test/rustdoc-json/structs.rs | 17 + src/test/rustdoc-ui/cfg-test.rs | 1 + src/test/rustdoc-ui/cfg-test.stdout | 6 +- .../check-doc-alias-attr-location.rs | 2 - .../check-doc-alias-attr-location.stderr | 8 +- src/test/rustdoc-ui/check-doc-alias-attr.rs | 1 - .../rustdoc-ui/check-doc-alias-attr.stderr | 36 +- src/test/rustdoc-ui/check-fail.rs | 21 + src/test/rustdoc-ui/check-fail.stderr | 57 + src/test/rustdoc-ui/check.rs | 11 + src/test/rustdoc-ui/check.stderr | 49 + src/test/rustdoc-ui/coverage/exotic.stdout | 3 +- src/test/rustdoc-ui/doc-alias-assoc-const.rs | 1 - .../rustdoc-ui/doc-alias-assoc-const.stderr | 2 +- .../rustdoc-ui/doc-alias-crate-level.stderr | 4 +- .../rustdoc-ui/doc-test-doctest-feature.rs | 4 +- .../doc-test-doctest-feature.stdout | 4 +- .../rustdoc-ui/doc-test-rustdoc-feature.rs | 1 + .../doc-test-rustdoc-feature.stdout | 4 +- .../rustdoc-ui/doc-without-codeblock.stderr | 12 +- src/test/rustdoc-ui/doctest-output.rs | 1 + src/test/rustdoc-ui/doctest-output.stdout | 8 +- .../rustdoc-ui/failed-doctest-compile-fail.rs | 1 + .../failed-doctest-compile-fail.stdout | 8 +- .../failed-doctest-missing-codes.rs | 1 + .../failed-doctest-missing-codes.stdout | 10 +- src/test/rustdoc-ui/failed-doctest-output.rs | 1 + .../rustdoc-ui/failed-doctest-output.stdout | 16 +- .../rustdoc-ui/failed-doctest-should-panic.rs | 1 + .../failed-doctest-should-panic.stdout | 8 +- .../alias-ice.rs} | 0 .../alias-ice.stderr} | 4 +- .../ambiguity.rs} | 0 .../ambiguity.stderr} | 48 +- .../anchors.rs} | 0 .../anchors.stderr} | 10 +- .../auxiliary/intra-doc-broken.rs | 0 .../broken-reexport.rs} | 0 .../disambiguator-mismatch.rs} | 0 .../disambiguator-mismatch.stderr} | 24 +- .../double-anchor.rs} | 0 .../double-anchor.stderr} | 2 +- .../errors.rs} | 0 .../errors.stderr} | 58 +- .../malformed-generics.rs} | 0 .../malformed-generics.stderr} | 32 +- .../prim-conflict.rs} | 0 .../prim-conflict.stderr} | 10 +- .../private.private.stderr} | 2 +- .../private.public.stderr} | 2 +- .../private.rs} | 0 .../span-ice-55723.rs} | 0 .../span-ice-55723.stderr} | 4 +- .../warning-crlf.rs} | 0 .../warning-crlf.stderr} | 8 +- .../warning.rs} | 0 .../warning.stderr} | 136 +- src/test/rustdoc-ui/invalid-html-tags.rs | 21 + src/test/rustdoc-ui/invalid-keyword.rs | 4 + src/test/rustdoc-ui/invalid-keyword.stderr | 8 + .../lint-missing-doc-code-example.stderr | 28 +- .../reference-link-has-one-warning.rs | 6 - .../reference-link-has-one-warning.stderr | 10 - src/test/rustdoc-ui/test-no_std.rs | 1 + src/test/rustdoc-ui/test-no_std.stdout | 4 +- src/test/rustdoc-ui/unparseable-doc-test.rs | 1 + .../rustdoc-ui/unparseable-doc-test.stdout | 10 +- src/test/rustdoc/async-fn.rs | 44 + src/test/rustdoc/auto-traits.rs | 2 +- src/test/rustdoc/auto_aliases.rs | 2 +- src/test/rustdoc/auxiliary/auto-traits.rs | 2 +- .../rustdoc/auxiliary/normalize-assoc-item.rs | 12 + .../rustdoc/auxiliary/rustdoc-default-impl.rs | 2 +- .../rustdoc-impl-parts-crosscrate.rs | 4 +- src/test/rustdoc/check.rs | 5 + src/test/rustdoc/codeblock-title.rs | 11 +- src/test/rustdoc/const-display.rs | 10 + .../const-equate-pred.rs | 0 src/test/rustdoc/decl_macro.rs | 39 + src/test/rustdoc/decl_macro_priv.rs | 14 + src/test/rustdoc/deprecated-future.rs | 2 - src/test/rustdoc/deprecated.rs | 2 - src/test/rustdoc/doc-cfg-traits.rs | 124 + src/test/rustdoc/doc-cfg.rs | 15 +- src/test/rustdoc/external-doc.rs | 16 + src/test/rustdoc/impl-parts-crosscrate.rs | 6 +- src/test/rustdoc/impl-parts.rs | 12 +- src/test/rustdoc/inline_cross/impl_trait.rs | 5 +- .../rustdoc/intra-doc-crate/auxiliary/self.rs | 7 + src/test/rustdoc/intra-doc-crate/self.rs | 6 + .../rustdoc/intra-doc-link-mod-ambiguity.rs | 18 - .../anchors.rs} | 4 +- .../rustdoc/intra-doc/associated-defaults.rs | 27 + .../rustdoc/intra-doc/associated-items.rs | 61 + .../auxiliary/intra-link-extern-crate.rs | 0 .../auxiliary/intra-link-pub-use.rs | 0 .../intra-link-reexport-additional-docs.rs | 0 .../auxiliary/intra-links-external-traits.rs | 0 .../{ => intra-doc}/auxiliary/my-core.rs | 0 .../auxiliary/proc-macro-macro.rs} | 1 - .../auxiliary/through-proc-macro-aux.rs | 0 .../{intra-links.rs => intra-doc/basic.rs} | 46 +- .../builtin-macros.rs} | 2 +- .../cross-crate}/additional_doc.rs | 0 .../cross-crate}/auxiliary/additional_doc.rs | 0 .../cross-crate}/auxiliary/hidden.rs | 0 .../cross-crate}/auxiliary/intra-doc-basic.rs | 0 .../auxiliary/intra-link-cross-crate-crate.rs | 0 .../cross-crate}/auxiliary/macro_inner.rs | 0 .../cross-crate}/auxiliary/module.rs | 0 .../cross-crate}/auxiliary/proc_macro.rs | 0 .../cross-crate}/auxiliary/submodule-inner.rs | 0 .../cross-crate}/auxiliary/submodule-outer.rs | 0 .../cross-crate}/auxiliary/traits.rs | 0 .../cross-crate}/basic.rs | 0 .../cross-crate/crate.rs} | 0 .../cross-crate}/hidden.rs | 0 .../cross-crate}/macro.rs | 0 .../cross-crate}/module.rs | 0 .../cross-crate}/submodule-inner.rs | 0 .../cross-crate}/submodule-outer.rs | 0 .../cross-crate}/traits.rs | 0 .../intra-doc/disambiguators-removed.rs | 51 + .../enum-struct-field.rs} | 0 .../extern-crate.rs} | 0 src/test/rustdoc/intra-doc/extern-type.rs | 17 + .../external-traits.rs} | 0 .../generic-params.rs} | 3 + .../in-bodies.rs} | 0 .../libstd-re-export.rs} | 0 src/test/rustdoc/intra-doc/mod-ambiguity.rs | 16 + src/test/rustdoc/intra-doc/prim-assoc.rs | 5 + .../prim-methods-external-core.rs} | 2 +- .../prim-methods-local.rs} | 2 +- .../prim-methods.rs} | 2 +- src/test/rustdoc/intra-doc/prim-precedence.rs | 17 + .../primitive-non-default-impl.rs} | 6 +- .../private-failures-ignored.rs} | 0 .../private.rs} | 0 src/test/rustdoc/intra-doc/proc-macro.rs | 27 + .../pub-use.rs} | 0 src/test/rustdoc/intra-doc/raw-ident-self.rs | 13 + .../reexport-additional-docs.rs} | 0 .../{intra-link-self.rs => intra-doc/self.rs} | 0 .../{ => intra-doc}/through-proc-macro.rs | 0 .../trait-impl.rs} | 0 .../trait-item.rs} | 2 +- .../true-false.rs} | 0 .../rustdoc/intra-link-associated-defaults.rs | 27 - .../rustdoc/intra-link-associated-items.rs | 61 - .../intra-link-disambiguators-removed.rs | 51 - src/test/rustdoc/intra-link-prim-assoc.rs | 5 - .../rustdoc/intra-link-prim-precedence.rs | 17 - src/test/rustdoc/intra-link-prim-self.rs | 36 + src/test/rustdoc/intra-link-proc-macro.rs | 27 - src/test/rustdoc/intra-link-self-cache.rs | 14 + src/test/rustdoc/issue-32395.rs | 2 + src/test/rustdoc/issue-76501.rs | 2 - src/test/rustdoc/issue-78673.rs | 24 + src/test/rustdoc/issue-79201.rs | 41 + src/test/rustdoc/keyword.rs | 5 + ...ext-summaries.rs => markdown-summaries.rs} | 9 +- src/test/rustdoc/normalize-assoc-item.rs | 69 + src/test/rustdoc/pub-restricted.rs | 34 - .../rustdoc/raw-ident-eliminate-r-hashtag.rs | 22 + src/test/rustdoc/redirect-rename.rs | 12 + src/test/rustdoc/reexport-check.rs | 1 + src/test/rustdoc/rustc_deprecated-future.rs | 12 +- src/test/rustdoc/show-const-contents.rs | 1 + src/test/rustdoc/stability.rs | 2 +- .../rustdoc/synthetic_auto/crate-local.rs | 2 +- src/test/rustdoc/trait-src-link.rs | 26 + src/test/rustdoc/visibility.rs | 76 + .../internal-lints/existing_doc_keyword.rs | 11 + .../existing_doc_keyword.stderr | 15 + .../ui-fulldeps/lint-plugin-forbid-attrs.rs | 8 +- .../lint-plugin-forbid-attrs.stderr | 10 +- .../ui-fulldeps/lint-plugin-forbid-cmdline.rs | 6 +- .../lint-plugin-forbid-cmdline.stderr | 6 +- .../ui/abi/issues/issue-22565-rust-call.rs | 8 + .../abi/issues/issue-22565-rust-call.stderr | 8 + src/test/ui/abi/rustcall-generic.rs | 9 + src/test/ui/abi/segfault-no-out-of-stack.rs | 1 - src/test/ui/abi/stack-probes-lto.rs | 1 - src/test/ui/abi/stack-probes.rs | 1 - src/test/ui/allocator/custom.rs | 15 +- .../no_std-alloc-error-handler-custom.rs | 1 - .../no_std-alloc-error-handler-default.rs | 1 - src/test/ui/allocator/xcrate-use.rs | 10 +- .../bounds-check-no-overflow.rs | 1 - .../array-slice-vec/box-of-array-of-drop-1.rs | 7 +- .../array-slice-vec/box-of-array-of-drop-2.rs | 7 +- src/test/ui/array-slice-vec/nested-vec-3.rs | 7 +- src/test/ui/asm/bad-arch.rs | 4 +- src/test/ui/asm/naked-functions.rs | 169 + src/test/ui/asm/naked-functions.stderr | 300 + src/test/ui/asm/naked-invalid-attr.rs | 51 + src/test/ui/asm/naked-invalid-attr.stderr | 42 + src/test/ui/assert-eq-trailing-comma.rs | 5 - src/test/ui/assert-escape.rs | 5 - src/test/ui/assert-ne-trailing-comma.rs | 5 - ...20-assoc-const-arith-overflow.noopt.stderr | 16 +- ...9020-assoc-const-arith-overflow.opt.stderr | 16 +- ...h-overflow.opt_with_overflow_checks.stderr | 16 +- .../issue-69020-assoc-const-arith-overflow.rs | 2 - .../dyn-impl-trait-type.rs | 2 +- .../ui/associated-type-bounds/dyn-lcsit.rs | 2 +- .../dyn-rpit-and-let.rs | 2 +- src/test/ui/associated-type-bounds/lcsit.rs | 2 +- .../order-dependent-bounds-issue-54121.rs | 47 + src/test/ui/associated-type-bounds/rpit.rs | 2 +- .../trait-alias-impl-trait.rs | 2 +- ...ciated-types-project-from-hrtb-in-fn.fixed | 2 +- ...ssociated-types-project-from-hrtb-in-fn.rs | 2 +- ...iated-types-project-from-hrtb-in-fn.stderr | 3 +- ...iated-types-project-from-hrtb-in-struct.rs | 8 +- ...d-types-project-from-hrtb-in-struct.stderr | 9 +- ...es-project-from-hrtb-in-trait-method.fixed | 4 +- ...types-project-from-hrtb-in-trait-method.rs | 4 +- ...s-project-from-hrtb-in-trait-method.stderr | 5 +- .../ui/associated-types/defaults-wf.stderr | 2 +- .../hr-associated-type-bound-1.stderr | 1 - .../hr-associated-type-bound-object.stderr | 1 - .../hr-associated-type-bound-param-1.stderr | 1 - .../hr-associated-type-bound-param-2.stderr | 3 - .../hr-associated-type-bound-param-3.stderr | 1 - .../hr-associated-type-bound-param-4.stderr | 1 - .../hr-associated-type-bound-param-5.stderr | 4 - .../hr-associated-type-bound-param-6.stderr | 1 - .../associated-types/impl-wf-cycle-1.stderr | 3 + .../project-recursion-limit-non-fatal.rs | 58 + .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- .../ui/async-await/issue-64130-3-other.rs | 2 +- .../ui/async-await/issue-64130-3-other.stderr | 2 - ...sue-74072-lifetime-name-annotations.stderr | 2 +- .../issue-75785-confusing-named-region.rs | 13 + .../issue-75785-confusing-named-region.stderr | 15 + src/test/ui/atomic-access-bool.rs | 24 - src/test/ui/atomic-alignment.rs | 38 - src/test/ui/atomic-compare_exchange.rs | 31 - src/test/ui/atomic-print.rs | 1 - src/test/ui/attr-eq-token-tree.rs | 2 +- src/test/ui/attr-eq-token-tree.stderr | 6 +- src/test/ui/attributes/key-value-expansion.rs | 10 +- .../ui/attributes/key-value-expansion.stderr | 21 +- src/test/ui/attributes/key-value-non-ascii.rs | 5 + .../ui/attributes/key-value-non-ascii.stderr | 14 + src/test/ui/attrs-resolution-errors.rs | 10 +- src/test/ui/attrs-resolution-errors.stderr | 30 +- .../ui/auto-traits/auto-trait-validation.rs | 2 +- src/test/ui/auto-traits/auto-traits.rs | 2 +- src/test/ui/auto-traits/issue-23080-2.rs | 2 +- src/test/ui/auto-traits/issue-23080.rs | 2 +- .../typeck-auto-trait-no-supertraits-2.rs | 2 +- .../typeck-auto-trait-no-supertraits.rs | 2 +- ...-default-trait-impl-constituent-types-2.rs | 2 +- ...ault-trait-impl-constituent-types-2.stderr | 2 - ...ck-default-trait-impl-constituent-types.rs | 2 +- ...efault-trait-impl-constituent-types.stderr | 3 - .../typeck-default-trait-impl-negation.rs | 2 +- .../typeck-default-trait-impl-negation.stderr | 6 - .../typeck-default-trait-impl-precedence.rs | 2 +- src/test/ui/auxiliary/fancy-panic.rs | 6 + src/test/ui/backtrace-debuginfo.rs | 1 - src/test/ui/backtrace.rs | 1 - src/test/ui/bad/bad-sized.stderr | 2 +- src/test/ui/big-literals.rs | 8 +- src/test/ui/binop/issue-77910-1.rs | 11 + src/test/ui/binop/issue-77910-1.stderr | 26 + src/test/ui/binop/issue-77910-2.rs | 9 + src/test/ui/binop/issue-77910-2.stderr | 11 + src/test/ui/bool-not.rs | 6 - src/test/ui/bool.rs | 72 - .../borrowck-mut-borrow-linear-errors.stderr | 2 +- .../ui/borrowck/mut-borrow-in-loop.stderr | 6 +- .../ui/borrowck/two-phase-across-loop.stderr | 2 +- src/test/ui/box/leak-alloc.rs | 16 +- src/test/ui/cfg/cfg-family.rs | 1 - src/test/ui/cfg/cfg-target-family.rs | 1 - src/test/ui/char_unicode.rs | 10 - src/test/ui/check-doc-alias-attr.stderr | 30 +- src/test/ui/cleanup-shortcircuit.rs | 1 - .../arrays-completely-captured.rs | 24 + .../arrays-completely-captured.stderr | 57 + .../capture-disjoint-field-struct.rs | 33 + .../capture-disjoint-field-struct.stderr | 57 + .../capture-disjoint-field-tuple.rs | 28 + .../capture-disjoint-field-tuple.stderr | 57 + .../2229_closure_analysis/capture-enums.rs | 64 + .../capture-enums.stderr | 122 + .../destructure_patterns.rs | 77 + .../destructure_patterns.stderr | 177 + .../diagnostics/arrays.rs | 86 + .../diagnostics/arrays.stderr | 111 + .../2229_closure_analysis/diagnostics/box.rs | 65 + .../diagnostics/box.stderr | 55 + .../diagnostics/multilevel-path.rs | 28 + .../diagnostics/multilevel-path.stderr | 26 + .../diagnostics/simple-struct-min-capture.rs | 26 + .../simple-struct-min-capture.stderr | 26 + .../feature-gate-capture_disjoint_fields.rs | 20 + ...eature-gate-capture_disjoint_fields.stderr | 57 + .../filter-on-struct-member.rs | 45 + .../filter-on-struct-member.stderr | 35 + .../multilevel-path-1.rs | 41 + .../multilevel-path-1.stderr | 57 + .../multilevel-path-2.rs | 37 + .../multilevel-path-2.stderr | 57 + .../2229_closure_analysis/nested-closure.rs | 56 + .../nested-closure.stderr | 110 + .../path-with-array-access.rs | 35 + .../path-with-array-access.stderr | 57 + .../2229_closure_analysis/run_pass/box.rs | 97 + .../2229_closure_analysis/run_pass/box.stderr | 11 + .../run_pass/capture-disjoint-field-struct.rs | 28 + .../capture-disjoint-field-struct.stderr | 11 + .../capture-disjoint-field-tuple-mut.rs | 23 + .../capture-disjoint-field-tuple-mut.stderr | 11 + .../run_pass/capture-disjoint-field-tuple.rs | 24 + .../capture-disjoint-field-tuple.stderr | 11 + .../disjoint-capture-in-same-closure.rs | 27 + .../disjoint-capture-in-same-closure.stderr | 11 + .../run_pass/filter-on-struct-member.rs | 41 + .../run_pass/filter-on-struct-member.stderr | 11 + .../run_pass/multilevel-path-1.rs | 36 + .../run_pass/multilevel-path-1.stderr | 11 + .../run_pass/multilevel-path-2.rs | 34 + .../run_pass/multilevel-path-2.stderr | 11 + .../run_pass/multilevel-path-3.rs | 31 + .../run_pass/multilevel-path-3.stderr | 11 + .../run_pass/nested-closure.rs | 40 + .../run_pass/nested-closure.stderr | 11 + .../simple-struct-min-capture.rs | 41 + .../simple-struct-min-capture.stderr | 62 + .../2229_closure_analysis/wild_patterns.rs | 75 + .../wild_patterns.stderr | 147 + src/test/ui/cmp-default.rs | 73 - .../coherence/coherence-default-trait-impl.rs | 2 +- ...ce-impl-trait-for-marker-trait-negative.rs | 2 +- ...ce-impl-trait-for-marker-trait-positive.rs | 2 +- src/test/ui/command/command-argv0-debug.rs | 1 - src/test/ui/command/command-argv0.rs | 1 - src/test/ui/command/command-exec.rs | 1 - src/test/ui/command/command-pre-exec.rs | 1 - src/test/ui/command/command-uid-gid.rs | 1 - .../cfg-generic-params.stderr | 24 +- .../cfg_accessible-stuck.rs | 2 +- .../cfg_accessible-stuck.stderr | 8 +- ...ay-size-in-generic-struct-param.min.stderr | 4 +- .../const-arg-in-const-arg.min.stderr | 7 + .../const-argument-if-length.full.stderr | 11 +- .../const-argument-if-length.min.stderr | 1 + .../const-argument-if-length.rs | 1 - ...const-param-before-other-params.min.stderr | 4 +- .../const-param-elided-lifetime.min.stderr | 10 +- .../const-generics/const-param-shadowing.rs | 9 + .../const-param-shadowing.stderr | 14 + ...ram-type-depends-on-const-param.min.stderr | 4 +- ...-gate-const_evaluatable_checked.min.stderr | 1 + .../const_evaluatable_checked/fn_call.rs | 2 +- .../simple.min.stderr | 2 + .../simple_fail.min.stderr | 1 + .../const-generics/different_byref.min.stderr | 2 +- ...rbid-non-structural_match-types.min.stderr | 4 +- ...c-function-call-in-array-length.min.stderr | 2 + .../generic-sum-in-array-length.min.stderr | 2 + .../infer/cannot-infer-const-args.full.stderr | 5 + .../infer/cannot-infer-const-args.min.stderr | 5 + .../const-generics/infer/issue-77092.stderr | 5 + .../infer/method-chain.full.stderr | 5 + .../infer/method-chain.min.stderr | 5 + .../infer/one-param-uninferred.full.stderr | 14 + .../infer/one-param-uninferred.min.stderr | 14 + .../infer/one-param-uninferred.rs | 17 + .../infer/uninferred-consts.full.stderr | 7 +- .../infer/uninferred-consts.min.stderr | 7 +- .../const-generics/infer/uninferred-consts.rs | 2 +- ...ics-type_name-as-const-argument.min.stderr | 3 +- .../invalid-constant-in-args.rs | 5 +- .../invalid-constant-in-args.stderr | 8 +- src/test/ui/const-generics/invalid-enum.rs | 12 +- .../ui/const-generics/invalid-enum.stderr | 64 +- .../issue-61522-array-len-succ.min.stderr | 2 + ...96-impl-trait-for-str-const-arg.min.stderr | 2 +- .../ui/const-generics/issue-67375.min.stderr | 1 + .../const-generics/issue-67945-1.min.stderr | 2 + .../const-generics/issue-67945-2.min.stderr | 2 + .../issues/issue-61747.min.stderr | 1 + .../issues/issue-61935.min.stderr | 1 + .../issues/issue-62220.min.stderr | 1 + .../issues/issue-62456.min.stderr | 1 + .../issues/issue-62579-no-match.min.stderr | 2 +- .../issues/issue-62878.full.stderr | 18 +- .../issues/issue-62878.min.stderr | 2 +- .../ui/const-generics/issues/issue-62878.rs | 3 +- .../issues/issue-63322-forbid-dyn.min.stderr | 2 +- .../issues/issue-64494.min.stderr | 2 + .../issues/issue-66205.min.stderr | 1 + .../issues/issue-68366.min.stderr | 1 + .../issues/issue-68615-adt.min.stderr | 2 +- .../issues/issue-68615-array.min.stderr | 2 +- .../issues/issue-68977.min.stderr | 2 + .../issues/issue-71169.min.stderr | 2 +- .../issues/issue-72787.min.stderr | 4 + ...ue-72819-generic-in-const-eval.full.stderr | 6 +- ...sue-72819-generic-in-const-eval.min.stderr | 3 +- .../issue-72819-generic-in-const-eval.rs | 4 +- .../ui/const-generics/issues/issue-73260.rs | 4 +- .../const-generics/issues/issue-73260.stderr | 16 +- .../issues/issue-73491.min.stderr | 2 +- .../issues/issue-74101.min.stderr | 4 +- .../issues/issue-74255.min.stderr | 2 +- .../issues/issue-74950.min.stderr | 10 +- .../issues/issue-75047.min.stderr | 2 +- .../ui/const-generics/issues/issue-76595.rs | 2 +- .../const-generics/issues/issue-76595.stderr | 4 +- .../issue-76701-ty-param-in-const.min.stderr | 2 + .../macro_rules-braces.full.stderr | 31 +- .../macro_rules-braces.min.stderr | 35 +- .../ui/const-generics/macro_rules-braces.rs | 37 +- .../complex-expression.stderr | 7 + .../min_const_generics/complex-types.stderr | 14 +- ...const-expression-suggest-missing-braces.rs | 3 +- ...t-expression-suggest-missing-braces.stderr | 36 +- .../min_const_generics/inferred_const.rs | 8 + .../min_const_generics/inferred_const.stderr | 11 + .../min_const_generics/macro-fail.rs | 12 +- .../min_const_generics/macro-fail.stderr | 56 +- .../min_const_generics/macro.rs | 10 +- .../self-ty-in-const-1.stderr | 1 + .../static-reference-array-const-param.stderr | 2 +- ...nsmute-const-param-static-reference.stderr | 2 +- .../ui/const-generics/nested-type.full.stderr | 11 +- .../ui/const-generics/nested-type.min.stderr | 13 +- src/test/ui/const-generics/nested-type.rs | 1 - .../occurs-check/unused-substs-5.rs | 20 + .../occurs-check/unused-substs-5.stderr | 12 + ...ams-in-ct-in-ty-param-lazy-norm.min.stderr | 1 + src/test/ui/const-generics/promotion.rs | 11 + .../slice-const-param-mismatch.min.stderr | 4 +- .../slice-const-param.min.stderr | 4 +- .../std/const-generics-range.min.stderr | 12 +- .../type-dependent/issue-71348.min.stderr | 4 +- src/test/ui/const-generics/wf-misc.min.stderr | 2 + src/test/ui/consts/ascii_ctype.rs | 53 - src/test/ui/consts/assume-type-intrinsics.rs | 13 + .../ui/consts/assume-type-intrinsics.stderr | 21 + src/test/ui/consts/const-call.rs | 1 - src/test/ui/consts/const-call.stderr | 11 +- src/test/ui/consts/const-err-early.rs | 2 +- src/test/ui/consts/const-err-early.stderr | 4 +- src/test/ui/consts/const-err-multi.rs | 2 +- src/test/ui/consts/const-err-multi.stderr | 4 +- src/test/ui/consts/const-err2.noopt.stderr | 12 +- src/test/ui/consts/const-err2.opt.stderr | 12 +- ...const-err2.opt_with_overflow_checks.stderr | 12 +- src/test/ui/consts/const-err2.rs | 6 +- .../const-eval/const-eval-overflow-3.rs | 2 - .../const-eval/const-eval-overflow-3.stderr | 2 +- .../const-eval/const-eval-overflow-3b.rs | 2 - .../const-eval/const-eval-overflow-3b.stderr | 4 +- .../const-eval/const-eval-overflow-4.rs | 2 - .../const-eval/const-eval-overflow-4.stderr | 2 +- .../const-eval/const-eval-overflow-4b.rs | 3 - .../const-eval/const-eval-overflow-4b.stderr | 6 +- .../consts/const-eval/const-eval-overflow2.rs | 2 - .../const-eval/const-eval-overflow2.stderr | 16 +- .../const-eval/const-eval-overflow2b.rs | 2 - .../const-eval/const-eval-overflow2b.stderr | 16 +- .../const-eval/const-eval-overflow2c.rs | 2 - .../const-eval/const-eval-overflow2c.stderr | 16 +- src/test/ui/consts/const-eval/dangling.rs | 2 +- .../ui/consts/const-eval/erroneous-const.rs | 4 +- .../consts/const-eval/erroneous-const.stderr | 16 +- .../const-eval/heap/alloc_intrinsic_errors.rs | 17 + .../heap/alloc_intrinsic_errors.stderr | 17 + .../heap/alloc_intrinsic_nontransient.rs | 20 + .../heap/alloc_intrinsic_nontransient_fail.rs | 19 + .../alloc_intrinsic_nontransient_fail.stderr | 8 + .../heap/alloc_intrinsic_transient.rs | 20 + .../const-eval/heap/alloc_intrinsic_uninit.rs | 10 + .../heap/alloc_intrinsic_uninit.stderr | 11 + .../heap/alloc_intrinsic_untyped.rs | 10 + .../heap/alloc_intrinsic_untyped.stderr | 8 + src/test/ui/consts/const-eval/issue-52442.rs | 1 - .../ui/consts/const-eval/issue-52442.stderr | 11 +- .../consts/const-eval/match-test-ptr-null.rs | 1 - .../const-eval/match-test-ptr-null.stderr | 11 +- src/test/ui/consts/const-eval/unwind-abort.rs | 4 +- .../ui/consts/const-eval/unwind-abort.stderr | 23 +- src/test/ui/consts/const-fn-feature-flags.rs | 13 - src/test/ui/consts/const-int-arithmetic.rs | 2 - .../ui/consts/const-int-overflowing-rpass.rs | 2 +- src/test/ui/consts/const-int-pow-rpass.rs | 1 - src/test/ui/consts/const-negation.rs | 10 +- src/test/ui/consts/const-size_of-cycle.stderr | 10 - src/test/ui/consts/const-str-ptr.rs | 17 - src/test/ui/consts/issue-63952.rs | 2 - src/test/ui/consts/issue-63952.stderr | 2 +- .../issue-68542-closure-in-array-len.rs | 1 - .../issue-68542-closure-in-array-len.stderr | 11 +- src/test/ui/consts/issue-76064.rs | 3 + src/test/ui/consts/issue-76064.stderr | 13 + src/test/ui/consts/issue-79137-monomorphic.rs | 19 + src/test/ui/consts/issue-79137-toogeneric.rs | 19 + .../ui/consts/issue-79137-toogeneric.stderr | 14 + .../consts/issue-79152-const-array-index.rs | 11 + .../const_refers_to_static_cross_crate.stderr | 5 + src/test/ui/consts/promote-not.rs | 14 +- src/test/ui/consts/promote-not.stderr | 43 +- src/test/ui/consts/promote_fn_calls_std.rs | 1 + src/test/ui/consts/promotion.rs | 2 +- .../const-repeat.rs | 27 + .../consts/uninhabited-const-issue-61744.rs | 6 +- .../uninhabited-const-issue-61744.stderr | 149 +- src/test/ui/core-run-destroy.rs | 1 - src/test/ui/cross/cross-file-errors/main.rs | 3 +- .../ui/cross/cross-file-errors/main.stderr | 22 +- src/test/ui/default-alloc-error-hook.rs | 1 - .../rustc_deprecation-in-future.rs | 9 +- .../rustc_deprecation-in-future.stderr | 16 +- src/test/ui/deref-mut-on-ref.rs | 15 - src/test/ui/deref-on-ref.rs | 19 - .../ui/{issues => derives}/issue-36617.rs | 1 - .../ui/{issues => derives}/issue-36617.stderr | 10 +- .../ui/destructuring-assignment/drop-order.rs | 44 + .../nested_destructure.rs | 3 + .../slice_destructure.rs | 2 + .../slice_destructure_fail.rs | 1 + .../slice_destructure_fail.stderr | 8 +- .../struct_destructure.rs | 6 +- .../struct_destructure_fail.rs | 2 + .../struct_destructure_fail.stderr | 32 +- .../tuple_destructure.rs | 2 + .../tuple_destructure_fail.rs | 1 + .../tuple_destructure_fail.stderr | 13 +- .../tuple_struct_destructure.rs | 4 +- .../tuple_struct_destructure_fail.rs | 4 + .../tuple_struct_destructure_fail.stderr | 28 +- .../underscore-range-expr-gating.rs | 2 + .../underscore-range-expr-gating.stderr | 13 +- ...92-tuple-destructure-missing-parens.stderr | 33 +- src/test/ui/discrim/discrim-ill-typed.rs | 2 - src/test/ui/discrim/discrim-ill-typed.stderr | 16 +- src/test/ui/discrim/discrim-overflow-2.rs | 2 - src/test/ui/discrim/discrim-overflow-2.stderr | 16 +- src/test/ui/discrim/discrim-overflow.rs | 2 - src/test/ui/discrim/discrim-overflow.stderr | 16 +- src/test/ui/doc-alias-crate-level.rs | 5 +- src/test/ui/doc-alias-crate-level.stderr | 12 +- src/test/ui/doc_keyword.rs | 12 + src/test/ui/doc_keyword.stderr | 20 + src/test/ui/drop/dynamic-drop-async.rs | 1 - src/test/ui/drop/dynamic-drop.rs | 1 - src/test/ui/{issues => dropck}/issue-38868.rs | 0 .../ui/{issues => dropck}/issue-38868.stderr | 0 .../reject-specialized-drops-8142.rs | 9 + .../reject-specialized-drops-8142.stderr | 80 +- src/test/ui/env-args-reverse-iterator.rs | 1 - src/test/ui/env-funky-keys.rs | 1 - src/test/ui/env-home-dir.rs | 51 - src/test/ui/env-vars.rs | 9 +- src/test/ui/error-codes/E0077.stderr | 2 +- src/test/ui/error-codes/E0275.stderr | 127 +- src/test/ui/error-codes/E0277.rs | 2 - src/test/ui/error-codes/E0277.stderr | 4 +- src/test/ui/error-codes/E0390.stderr | 6 +- src/test/ui/error-codes/E0396.rs | 11 + src/test/ui/error-codes/E0396.stderr | 20 +- src/test/ui/error-codes/E0453.rs | 6 +- src/test/ui/error-codes/E0453.stderr | 6 +- src/test/ui/error-codes/E0496.stderr | 2 +- .../e0119/conflict-with-std.stderr | 2 +- src/test/ui/exec-env.rs | 1 - src/test/ui/explain.stdout | 18 +- .../ui/expr/compound-assignment/eval-order.rs | 76 + src/test/ui/{ => expr}/if-bot.rs | 0 .../ui/{if-attrs => expr/if/attrs}/bad-cfg.rs | 0 .../if/attrs}/bad-cfg.stderr | 0 .../if/attrs}/builtin-if-attr.rs | 0 .../if/attrs}/cfg-false-if-attr.rs | 0 .../{if-attrs => expr/if/attrs}/else-attrs.rs | 0 .../if/attrs}/else-attrs.stderr | 0 .../if/attrs}/gate-whole-expr.rs | 0 .../if/attrs}/let-chains-attr.rs | 0 .../if/attrs}/let-chains-attr.stderr | 0 .../if/attrs}/stmt-expr-gated.rs | 0 .../if/attrs}/stmt-expr-gated.stderr | 0 src/test/ui/{ => expr}/if/expr-if-panic-fn.rs | 0 src/test/ui/{ => expr}/if/expr-if-panic.rs | 0 src/test/ui/{ => expr}/if/if-branch-types.rs | 0 .../ui/{ => expr}/if/if-branch-types.stderr | 0 src/test/ui/{ => expr}/if/if-check-panic.rs | 0 src/test/ui/{ => expr/if}/if-check.rs | 0 src/test/ui/{ => expr}/if/if-cond-bot.rs | 0 .../ui/{ => expr/if}/if-else-type-mismatch.rs | 0 .../if}/if-else-type-mismatch.stderr | 0 src/test/ui/{ => expr}/if/if-let-arm-types.rs | 0 .../ui/{ => expr}/if/if-let-arm-types.stderr | 0 src/test/ui/{ => expr}/if/if-let.rs | 0 src/test/ui/{ => expr}/if/if-let.stderr | 0 src/test/ui/{ => expr}/if/if-loop.rs | 0 .../ui/{ => expr}/if/if-no-match-bindings.rs | 0 .../{ => expr}/if/if-no-match-bindings.stderr | 0 src/test/ui/{ => expr/if}/if-ret.rs | 0 src/test/ui/{ => expr/if}/if-ret.stderr | 0 src/test/ui/{ => expr}/if/if-typeck.rs | 0 src/test/ui/{ => expr}/if/if-typeck.stderr | 0 src/test/ui/{ => expr}/if/if-without-block.rs | 0 .../ui/{ => expr}/if/if-without-block.stderr | 0 .../if/if-without-else-as-fn-expr.rs | 0 .../if/if-without-else-as-fn-expr.stderr | 0 .../{ => expr}/if/if-without-else-result.rs | 0 .../if/if-without-else-result.stderr | 0 src/test/ui/extend-for-unit.rs | 12 - src/test/ui/fds-are-cloexec.rs | 1 - .../issue-43106-gating-of-test.rs | 1 + .../issue-43106-gating-of-test.stderr | 2 +- src/test/ui/feature-gates/feature-gate-abi.rs | 12 +- .../ui/feature-gates/feature-gate-abi.stderr | 12 +- ...-traits.rs => feature-gate-auto-traits.rs} | 2 +- ...stderr => feature-gate-auto-traits.stderr} | 6 +- .../feature-gate-custom_attribute2.stderr | 128 +- ...ture-gate-extended_key_value_attributes.rs | 8 + ...-gate-extended_key_value_attributes.stderr | 39 + .../feature-gate-naked_functions.rs | 10 +- .../feature-gate-naked_functions.stderr | 4 +- ...ture-gate-precise_pointer_size_matching.rs | 21 +- ...-gate-precise_pointer_size_matching.stderr | 2 +- src/test/ui/fmt/format-args-capture.rs | 1 + src/test/ui/{if => fmt}/ifmt-bad-arg.rs | 0 src/test/ui/{if => fmt}/ifmt-bad-arg.stderr | 0 .../ui/{if => fmt}/ifmt-bad-format-args.rs | 0 .../{if => fmt}/ifmt-bad-format-args.stderr | 0 src/test/ui/{if => fmt}/ifmt-unimpl.rs | 0 src/test/ui/{if => fmt}/ifmt-unimpl.stderr | 0 src/test/ui/{if => fmt}/ifmt-unknown-trait.rs | 0 .../ui/{if => fmt}/ifmt-unknown-trait.stderr | 0 src/test/ui/fn/fn-recover-return-sign.fixed | 28 + src/test/ui/fn/fn-recover-return-sign.rs | 28 + src/test/ui/fn/fn-recover-return-sign.stderr | 26 + src/test/ui/fn/fn-recover-return-sign2.rs | 8 + src/test/ui/fn/fn-recover-return-sign2.stderr | 14 + src/test/ui/foreign/foreign-pub-super.rs | 12 + src/test/ui/generator/auto-trait-regions.rs | 2 +- .../print/generator-print-verbose-2.stderr | 4 +- .../ui/generator/yielding-in-match-guards.rs | 11 + .../generic-associated-types/issue-74824.rs | 27 + .../issue-74824.stderr | 27 + .../parse/trait-path-expected-token.rs | 11 + .../parse/trait-path-expected-token.stderr | 17 + .../parse/trait-path-expressions.rs | 23 + .../parse/trait-path-expressions.stderr | 25 + .../parse/trait-path-missing-gen_arg.rs | 21 + .../parse/trait-path-missing-gen_arg.stderr | 50 + .../parse/trait-path-segments.rs | 35 + .../parse/trait-path-segments.stderr | 31 + .../trait-path-type-error-once-implemented.rs | 10 + ...it-path-type-error-once-implemented.stderr | 8 + .../parse/trait-path-types.rs | 23 + .../parse/trait-path-types.stderr | 29 + .../parse/trait-path-unimplemented.rs | 17 + .../parse/trait-path-unimplemented.stderr | 14 + .../generic-associated-types/shadowing.stderr | 4 +- ...eric-impl-more-params-with-defaults.stderr | 4 +- ...eric-type-more-params-with-defaults.stderr | 4 +- .../half-open-range-pats-exhaustive-fail.rs | 64 +- ...alf-open-range-pats-exhaustive-fail.stderr | 24 +- .../half-open-range-pats-exhaustive-pass.rs | 20 +- .../half-open-range-pats-semantics.rs | 82 +- .../half-open-range-pats-thir-lower-empty.rs | 24 +- ...lf-open-range-pats-thir-lower-empty.stderr | 96 +- .../ui/hashmap/hashmap-capacity-overflow.rs | 1 - src/test/ui/hidden-rt-injection.rs | 8 - src/test/ui/hidden-rt-injection.stderr | 9 - src/test/ui/hidden-rt-injection2.rs | 8 - src/test/ui/hidden-rt-injection2.stderr | 9 - src/test/ui/huge-array-simple-32.stderr | 2 +- src/test/ui/huge-array-simple-64.stderr | 2 +- src/test/ui/huge-array.rs | 2 +- src/test/ui/huge-array.stderr | 2 +- src/test/ui/huge-enum.rs | 2 +- src/test/ui/huge-enum.stderr | 2 +- src/test/ui/huge-struct.rs | 2 +- src/test/ui/huge-struct.stderr | 2 +- .../ui/hygiene/hygienic-labels-in-let.stderr | 56 +- src/test/ui/hygiene/hygienic-labels.stderr | 56 +- src/test/ui/hygiene/no_implicit_prelude.rs | 4 +- .../ui/hygiene/no_implicit_prelude.stderr | 13 +- src/test/ui/hygiene/panic-location.run.stderr | 2 +- src/test/ui/impl-trait/issues/issue-78721.rs | 15 + .../ui/impl-trait/issues/issue-78721.stderr | 27 + src/test/ui/impl-trait/issues/issue-78722.rs | 21 + .../ui/impl-trait/issues/issue-78722.stderr | 27 + src/test/ui/import.rs | 17 - src/test/ui/import2.rs | 10 - src/test/ui/import3.rs | 4 - src/test/ui/import4.rs | 7 - .../auxiliary/issue-36881-aux.rs | 0 .../auxiliary/issue-52891.rs | 0 .../auxiliary/issue-59764.rs | 0 src/test/ui/{ => imports}/double-import.rs | 0 .../ui/{ => imports}/double-import.stderr | 0 .../export-glob-imports-target.rs | 0 src/test/ui/{ => imports}/glob-resolve1.rs | 0 .../ui/{ => imports}/glob-resolve1.stderr | 0 src/test/ui/imports/import-rpass.rs | 12 + src/test/ui/imports/import.rs | 23 +- src/test/ui/{ => imports}/import.stderr | 0 src/test/ui/imports/import2-rpass.rs | 9 + src/test/ui/imports/import2.rs | 13 +- src/test/ui/{ => imports}/import2.stderr | 0 src/test/ui/imports/import3-rpass.rs | 13 + src/test/ui/imports/import3.rs | 15 +- src/test/ui/{ => imports}/import3.stderr | 0 src/test/ui/imports/import4-rpass.rs | 9 + src/test/ui/imports/import4.rs | 10 +- src/test/ui/{ => imports}/import4.stderr | 0 .../ui/{issues => imports}/issue-13404.rs | 0 .../ui/{issues => imports}/issue-13404.stderr | 0 src/test/ui/{issues => imports}/issue-1697.rs | 0 .../ui/{issues => imports}/issue-1697.stderr | 0 .../ui/{issues => imports}/issue-18083.rs | 0 .../ui/{issues => imports}/issue-19498.rs | 0 .../ui/{issues => imports}/issue-19498.stderr | 0 .../ui/{issues => imports}/issue-24081.rs | 0 .../ui/{issues => imports}/issue-24081.stderr | 0 .../ui/{issues => imports}/issue-25396.rs | 0 .../ui/{issues => imports}/issue-25396.stderr | 0 .../ui/{issues => imports}/issue-26886.rs | 0 .../ui/{issues => imports}/issue-26886.stderr | 0 .../ui/{issues => imports}/issue-28134.rs | 1 + .../ui/{issues => imports}/issue-28134.stderr | 2 +- .../ui/{issues => imports}/issue-28388-1.rs | 0 .../{issues => imports}/issue-28388-1.stderr | 0 .../ui/{issues => imports}/issue-28388-2.rs | 0 .../{issues => imports}/issue-28388-2.stderr | 0 src/test/ui/{issues => imports}/issue-2937.rs | 0 .../ui/{issues => imports}/issue-2937.stderr | 0 .../ui/{issues => imports}/issue-30560.rs | 0 .../ui/{issues => imports}/issue-30560.stderr | 0 .../ui/{issues => imports}/issue-31212.rs | 0 .../ui/{issues => imports}/issue-31212.stderr | 0 .../issue-32354-suggest-import-rename.fixed | 0 .../issue-32354-suggest-import-rename.rs | 0 .../issue-32354-suggest-import-rename.stderr | 0 .../ui/{issues => imports}/issue-32833.rs | 0 .../ui/{issues => imports}/issue-32833.stderr | 0 .../ui/{issues => imports}/issue-33464.rs | 0 .../ui/{issues => imports}/issue-33464.stderr | 0 .../ui/{issues => imports}/issue-36881.rs | 0 .../ui/{issues => imports}/issue-36881.stderr | 0 .../ui/{issues => imports}/issue-37887.rs | 0 .../ui/{issues => imports}/issue-37887.stderr | 0 .../ui/{issues => imports}/issue-38293.rs | 0 .../ui/{issues => imports}/issue-38293.stderr | 0 .../ui/{issues => imports}/issue-4366-2.rs | 0 .../{issues => imports}/issue-4366-2.stderr | 0 src/test/ui/{issues => imports}/issue-4366.rs | 0 .../ui/{issues => imports}/issue-4366.stderr | 0 ...n-crate-rename-suggestion-formatting.fixed | 0 ...tern-crate-rename-suggestion-formatting.rs | 0 ...-crate-rename-suggestion-formatting.stderr | 0 .../issue-45829/auxiliary/issue-45829-a.rs | 0 .../issue-45829/auxiliary/issue-45829-b.rs | 0 .../issue-45829/import-self.rs | 0 .../issue-45829/import-self.stderr | 0 .../issue-45829/import-twice.rs | 0 .../issue-45829/import-twice.stderr | 0 .../issue-45829/issue-45829.rs | 0 .../issue-45829/issue-45829.stderr | 0 .../issue-45829/rename-extern-vs-use.rs | 0 .../issue-45829/rename-extern-vs-use.stderr | 0 .../issue-45829/rename-extern-with-tab.rs | 0 .../issue-45829/rename-extern-with-tab.stderr | 0 .../issue-45829/rename-extern.rs | 0 .../issue-45829/rename-extern.stderr | 0 .../issue-45829/rename-use-vs-extern.rs | 0 .../issue-45829/rename-use-vs-extern.stderr | 0 .../issue-45829/rename-use-with-tabs.rs | 0 .../issue-45829/rename-use-with-tabs.stderr | 0 .../issue-45829/rename-with-path.rs | 0 .../issue-45829/rename-with-path.stderr | 0 .../{issues => imports}/issue-45829/rename.rs | 0 .../issue-45829/rename.stderr | 0 .../ui/{issues => imports}/issue-47623.rs | 0 .../ui/{issues => imports}/issue-47623.stderr | 0 .../ui/{issues => imports}/issue-4865-1.rs | 0 .../ui/{issues => imports}/issue-4865-2.rs | 0 .../ui/{issues => imports}/issue-4865-3.rs | 0 .../ui/{issues => imports}/issue-52891.fixed | 0 .../ui/{issues => imports}/issue-52891.rs | 0 .../ui/{issues => imports}/issue-52891.stderr | 0 .../ui/{issues => imports}/issue-53565.rs | 0 .../ui/{issues => imports}/issue-53565.stderr | 0 .../ui/{issues => imports}/issue-59764.rs | 0 .../ui/{issues => imports}/issue-59764.stderr | 0 src/test/ui/{issues => imports}/issue-8208.rs | 0 .../ui/{issues => imports}/issue-8208.stderr | 0 src/test/ui/{issues => imports}/issue-8640.rs | 0 .../ui/{issues => imports}/issue-8640.stderr | 0 .../{ => imports}/resolve_self_super_hint.rs | 0 .../resolve_self_super_hint.stderr | 0 src/test/ui/in-band-lifetimes/shadow.stderr | 4 +- .../infinite/infinite-recursion-const-fn.rs | 3 +- .../infinite-recursion-const-fn.stderr | 156 +- src/test/ui/infinite/infinite-struct.rs | 10 + src/test/ui/infinite/infinite-struct.stderr | 27 + .../auxiliary/repeat.rs | 54 + .../no-overlap.rs | 34 + .../inherent-impls-overlap-check/overlap.rs | 71 + .../overlap.stderr | 47 + src/test/ui/intrinsics/intrinsic-alignment.rs | 1 - ...lid-rustc_args_required_const-arguments.rs | 6 + ...rustc_args_required_const-arguments.stderr | 14 +- src/test/ui/issues/issue-10626.rs | 1 - src/test/ui/issues/issue-10767.rs | 2 +- src/test/ui/issues/issue-12133-3.rs | 1 - src/test/ui/issues/issue-13304.rs | 1 - src/test/ui/issues/issue-14456.rs | 1 - src/test/ui/issues/issue-14940.rs | 1 - src/test/ui/issues/issue-15129.rs | 17 - src/test/ui/issues/issue-15919-32.stderr | 2 +- src/test/ui/issues/issue-15919-64.stderr | 2 +- src/test/ui/issues/issue-16272.rs | 1 - src/test/ui/issues/issue-17121.rs | 1 - src/test/ui/issues/issue-17913.stderr | 2 +- src/test/ui/issues/issue-18400.stderr | 128 +- src/test/ui/issues/issue-20091.rs | 1 - src/test/ui/issues/issue-20413.rs | 28 + src/test/ui/issues/issue-20413.stderr | 316 +- src/test/ui/issues/issue-20427.rs | 1 + src/test/ui/issues/issue-20433.stderr | 2 +- src/test/ui/issues/issue-20616-2.rs | 2 +- src/test/ui/issues/issue-20616-2.stderr | 4 +- src/test/ui/issues/issue-20616-3.rs | 2 +- src/test/ui/issues/issue-20616-3.stderr | 4 +- src/test/ui/issues/issue-20616-4.rs | 2 +- src/test/ui/issues/issue-20616-4.stderr | 4 +- src/test/ui/issues/issue-20616-5.rs | 2 +- src/test/ui/issues/issue-20616-5.stderr | 4 +- src/test/ui/issues/issue-20616-6.rs | 2 +- src/test/ui/issues/issue-20616-6.stderr | 4 +- src/test/ui/issues/issue-20616-7.rs | 2 +- src/test/ui/issues/issue-20616-7.stderr | 4 +- src/test/ui/issues/issue-20644.rs | 1 - src/test/ui/issues/issue-2074.rs | 4 +- src/test/ui/issues/issue-20797.rs | 1 - src/test/ui/issues/issue-2111.rs | 12 - src/test/ui/issues/issue-21475.rs | 2 +- src/test/ui/issues/issue-2214.rs | 2 +- src/test/ui/issues/issue-22577.rs | 1 - src/test/ui/issues/issue-23036.rs | 1 - src/test/ui/issues/issue-23122-2.stderr | 3 +- src/test/ui/issues/issue-23649-2.rs | 1 - src/test/ui/issues/issue-23833.rs | 2 - src/test/ui/issues/issue-24313.rs | 1 - src/test/ui/issues/issue-26251.rs | 2 +- src/test/ui/issues/issue-27859.rs | 1 - src/test/ui/issues/issue-29516.rs | 2 +- src/test/ui/issues/issue-30490.rs | 1 - src/test/ui/issues/issue-31173.stderr | 6 +- src/test/ui/issues/issue-33770.rs | 1 - src/test/ui/issues/issue-34334.rs | 2 +- src/test/ui/issues/issue-34334.stderr | 6 +- src/test/ui/issues/issue-37665.rs | 1 - src/test/ui/issues/issue-37665.stderr | 2 +- src/test/ui/issues/issue-37686.rs | 2 +- src/test/ui/issues/issue-39175.rs | 1 - src/test/ui/issues/issue-39175.stderr | 2 +- src/test/ui/issues/issue-39559-2.rs | 2 - src/test/ui/issues/issue-39559-2.stderr | 19 +- src/test/ui/issues/issue-40000.nll.stderr | 8 +- src/test/ui/issues/issue-40845.stderr | 12 +- src/test/ui/issues/issue-41880.rs | 2 +- src/test/ui/issues/issue-41974.stderr | 2 +- src/test/ui/issues/issue-43105.rs | 1 - src/test/ui/issues/issue-43105.stderr | 16 +- src/test/ui/issues/issue-4541.rs | 1 - src/test/ui/issues/issue-4542.rs | 1 - src/test/ui/issues/issue-48006.rs | 4 +- src/test/ui/issues/issue-49934-errors.rs | 2 - src/test/ui/issues/issue-49934-errors.stderr | 16 +- src/test/ui/issues/issue-49955-2.rs | 19 - src/test/ui/issues/issue-50811.rs | 9 +- .../issue-52023-array-size-pointer-cast.rs | 1 - ...issue-52023-array-size-pointer-cast.stderr | 11 +- src/test/ui/issues/issue-52060.rs | 1 - src/test/ui/issues/issue-52060.stderr | 11 +- src/test/ui/issues/issue-56762.rs | 4 +- src/test/ui/issues/issue-56762.stderr | 4 +- .../ui/issues/issue-68010-large-zst-consts.rs | 2 +- src/test/ui/issues/issue-6804.rs | 2 +- src/test/ui/issues/issue-73899.rs | 21 + src/test/ui/issues/issue-75763.rs | 3 +- src/test/ui/issues/issue-76042.rs | 16 + src/test/ui/issues/issue-77919.rs | 4 +- src/test/ui/issues/issue-77919.stderr | 18 +- src/test/ui/issues/issue-78720.rs | 19 + src/test/ui/issues/issue-78720.stderr | 55 + src/test/ui/issues/issue-78957.rs | 30 + src/test/ui/issues/issue-78957.stderr | 69 + src/test/ui/issues/issue-79593.rs | 29 + src/test/ui/issues/issue-79593.stderr | 33 + .../ui/issues/issue-8460-const.noopt.stderr | 48 +- .../ui/issues/issue-8460-const.opt.stderr | 48 +- ...8460-const.opt_with_overflow_checks.stderr | 48 +- src/test/ui/issues/issue-8460-const.rs | 1 - .../ui/iterators/iter-count-overflow-debug.rs | 5 +- .../iterators/iter-count-overflow-ndebug.rs | 7 +- .../iterators/iter-position-overflow-debug.rs | 5 +- .../iter-position-overflow-ndebug.rs | 7 +- src/test/ui/kinds-of-primitive-impl.rs | 23 + src/test/ui/kinds-of-primitive-impl.stderr | 40 + src/test/ui/label/label_misspelled.rs | 18 + src/test/ui/label/label_misspelled.stderr | 47 + src/test/ui/layout/big-type-no-err.rs | 13 + src/test/ui/lint/dead-code/type-in-foreign.rs | 19 + src/test/ui/lint/expansion-time.rs | 10 + src/test/ui/lint/expansion-time.stderr | 2 +- src/test/ui/lint/forbid-error-capped.rs | 15 + src/test/ui/lint/forbid-group-group-1.rs | 13 + src/test/ui/lint/forbid-group-group-1.stderr | 15 + src/test/ui/lint/forbid-group-group-2.rs | 26 + src/test/ui/lint/forbid-group-group-2.stderr | 115 + src/test/ui/lint/forbid-group-member.rs | 19 + src/test/ui/lint/forbid-group-member.stderr | 51 + src/test/ui/lint/forbid-member-group.rs | 12 + src/test/ui/lint/forbid-member-group.stderr | 30 + .../inline-trait-and-foreign-items.stderr | 32 +- .../issue-69485-var-size-diffs-too-large.rs | 2 +- ...ssue-69485-var-size-diffs-too-large.stderr | 2 +- ...0819-dont-override-forbid-in-same-scope.rs | 52 + ...-dont-override-forbid-in-same-scope.stderr | 29 + src/test/ui/lint/issue-80988.rs | 16 + src/test/ui/lint/issue-80988.stderr | 51 + src/test/ui/lint/issue-81218.rs | 14 + src/test/ui/lint/lint-const-item-mutation.rs | 8 + .../ui/lint/lint-const-item-mutation.stderr | 16 +- src/test/ui/lint/lint-forbid-attr.rs | 6 +- src/test/ui/lint/lint-forbid-attr.stderr | 6 +- src/test/ui/lint/lint-forbid-cmdline.rs | 6 +- src/test/ui/lint/lint-forbid-cmdline.stderr | 6 +- src/test/ui/lint/outer-forbid.rs | 27 +- src/test/ui/lint/outer-forbid.stderr | 75 +- src/test/ui/lint/reasons-forbidden.rs | 37 +- src/test/ui/lint/reasons-forbidden.stderr | 66 +- .../redundant-semicolon/item-stmt-semi.rs | 10 + src/test/ui/lint/special-upper-lower-cases.rs | 24 + .../ui/lint/special-upper-lower-cases.stderr | 32 + src/test/ui/lint/unused_labels.stderr | 2 +- src/test/ui/lint/use_suggestion_json.rs | 1 - src/test/ui/lint/use_suggestion_json.stderr | 106 +- ...warn-unused-inline-on-fn-prototypes.stderr | 4 +- src/test/ui/loops/loop-break-value.rs | 6 + src/test/ui/loops/loop-break-value.stderr | 24 +- .../loops-reject-duplicate-labels-2.stderr | 16 +- .../loops-reject-duplicate-labels.stderr | 16 +- ...s-reject-labels-shadowing-lifetimes.stderr | 24 +- ...ops-reject-lifetime-shadowing-label.stderr | 2 +- src/test/ui/macros/issue-78333.rs | 13 + src/test/ui/macros/macro-2.rs | 2 +- src/test/ui/macros/macro-attribute.rs | 2 +- src/test/ui/macros/macro-attribute.stderr | 4 +- .../ui/macros/macro-comma-behavior-rpass.rs | 1 + src/test/ui/macros/macro-first-set.rs | 2 +- .../macro-lifetime-used-with-labels.stderr | 2 +- src/test/ui/macros/macro-pat-follow-2018.rs | 15 + src/test/ui/macros/macro-pat-follow.rs | 16 +- src/test/ui/macros/macro-path.rs | 2 +- .../issue-69341-malformed-derive-inert.rs | 1 - .../issue-69341-malformed-derive-inert.stderr | 10 +- .../ui/malformed/malformed-interpolated.rs | 7 +- .../malformed/malformed-interpolated.stderr | 24 +- src/test/ui/match/issue-72680.rs | 65 + src/test/ui/mir/auxiliary/issue_76375_aux.rs | 10 +- src/test/ui/mir/issue-76375.rs | 16 +- src/test/ui/mir/issue-77911.rs | 1 - src/test/ui/mir/issue-78496.rs | 16 + src/test/ui/mir/issue-80949.rs | 34 + .../array-clone-with-generic-size.rs | 13 + src/test/ui/mir/mir_dynamic_drops_1.rs | 1 - src/test/ui/mir/mir_dynamic_drops_2.rs | 1 - src/test/ui/mir/mir_dynamic_drops_3.rs | 1 - .../ui/mismatched_types/issue-36053-2.stderr | 2 +- .../ui/mismatched_types/recovered-block.rs | 2 - .../mismatched_types/recovered-block.stderr | 4 +- .../ui/{issues => modules}/issue-56411-aux.rs | 0 .../ui/{issues => modules}/issue-56411.rs | 0 .../ui/{issues => modules}/issue-56411.stderr | 0 ...type-move-out-of-closure-env-issue-1965.rs | 2 - ...-move-out-of-closure-env-issue-1965.stderr | 2 +- src/test/ui/multi-panic.rs | 1 - src/test/ui/never_type/auto-traits.rs | 2 +- src/test/ui/never_type/issue-13352.rs | 2 - src/test/ui/never_type/issue-13352.stderr | 2 +- .../escape-argument-callee.stderr | 2 +- .../escape-argument.stderr | 2 +- ...pagate-approximated-fail-no-postdom.stderr | 2 +- .../propagate-approximated-ref.stderr | 2 +- ...er-to-static-comparing-against-free.stderr | 4 +- ...oximated-shorter-to-static-no-bound.stderr | 2 +- ...mated-shorter-to-static-wrong-bound.stderr | 2 +- .../propagate-approximated-val.stderr | 2 +- .../propagate-despite-same-free-region.stderr | 2 +- ...ail-to-approximate-longer-no-bounds.stderr | 2 +- ...-to-approximate-longer-wrong-bounds.stderr | 2 +- .../return-wrong-bound-region.stderr | 2 +- src/test/ui/nll/closures-in-loops.stderr | 2 +- .../nll/issue-62007-assign-const-index.stderr | 4 +- ...issue-62007-assign-differing-fields.stderr | 4 +- .../assignment-to-differing-field.stderr | 8 +- ...ram-closure-approximate-lower-bound.stderr | 4 +- src/test/ui/no-std-macros.rs | 13 + src/test/ui/no-stdio.rs | 1 - .../float-int-invalid-const-cast.rs | 2 - src/test/ui/numbers-arithmetic/float-nan.rs | 1 - .../ui/numbers-arithmetic/num-wrapping.rs | 3 +- .../ui/numbers-arithmetic/overflowing-neg.rs | 2 +- .../saturating-float-casts-impl.rs | 4 - .../ui/numbers-arithmetic/shift-near-oflo.rs | 20 +- src/test/ui/numbers-arithmetic/u128-as-f32.rs | 2 - src/test/ui/offset_from.rs | 13 - .../old-suffixes-are-really-forbidden.stderr | 8 +- src/test/ui/option-ext.rs | 10 - .../exhaustiveness-unreachable-pattern.rs | 29 + .../exhaustiveness-unreachable-pattern.stderr | 22 +- .../or-patterns-syntactic-fail-2018.rs | 15 + .../or-patterns-syntactic-fail-2018.stderr | 20 + .../or-patterns/or-patterns-syntactic-fail.rs | 10 - .../or-patterns-syntactic-fail.stderr | 48 +- .../or-patterns-syntactic-pass-2021.rs | 14 + src/test/ui/out-of-stack.rs | 1 - src/test/ui/overloaded-calls-nontuple.rs | 2 + src/test/ui/overloaded-calls-nontuple.stderr | 16 +- src/test/ui/panic-brace.rs | 31 + src/test/ui/panic-brace.stderr | 107 + .../abort-link-to-unwind-dylib.rs | 1 - .../abort-link-to-unwinding-crates.rs | 1 - src/test/ui/panic-runtime/abort.rs | 1 - src/test/ui/panic-runtime/lto-abort.rs | 1 - src/test/ui/panic-runtime/lto-unwind.rs | 1 - src/test/ui/panic-while-printing.rs | 22 +- src/test/ui/panics/abort-on-panic.rs | 1 - .../ui/panics/issue-47429-short-backtraces.rs | 1 - .../issue-47429-short-backtraces.run.stderr | 2 +- src/test/ui/parser/attr-bad-meta-2.rs | 2 +- src/test/ui/parser/attr-bad-meta-2.stderr | 4 +- src/test/ui/parser/bad-lit-suffixes.rs | 4 +- src/test/ui/parser/bad-lit-suffixes.stderr | 8 +- .../ui/parser/default-unmatched-assoc.stderr | 4 +- src/test/ui/parser/fn-colon-return-type.rs | 3 +- .../ui/parser/fn-colon-return-type.stderr | 4 +- .../ui/parser/fn-header-semantic-fail.stderr | 45 +- ...correct-move-async-order-issue-79694.fixed | 8 + .../incorrect-move-async-order-issue-79694.rs | 8 + ...orrect-move-async-order-issue-79694.stderr | 13 + src/test/ui/parser/issue-14303-fncall.stderr | 2 - src/test/ui/parser/issue-14303-path.stderr | 2 - src/test/ui/parser/issue-62660.rs | 2 +- src/test/ui/parser/issue-62660.stderr | 4 +- src/test/ui/parser/issue-63116.stderr | 2 +- ...sue-65122-mac-invoc-in-mut-patterns.stderr | 8 +- src/test/ui/parser/lifetime-semicolon.rs | 2 +- src/test/ui/parser/lifetime-semicolon.stderr | 4 +- src/test/ui/parser/no-binary-float-literal.rs | 2 +- .../ui/parser/no-binary-float-literal.stderr | 4 +- .../parser/no-const-fn-in-extern-block.stderr | 18 +- src/test/ui/parser/not-a-pred.rs | 13 +- src/test/ui/parser/not-a-pred.stderr | 32 +- .../parser/removed-syntax-closure-lifetime.rs | 2 +- .../removed-syntax-closure-lifetime.stderr | 4 +- .../ui/parser/removed-syntax-uniq-mut-ty.rs | 2 +- .../parser/removed-syntax-uniq-mut-ty.stderr | 4 +- ...ait-item-with-defaultness-fail-semantic.rs | 12 +- ...item-with-defaultness-fail-semantic.stderr | 12 +- src/test/ui/parser/trait-object-bad-parens.rs | 2 +- src/test/ui/paths-containing-nul.rs | 1 - ...er-binding.rs => integer-range-binding.rs} | 0 ...issue-80186-mut-binding-help-suggestion.rs | 9 + ...e-80186-mut-binding-help-suggestion.stderr | 10 + src/test/ui/pattern/or-pattern-macro-pat.rs | 44 + .../ui/pattern/usefulness/auxiliary/empty.rs | 2 + .../pattern/{ => usefulness}/const-pat-ice.rs | 0 .../ui/pattern/usefulness/consts-opaque.rs | 39 +- .../pattern/usefulness/consts-opaque.stderr | 60 +- .../deny-irrefutable-let-patterns.rs | 0 .../deny-irrefutable-let-patterns.stderr | 0 .../usefulness/exhaustive_integer_patterns.rs | 172 - .../exhaustive_integer_patterns.stderr | 146 - ...austive-float-range-match.rs => floats.rs} | 6 + ...float-range-match.stderr => floats.stderr} | 16 +- .../usefulness/guards-not-exhaustive.rs | 18 - src/test/ui/pattern/usefulness/guards.rs | 22 + src/test/ui/pattern/usefulness/guards.stderr | 12 + .../integer-ranges/exhaustiveness.rs | 102 + .../integer-ranges/exhaustiveness.stderr | 111 + .../overlapping_range_endpoints.rs | 59 + .../overlapping_range_endpoints.stderr | 89 + .../integer-ranges/pointer-sized-int-allow.rs | 38 + .../pointer-sized-int-allow.stderr | 12 + .../integer-ranges/pointer-sized-int-deny.rs | 48 + .../pointer-sized-int-deny.stderr | 129 + .../precise_pointer_matching-message.rs} | 15 +- .../precise_pointer_matching-message.stderr} | 15 +- .../usefulness/integer-ranges/reachability.rs | 113 + .../integer-ranges/reachability.stderr | 152 + .../irrefutable-let-patterns.rs | 0 .../usefulness}/issue-12116.rs | 0 .../usefulness}/issue-12116.stderr | 0 .../usefulness}/issue-12369.rs | 0 .../usefulness}/issue-12369.stderr | 0 .../usefulness}/issue-13727.rs | 0 .../usefulness}/issue-13727.stderr | 0 src/test/ui/pattern/usefulness/issue-15129.rs | 17 + .../usefulness}/issue-15129.stderr | 4 +- src/test/ui/pattern/usefulness/issue-2111.rs | 11 + .../usefulness}/issue-2111.stderr | 8 +- .../usefulness}/issue-30240-b.rs | 0 .../usefulness}/issue-30240-b.stderr | 0 .../usefulness}/issue-30240-rpass.rs | 0 .../usefulness}/issue-30240.rs | 0 .../usefulness}/issue-30240.stderr | 0 .../usefulness}/issue-3096-1.rs | 0 .../usefulness}/issue-3096-1.stderr | 0 .../usefulness}/issue-3096-2.rs | 0 .../usefulness}/issue-3096-2.stderr | 0 .../usefulness}/issue-31221.rs | 0 .../usefulness}/issue-31221.stderr | 0 .../usefulness}/issue-31561.rs | 0 .../usefulness}/issue-31561.stderr | 0 .../usefulness}/issue-3601.rs | 0 .../usefulness}/issue-3601.stderr | 0 .../usefulness}/issue-39362.rs | 0 .../usefulness}/issue-39362.stderr | 0 .../usefulness}/issue-40221.rs | 0 .../usefulness}/issue-40221.stderr | 0 .../usefulness}/issue-4321.rs | 0 .../usefulness}/issue-4321.stderr | 0 src/test/ui/pattern/usefulness/issue-43253.rs | 47 - .../ui/pattern/usefulness/issue-43253.stderr | 52 - .../usefulness}/issue-50900.rs | 0 .../usefulness}/issue-50900.stderr | 0 src/test/ui/pattern/usefulness/issue-56379.rs | 14 + .../ui/pattern/usefulness/issue-56379.stderr | 22 + .../usefulness}/issue-57472.rs | 0 .../usefulness}/issue-57472.stderr | 0 .../pattern/{ => usefulness}/issue-66501.rs | 0 .../match-empty-exhaustive_patterns.rs | 33 +- .../match-empty-exhaustive_patterns.stderr | 64 +- src/test/ui/pattern/usefulness/match-empty.rs | 40 +- .../ui/pattern/usefulness/match-empty.stderr | 78 +- .../usefulness/match-range-fail-dominate.rs | 49 - .../match-range-fail-dominate.stderr | 93 - .../usefulness/non-exhaustive-match.rs | 2 +- .../usefulness/non-exhaustive-match.stderr | 4 +- .../type_polymorphic_byte_str_literals.rs | 0 .../type_polymorphic_byte_str_literals.stderr | 0 ...phantom-oibit.rs => phantom-auto-trait.rs} | 6 +- ...oibit.stderr => phantom-auto-trait.stderr} | 4 +- src/test/ui/precise_pointer_size_matching.rs | 33 - .../ui/precise_pointer_size_matching.stderr | 21 - src/test/ui/print-fuel/print-fuel.rs | 4 +- src/test/ui/print-stdout-eprint-stderr.rs | 1 - src/test/ui/print_type_sizes/niche-filling.rs | 16 +- .../ui/print_type_sizes/niche-filling.stdout | 6 + src/test/ui/privacy/privacy-ns1.rs | 4 +- src/test/ui/privacy/privacy-ns1.stderr | 16 +- src/test/ui/privacy/privacy-ns2.rs | 6 +- src/test/ui/privacy/privacy-ns2.stderr | 42 +- .../private-in-public-non-principal-2.rs | 2 +- .../private-in-public-non-principal.rs | 2 +- .../ui/proc-macro/allowed-attr-stmt-expr.rs | 78 + .../proc-macro/allowed-attr-stmt-expr.stdout | 321 + .../ui/proc-macro/ambiguous-builtin-attrs.rs | 4 +- .../proc-macro/ambiguous-builtin-attrs.stderr | 14 +- src/test/ui/proc-macro/attr-stmt-expr.rs | 49 +- src/test/ui/proc-macro/attr-stmt-expr.stderr | 8 +- src/test/ui/proc-macro/attr-stmt-expr.stdout | 274 + .../ui/proc-macro/auxiliary/attr-stmt-expr.rs | 8 +- .../ui/proc-macro/auxiliary/issue-66286.rs | 14 + .../ui/proc-macro/auxiliary/issue-79242.rs | 16 + .../ui/proc-macro/capture-unglued-token.rs | 20 + .../proc-macro/capture-unglued-token.stdout | 28 + src/test/ui/proc-macro/issue-66286.rs | 13 + src/test/ui/proc-macro/issue-66286.stderr | 12 + .../issue-79242-slow-retokenize-check.rs | 34 + src/test/ui/proc-macro/keep-expr-tokens.rs | 9 + .../ui/proc-macro/keep-expr-tokens.stderr | 4 +- .../ui/proc-macro/keep-expr-tokens.stdout | 46 + src/test/ui/proc-macro/proc-macro-gates.rs | 9 +- .../ui/proc-macro/proc-macro-gates.stderr | 24 +- src/test/ui/proc-macro/proc-macro-gates2.rs | 4 +- .../ui/proc-macro/proc-macro-gates2.stderr | 12 +- src/test/ui/process/process-envs.rs | 1 - src/test/ui/process/process-exit.rs | 1 - .../ui/process/process-remove-from-env.rs | 1 - src/test/ui/process/process-sigpipe.rs | 1 - .../ui/process/process-spawn-nonexistent.rs | 1 - .../process-spawn-with-unicode-params.rs | 1 - .../process/process-status-inherits-stdin.rs | 1 - src/test/ui/process/tls-exit-status.rs | 1 - src/test/ui/realloc-16687.rs | 6 +- .../regions-addr-of-upvar-self.nll.stderr | 6 +- .../ui/regions/regions-addr-of-upvar-self.rs | 2 - .../regions/regions-addr-of-upvar-self.stderr | 10 +- src/test/ui/regions/regions-mock-codegen.rs | 10 +- .../auxiliary/extern-prelude-vec.rs | 0 .../{ => resolve}/auxiliary/extern-prelude.rs | 0 .../ui/{ => resolve}/extern-prelude-fail.rs | 0 .../{ => resolve}/extern-prelude-fail.stderr | 0 src/test/ui/{ => resolve}/extern-prelude.rs | 0 .../ui/{issues => resolve}/issue-49074.rs | 0 .../ui/{issues => resolve}/issue-49074.stderr | 0 .../resolve/macro-determinacy-non-module.rs | 7 + .../{ => resolve}/resolve-pseudo-shadowing.rs | 0 src/test/ui/resolve/token-error-correct-3.rs | 2 - .../ui/resolve/token-error-correct-3.stderr | 6 +- .../ui/resolve/use_suggestion_placement.rs | 2 - .../resolve/use_suggestion_placement.stderr | 6 +- src/test/ui/result-opt-conversions.rs | 47 - .../match-forbidden-without-eq.rs | 2 - .../match-forbidden-without-eq.stderr | 6 +- .../enum_same_crate_empty_match.rs | 2 +- .../enum_same_crate_empty_match.stderr | 14 +- .../rfc-2091-track-caller/error-with-naked.rs | 16 +- .../error-with-naked.stderr | 10 +- src/test/ui/rfc-2294-if-let-guard/bindings.rs | 10 + .../ui/rfc-2294-if-let-guard/bindings.stderr | 15 + .../ui/rfc-2294-if-let-guard/feature-gate.rs | 5 +- .../rfc-2294-if-let-guard/feature-gate.stderr | 83 +- src/test/ui/rfc-2294-if-let-guard/run-pass.rs | 34 + src/test/ui/rfc-2294-if-let-guard/typeck.rs | 16 + .../ui/rfc-2294-if-let-guard/typeck.stderr | 21 + src/test/ui/rfc-2294-if-let-guard/warns.rs | 22 + .../ui/rfc-2294-if-let-guard/warns.stderr | 26 + .../param-attrs-allowed.rs | 12 +- .../param-attrs-builtin-attrs.rs | 20 +- .../param-attrs-builtin-attrs.stderr | 60 +- .../proc-macro-cannot-be-used.rs | 58 +- .../proc-macro-cannot-be-used.stderr | 174 +- .../call-generic-method-chain.rs | 27 + .../call-generic-method-dup-bound.rs | 24 + .../call-generic-method-fail.rs | 11 + .../call-generic-method-fail.stderr | 9 + .../call-generic-method-nonconst-opt-out.rs | 24 + .../call-generic-method-nonconst.rs | 26 + .../call-generic-method-pass.rs | 23 + .../const-impl-norecover.rs | 13 + .../const-impl-norecover.stderr | 8 + .../const-impl-recovery.rs | 16 + .../const-impl-recovery.stderr | 24 + src/test/ui/rfcs/rfc-1014.rs | 1 - src/test/ui/running-with-no-runtime.rs | 1 - .../new-llvm-pass-manager-thin-lto.rs | 1 - src/test/ui/shadowed/shadowed-lifetime.stderr | 4 +- src/test/ui/signal-alternate-stack-cleanup.rs | 1 - src/test/ui/signal-exit-status.rs | 1 - src/test/ui/sigpipe-should-be-ignored.rs | 1 - .../ui/simd-type-generic-monomorphisation.rs | 4 +- .../simd-type-generic-monomorphisation.stderr | 2 +- src/test/ui/simd-type.rs | 10 + src/test/ui/simd-type.stderr | 20 +- src/test/ui/simd/simd-array-trait.rs | 41 + src/test/ui/simd/simd-array-trait.stderr | 10 + src/test/ui/simd/simd-array-type.rs | 42 + src/test/ui/simd/simd-generics.rs | 28 +- .../ui/simd/simd-intrinsic-float-minmax.rs | 4 +- ...intrinsic-generic-arithmetic-saturating.rs | 66 +- .../simd/simd-intrinsic-generic-arithmetic.rs | 61 +- .../simd/simd-intrinsic-generic-comparison.rs | 4 +- .../ui/single-primitive-inherent-impl.stderr | 8 +- src/test/ui/span/issue-33884.rs | 2 - src/test/ui/span/issue-33884.stderr | 2 +- src/test/ui/span/issue-36530.rs | 2 +- src/test/ui/span/issue-36530.stderr | 6 +- .../ui/span/issue-43927-non-ADT-derive.rs | 3 - .../ui/span/issue-43927-non-ADT-derive.stderr | 26 +- .../specialization/specialization-polarity.rs | 2 +- src/test/ui/sse2.rs | 1 - .../auxiliary/lint-stability.rs | 0 .../issue-28075.rs | 0 .../issue-28075.stderr | 0 .../issue-28388-3.rs | 0 .../issue-28388-3.stderr | 0 .../stability-attribute-sanity.rs | 6 +- .../stability-attribute-sanity.stderr | 14 +- src/test/ui/std-backtrace.rs | 1 - src/test/ui/stdio-is-blocking.rs | 1 - .../structs-enums/discrim-explicit-23030.rs | 2 - .../structs-enums/nested-enum-same-names.rs | 4 +- src/test/ui/structs-enums/rec-align-u64.rs | 1 - src/test/ui/suffixed-literal-meta.rs | 14 +- src/test/ui/suffixed-literal-meta.stderr | 118 +- ...fn-or-tuple-struct-with-underscore-args.rs | 18 +- ...r-tuple-struct-with-underscore-args.stderr | 89 +- .../impl-trait-with-missing-bounds.rs | 8 + .../impl-trait-with-missing-bounds.stderr | 17 +- ...l-trait-with-missing-bounds-on-async-fn.rs | 32 + ...ait-with-missing-bounds-on-async-fn.stderr | 33 + .../ui/suggestions/suggest-move-types.stderr | 4 - src/test/ui/symbol-names/const-generics.rs | 12 +- src/test/ui/symbol-names/impl1.rs | 2 +- src/test/ui/tcp-stress.rs | 1 - src/test/ui/test-panic-abort-nocapture.rs | 1 + .../ui/test-panic-abort-nocapture.run.stderr | 4 +- .../ui/test-panic-abort-nocapture.run.stdout | 2 +- src/test/ui/test-panic-abort.rs | 1 + src/test/ui/test-panic-abort.run.stdout | 4 +- src/test/ui/test-passed-wasm.rs | 20 + src/test/ui/test-passed-wasm.run.stdout | 7 + src/test/ui/test-passed.rs | 21 + src/test/ui/test-passed.run.stdout | 7 + src/test/ui/test-thread-capture.rs | 1 + src/test/ui/test-thread-capture.run.stdout | 4 +- src/test/ui/test-thread-nocapture.rs | 1 + src/test/ui/test-thread-nocapture.run.stderr | 2 +- src/test/ui/test-thread-nocapture.run.stdout | 2 +- .../ui/threads-sendsync/sync-send-in-std.rs | 1 - src/test/ui/threads-sendsync/task-stderr.rs | 26 +- src/test/ui/traits/issue-79458.rs | 10 + src/test/ui/traits/issue-79458.stderr | 15 + .../explicitly-unimplemented-error-message.rs | 53 + ...licitly-unimplemented-error-message.stderr | 60 + .../ui/traits/trait-object-vs-lifetime.stderr | 2 - ...ductive-overflow-supertrait-auto-trait.rs} | 6 +- ...ive-overflow-supertrait-auto-trait.stderr} | 4 +- src/test/ui/try-is-identifier-edition2015.rs | 2 +- src/test/ui/try-operator-on-main.rs | 2 - src/test/ui/try-operator-on-main.stderr | 8 +- src/test/ui/try-operator.rs | 1 - src/test/ui/try-wait.rs | 1 - src/test/ui/type/ascription/issue-34255-1.rs | 2 +- .../ui/type/ascription/issue-34255-1.stderr | 4 +- .../typeck/auxiliary/tdticc_coherence_lib.rs | 2 +- .../ui/typeck/issue-80207-unsized-return.rs | 20 + src/test/ui/union/union-transmute.rs | 3 - src/test/ui/union/union-unsafe.rs | 27 +- src/test/ui/union/union-unsafe.stderr | 56 +- src/test/ui/unique-object-noncopyable.stderr | 2 +- src/test/ui/unique-pinned-nocopy.stderr | 2 +- src/test/ui/{issues => unused}/issue-30730.rs | 0 .../ui/{issues => unused}/issue-30730.stderr | 0 src/test/ui/{issues => unused}/issue-46576.rs | 2 - .../ui/{issues => unused}/issue-46576.stderr | 4 +- src/test/ui/{issues => unused}/issue-59896.rs | 0 .../ui/{issues => unused}/issue-59896.stderr | 0 src/test/ui/{issues => unused}/issue-70041.rs | 0 .../ui/{issues => unused}/issue-70041.stderr | 0 src/test/ui/use-module-level-int-consts.rs | 1 + src/test/ui/utf8.rs | 50 - src/test/ui/utf8_chars.rs | 31 - src/test/ui/wait-forked-but-failed-child.rs | 1 - src/test/ui/weird-exprs.rs | 7 + src/test/ui/wrapping-int-api.rs | 228 - src/test/ui/x86stdcall.rs | 1 - .../zero-sized/zero-size-type-destructors.rs | 2 +- src/tools/build-manifest/src/main.rs | 3 +- src/tools/cargotest/main.rs | 2 +- src/tools/compiletest/src/common.rs | 12 + src/tools/compiletest/src/header.rs | 2 + src/tools/compiletest/src/json.rs | 11 +- src/tools/compiletest/src/main.rs | 18 +- src/tools/compiletest/src/runtest.rs | 208 +- src/tools/compiletest/src/util.rs | 1 - src/tools/expand-yaml-anchors/src/main.rs | 3 +- src/tools/linkchecker/main.rs | 13 +- src/tools/lint-docs/src/groups.rs | 203 +- src/tools/lint-docs/src/lib.rs | 756 +- src/tools/lint-docs/src/main.rs | 33 +- src/tools/publish_toolstate.py | 2 +- src/tools/rustbook/Cargo.toml | 3 +- src/tools/rustbook/src/main.rs | 1 + src/tools/rustc-workspace-hack/Cargo.toml | 3 + src/tools/rustdoc-js/tester.js | 31 + src/tools/tidy/src/cargo.rs | 9 +- src/tools/tidy/src/deps.rs | 30 +- src/tools/tidy/src/error_codes_check.rs | 101 +- src/tools/tidy/src/extdeps.rs | 5 +- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/lib.rs | 6 + src/tools/tidy/src/main.rs | 5 +- src/tools/tidy/src/style.rs | 1 - src/tools/tidy/src/ui_tests.rs | 63 +- src/tools/tidy/src/unit_tests.rs | 2 - src/tools/x/README.md | 7 + src/version | 2 +- vendor/addr2line/.cargo-checksum.json | 2 +- vendor/addr2line/CHANGELOG.md | 18 + vendor/addr2line/Cargo.lock | 252 +- vendor/addr2line/Cargo.toml | 6 +- vendor/addr2line/examples/addr2line.rs | 2 +- vendor/addr2line/src/lib.rs | 275 +- vendor/addr2line/tests/output_equivalence.rs | 5 +- vendor/cc/.cargo-checksum.json | 2 +- vendor/cc/Cargo.lock | 10 +- vendor/cc/Cargo.toml | 4 +- vendor/cc/src/lib.rs | 74 +- vendor/cfg-if/.cargo-checksum.json | 1 + vendor/cfg-if/Cargo.toml | 36 + .../{object-0.20.0 => cfg-if}/LICENSE-APACHE | 0 vendor/cfg-if/LICENSE-MIT | 25 + vendor/cfg-if/README.md | 47 + vendor/cfg-if/src/lib.rs | 176 + vendor/cfg-if/tests/xcrate.rs | 14 + vendor/crc32fast/.cargo-checksum.json | 2 +- vendor/crc32fast/Cargo.toml | 10 +- vendor/crc32fast/README.md | 2 +- vendor/crc32fast/benches/bench.rs | 2 +- vendor/dlmalloc/.cargo-checksum.json | 2 +- vendor/dlmalloc/Cargo.toml | 3 +- vendor/dlmalloc/src/dlmalloc.rs | 102 +- vendor/dlmalloc/src/dummy.rs | 42 + vendor/dlmalloc/src/global.rs | 34 +- vendor/dlmalloc/src/lib.rs | 107 +- vendor/dlmalloc/src/linux.rs | 104 +- vendor/dlmalloc/src/macos.rs | 86 +- vendor/dlmalloc/src/sgx.rs | 66 - vendor/dlmalloc/src/wasm.rs | 70 +- vendor/dlmalloc/tests/global.rs | 4 +- vendor/gimli/.cargo-checksum.json | 2 +- vendor/gimli/CHANGELOG.md | 36 + vendor/gimli/Cargo.lock | 336 +- vendor/gimli/Cargo.toml | 6 +- vendor/gimli/README.md | 2 +- vendor/gimli/examples/dwarf-validate.rs | 21 +- vendor/gimli/examples/dwarfdump.rs | 58 +- vendor/gimli/examples/simple.rs | 5 +- vendor/gimli/examples/simple_line.rs | 2 +- vendor/gimli/src/arch.rs | 10 + vendor/gimli/src/common.rs | 58 + vendor/gimli/src/read/dwarf.rs | 154 +- vendor/gimli/src/read/lists.rs | 67 + vendor/gimli/src/read/loclists.rs | 323 +- vendor/gimli/src/read/mod.rs | 2 + vendor/gimli/src/read/rnglists.rs | 201 +- vendor/gimli/src/read/str.rs | 27 +- vendor/gimli/src/read/unit.rs | 1659 +- vendor/gimli/src/read/value.rs | 6 +- vendor/gimli/src/write/loc.rs | 5 +- vendor/gimli/src/write/mod.rs | 3 + vendor/gimli/src/write/op.rs | 10 +- vendor/gimli/src/write/range.rs | 5 +- vendor/gimli/src/write/unit.rs | 28 +- vendor/gsgdt/.cargo-checksum.json | 1 + vendor/gsgdt/Cargo.toml | 26 + vendor/gsgdt/LICENSE | 21 + vendor/gsgdt/README.md | 33 + vendor/gsgdt/src/diff/diff.rs | 106 + vendor/gsgdt/src/diff/diff_graph.rs | 57 + vendor/gsgdt/src/diff/match_graph.rs | 184 + vendor/gsgdt/src/diff/mod.rs | 7 + vendor/gsgdt/src/graph.rs | 273 + vendor/gsgdt/src/levenshtein.rs | 70 + vendor/gsgdt/src/lib.rs | 12 + vendor/gsgdt/src/multi_graph.rs | 33 + vendor/gsgdt/src/node.rs | 118 + vendor/gsgdt/src/util.rs | 6 + vendor/gsgdt/tests/graph1.json | 513 + vendor/gsgdt/tests/graph2.json | 297 + vendor/gsgdt/tests/helpers.rs | 14 + vendor/gsgdt/tests/small_graph.json | 36 + vendor/gsgdt/tests/test_diff.rs | 57 + vendor/gsgdt/tests/test_graph.rs | 18 + vendor/gsgdt/tests/test_multigraph.rs | 28 + vendor/libc/.cargo-checksum.json | 2 +- vendor/libc/Cargo.toml | 4 +- vendor/libc/README.md | 6 +- vendor/libc/src/macros.rs | 28 +- .../unix/bsd/freebsdlike/dragonfly/errno.rs | 2 +- .../bsd/freebsdlike/freebsd/freebsd11/mod.rs | 2 + .../bsd/freebsdlike/freebsd/freebsd12/mod.rs | 8 + .../src/unix/bsd/freebsdlike/freebsd/mod.rs | 7 +- .../src/unix/bsd/netbsdlike/netbsd/mod.rs | 12 + .../libc/src/unix/linux_like/android/mod.rs | 58 +- .../src/unix/linux_like/emscripten/mod.rs | 2 + .../src/unix/linux_like/linux/gnu/b32/mod.rs | 156 +- .../linux_like/linux/gnu/b32/sparc/mod.rs | 67 - .../linux_like/linux/gnu/b64/x86_64/mod.rs | 19 + .../libc/src/unix/linux_like/linux/gnu/mod.rs | 4 + vendor/libc/src/unix/linux_like/linux/mod.rs | 32 +- .../src/unix/linux_like/linux/musl/mod.rs | 70 +- vendor/libc/src/unix/linux_like/mod.rs | 1 - vendor/libc/src/unix/mod.rs | 14 +- vendor/libc/src/vxworks/mod.rs | 0 vendor/libc/triagebot.toml | 5 + vendor/mdbook/.cargo-checksum.json | 2 +- vendor/mdbook/CHANGELOG.md | 17 +- vendor/mdbook/Cargo.lock | 2 +- vendor/mdbook/Cargo.toml | 4 +- vendor/mdbook/README.md | 2 +- vendor/mdbook/ci/install-hub.sh | 2 +- vendor/mdbook/ci/make-release.sh | 12 +- vendor/mdbook/src/book/init.rs | 13 +- vendor/mdbook/src/config.rs | 17 + vendor/mdbook/src/preprocess/cmd.rs | 6 +- .../renderer/html_handlebars/hbs_renderer.rs | 23 +- vendor/mdbook/src/theme/index.hbs | 4 + vendor/mdbook/src/theme/searcher/searcher.js | 5 + vendor/mdbook/src/utils/fs.rs | 23 +- vendor/mdbook/tests/dummy_book/mod.rs | 6 +- vendor/mdbook/tests/rendered_output.rs | 2 +- vendor/miow/.cargo-checksum.json | 2 +- vendor/miow/Cargo.toml | 4 +- vendor/miow/LICENSE-APACHE | 402 +- vendor/miow/LICENSE-MIT | 50 +- vendor/miow/README.md | 62 +- vendor/miow/appveyor.yml | 40 +- vendor/miow/src/handle.rs | 354 +- vendor/miow/src/iocp.rs | 656 +- vendor/miow/src/lib.rs | 116 +- vendor/miow/src/net.rs | 2580 +- vendor/miow/src/overlapped.rs | 184 +- vendor/miow/src/pipe.rs | 1568 +- vendor/object-0.20.0/.cargo-checksum.json | 1 - vendor/object-0.20.0/Cargo.lock | 170 - vendor/object-0.20.0/README.md | 5 - vendor/object-0.20.0/src/lib.rs | 49 - vendor/object-0.20.0/src/read/coff/symbol.rs | 250 - vendor/object-0.20.0/src/read/macho/symbol.rs | 235 - vendor/object/.cargo-checksum.json | 1 + vendor/object/Cargo.lock | 144 + vendor/{object-0.20.0 => object}/Cargo.toml | 15 +- vendor/object/LICENSE-APACHE | 201 + vendor/{object-0.20.0 => object}/LICENSE-MIT | 0 vendor/object/README.md | 31 + vendor/object/examples/ar.rs | 47 + .../{object-0.20.0 => object}/examples/nm.rs | 11 +- .../examples/objcopy.rs | 39 +- .../examples/objdump.rs | 14 +- vendor/object/examples/objectmap.rs | 67 + vendor/object/src/archive.rs | 39 + .../{object-0.20.0 => object}/src/common.rs | 45 +- vendor/{object-0.20.0 => object}/src/elf.rs | 16 +- .../{object-0.20.0 => object}/src/endian.rs | 0 vendor/object/src/lib.rs | 71 + vendor/{object-0.20.0 => object}/src/macho.rs | 0 vendor/{object-0.20.0 => object}/src/pe.rs | 22 +- vendor/{object-0.20.0 => object}/src/pod.rs | 55 +- .../{object-0.20.0 => object}/src/read/any.rs | 360 +- vendor/object/src/read/archive.rs | 407 + vendor/object/src/read/coff/comdat.rs | 200 + .../src/read/coff/file.rs | 83 +- .../src/read/coff/mod.rs | 3 + .../src/read/coff/relocation.rs | 0 .../src/read/coff/section.rs | 6 +- vendor/object/src/read/coff/symbol.rs | 451 + vendor/object/src/read/elf/comdat.rs | 147 + .../src/read/elf/compression.rs | 0 .../src/read/elf/file.rs | 75 +- .../src/read/elf/mod.rs | 3 + .../src/read/elf/note.rs | 0 .../src/read/elf/relocation.rs | 41 + .../src/read/elf/section.rs | 3 +- .../src/read/elf/segment.rs | 0 .../src/read/elf/symbol.rs | 287 +- .../src/read/macho/file.rs | 168 +- .../src/read/macho/load_command.rs | 0 .../src/read/macho/mod.rs | 0 .../src/read/macho/relocation.rs | 0 .../src/read/macho/section.rs | 0 .../src/read/macho/segment.rs | 0 vendor/object/src/read/macho/symbol.rs | 424 + .../{object-0.20.0 => object}/src/read/mod.rs | 206 +- .../src/read/pe/file.rs | 153 +- .../src/read/pe/mod.rs | 0 .../src/read/pe/section.rs | 4 +- .../src/read/traits.rs | 184 +- .../src/read/util.rs | 0 .../src/read/wasm.rs | 268 +- .../src/write/coff.rs | 99 +- .../src/write/elf.rs | 222 +- .../src/write/macho.rs | 72 +- .../src/write/mod.rs | 61 +- .../src/write/string.rs | 0 .../src/write/util.rs | 4 +- .../tests/integration.rs | 0 .../tests/parse_self.rs | 0 .../tests/round_trip/bss.rs | 30 +- vendor/object/tests/round_trip/comdat.rs | 225 + .../tests/round_trip/common.rs | 36 +- .../tests/round_trip/elf.rs | 10 +- .../tests/round_trip/mod.rs | 48 +- .../tests/round_trip/tls.rs | 41 +- vendor/serde/.cargo-checksum.json | 2 +- vendor/serde/Cargo.toml | 4 +- vendor/serde/src/de/impls.rs | 15 +- vendor/serde/src/de/value.rs | 2 +- vendor/serde/src/lib.rs | 7 +- vendor/serde/src/ser/impls.rs | 5 +- vendor/serde_derive/.cargo-checksum.json | 2 +- vendor/serde_derive/Cargo.toml | 2 +- vendor/serde_derive/src/de.rs | 3 +- vendor/serde_derive/src/lib.rs | 3 +- vendor/socket2/.cargo-checksum.json | 2 +- vendor/socket2/9f0fbf2.diff | 2623 + vendor/socket2/Cargo.toml | 3 +- vendor/socket2/TODO | 337 + vendor/socket2/TODO.refactor | 7 + vendor/socket2/check_targets.bash | 15 + vendor/socket2/socket_type.diff | 39 + vendor/socket2/src/sockaddr.rs | 169 +- vendor/socket2/src/socket.rs | 16 +- vendor/socket2/src/sys/unix.rs | 5 +- vendor/syn/.cargo-checksum.json | 2 +- vendor/syn/Cargo.toml | 2 +- vendor/syn/src/attr.rs | 4 +- vendor/syn/src/await.rs | 2 +- vendor/syn/src/lib.rs | 2 +- vendor/syn/src/lit.rs | 28 +- vendor/syn/src/token.rs | 200 +- vendor/syn/tests/common/eq.rs | 24 +- vendor/syn/tests/test_lit.rs | 11 +- vendor/syn/tests/test_meta.rs | 37 + version | 2 +- 3324 files changed, 155481 insertions(+), 79568 deletions(-) create mode 100644 compiler/rustc_data_structures/src/functor.rs rename compiler/{rustc_middle/src/ty => rustc_data_structures/src}/steal.rs (82%) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0212.md create mode 100644 compiler/rustc_error_codes/src/error_codes/E0546.md create mode 100644 compiler/rustc_feature/src/tests.rs create mode 100644 compiler/rustc_lint/src/panic_fmt.rs create mode 100644 compiler/rustc_macros/src/symbols/tests.rs create mode 100644 compiler/rustc_mir/src/transform/const_debuginfo.rs create mode 100644 compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml create mode 100644 compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs create mode 100644 compiler/rustc_mir/src/transform/coverage/tests.rs create mode 100644 compiler/rustc_mir/src/transform/lower_intrinsics.rs create mode 100644 compiler/rustc_mir/src/util/generic_graph.rs delete mode 100644 compiler/rustc_mir_build/src/thir/pattern/_match.rs create mode 100644 compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs create mode 100644 compiler/rustc_mir_build/src/thir/pattern/usefulness.rs create mode 100644 compiler/rustc_passes/src/liveness/rwu_table.rs create mode 100644 compiler/rustc_passes/src/naked_functions.rs rename compiler/{rustc_ast/src/util => rustc_span/src}/lev_distance.rs (86%) rename compiler/{rustc_ast/src/util => rustc_span/src}/lev_distance/tests.rs (69%) create mode 100644 compiler/rustc_target/src/asm/wasm.rs create mode 100644 compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs delete mode 100644 compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs create mode 100644 compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs delete mode 100644 compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs delete mode 100644 compiler/rustc_target/src/spec/cloudabi_base.rs delete mode 100644 compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs delete mode 100644 compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs rename compiler/{rustc_ty => rustc_ty_utils}/Cargo.toml (95%) rename compiler/{rustc_ty => rustc_ty_utils}/src/common_traits.rs (100%) rename compiler/{rustc_ty => rustc_ty_utils}/src/instance.rs (98%) rename compiler/{rustc_ty => rustc_ty_utils}/src/lib.rs (100%) rename compiler/{rustc_ty => rustc_ty_utils}/src/needs_drop.rs (94%) rename compiler/{rustc_ty => rustc_ty_utils}/src/ty.rs (99%) create mode 100644 compiler/rustc_type_ir/Cargo.toml create mode 100644 compiler/rustc_type_ir/src/lib.rs create mode 100644 library/alloc/src/collections/btree/map/tests/ord_chaos.rs create mode 100644 library/alloc/src/collections/vec_deque/into_iter.rs create mode 100644 library/alloc/src/collections/vec_deque/iter.rs create mode 100644 library/alloc/src/collections/vec_deque/iter_mut.rs create mode 100644 library/alloc/src/collections/vec_deque/macros.rs rename library/alloc/src/collections/{vec_deque.rs => vec_deque/mod.rs} (86%) create mode 100644 library/alloc/src/collections/vec_deque/pair_slices.rs create mode 100644 library/alloc/src/collections/vec_deque/ring_slices.rs create mode 100644 library/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile create mode 100644 library/core/src/iter/adapters/cloned.rs create mode 100644 library/core/src/iter/adapters/copied.rs create mode 100644 library/core/src/iter/adapters/cycle.rs create mode 100644 library/core/src/iter/adapters/enumerate.rs create mode 100644 library/core/src/iter/adapters/filter.rs create mode 100644 library/core/src/iter/adapters/filter_map.rs create mode 100644 library/core/src/iter/adapters/inspect.rs create mode 100644 library/core/src/iter/adapters/map.rs create mode 100644 library/core/src/iter/adapters/map_while.rs create mode 100644 library/core/src/iter/adapters/peekable.rs create mode 100644 library/core/src/iter/adapters/rev.rs create mode 100644 library/core/src/iter/adapters/scan.rs create mode 100644 library/core/src/iter/adapters/skip.rs create mode 100644 library/core/src/iter/adapters/skip_while.rs create mode 100644 library/core/src/iter/adapters/step_by.rs create mode 100644 library/core/src/iter/adapters/take.rs create mode 100644 library/core/src/iter/adapters/take_while.rs create mode 100644 library/core/src/iter/sources/empty.rs create mode 100644 library/core/src/iter/sources/from_fn.rs create mode 100644 library/core/src/iter/sources/once.rs create mode 100644 library/core/src/iter/sources/once_with.rs create mode 100644 library/core/src/iter/sources/repeat.rs create mode 100644 library/core/src/iter/sources/repeat_with.rs create mode 100644 library/core/src/iter/sources/successors.rs create mode 100644 library/core/tests/macros.rs create mode 100644 library/core/tests/num/i128.rs create mode 100644 library/core/tests/num/u128.rs create mode 100644 library/core/tests/unicode.rs create mode 100644 library/std/src/io/copy.rs delete mode 100644 library/std/src/sys/cloudabi/abi/bitflags.rs delete mode 100644 library/std/src/sys/cloudabi/abi/cloudabi.rs delete mode 100644 library/std/src/sys/cloudabi/abi/mod.rs delete mode 100644 library/std/src/sys/cloudabi/args.rs delete mode 100644 library/std/src/sys/cloudabi/condvar.rs delete mode 100644 library/std/src/sys/cloudabi/io.rs delete mode 100644 library/std/src/sys/cloudabi/mod.rs delete mode 100644 library/std/src/sys/cloudabi/mutex.rs delete mode 100644 library/std/src/sys/cloudabi/os.rs delete mode 100644 library/std/src/sys/cloudabi/rwlock.rs delete mode 100644 library/std/src/sys/cloudabi/shims/args.rs delete mode 100644 library/std/src/sys/cloudabi/shims/env.rs delete mode 100644 library/std/src/sys/cloudabi/shims/fs.rs delete mode 100644 library/std/src/sys/cloudabi/shims/mod.rs delete mode 100644 library/std/src/sys/cloudabi/shims/net.rs delete mode 100644 library/std/src/sys/cloudabi/shims/os.rs delete mode 100644 library/std/src/sys/cloudabi/shims/pipe.rs delete mode 100644 library/std/src/sys/cloudabi/shims/process.rs delete mode 100644 library/std/src/sys/cloudabi/stack_overflow.rs delete mode 100644 library/std/src/sys/cloudabi/stdio.rs delete mode 100644 library/std/src/sys/cloudabi/thread.rs delete mode 100644 library/std/src/sys/cloudabi/time.rs delete mode 100644 library/std/src/sys/unix/ext/net.rs create mode 100644 library/std/src/sys/unix/ext/net/addr.rs create mode 100644 library/std/src/sys/unix/ext/net/ancillary.rs create mode 100644 library/std/src/sys/unix/ext/net/datagram.rs create mode 100644 library/std/src/sys/unix/ext/net/listener.rs create mode 100644 library/std/src/sys/unix/ext/net/mod.rs create mode 100644 library/std/src/sys/unix/ext/net/raw_fd.rs create mode 100644 library/std/src/sys/unix/ext/net/stream.rs create mode 100644 library/std/src/sys/unix/kernel_copy.rs create mode 100644 library/std/src/sys/unix/kernel_copy/tests.rs create mode 100644 library/std/src/sys/windows/thread_parker.rs rename src/test/ui/sleep.rs => library/std/tests/thread.rs (58%) create mode 100644 library/stdarch/crates/core_arch/avx512bw.md rename library/stdarch/crates/core_arch/src/{aarch64 => arm}/crypto.rs (77%) create mode 100644 library/stdarch/crates/core_arch/src/arm/neon/load_tests.rs create mode 100644 library/stdarch/crates/core_arch/src/arm/neon/shift_and_insert_tests.rs create mode 100644 library/stdarch/crates/core_arch/src/x86/avx512bitalg.rs create mode 100644 library/stdarch/crates/core_arch/src/x86/avx512bw.rs create mode 100644 library/stdarch/crates/core_arch/src/x86/avx512cd.rs create mode 100644 library/stdarch/crates/core_arch/src/x86/avx512gfni.rs create mode 100644 library/stdarch/crates/core_arch/src/x86/avx512vaes.rs create mode 100644 library/stdarch/crates/core_arch/src/x86/avx512vpclmulqdq.rs create mode 100644 library/stdarch/crates/core_arch/src/x86/avx512vpopcntdq.rs delete mode 100644 library/test/src/helpers/sink.rs create mode 100644 src/bootstrap/tarball.rs delete mode 100755 src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh rename src/ci/docker/host-x86_64/{x86_64-gnu-llvm-8 => x86_64-gnu-llvm-9}/Dockerfile (63%) create mode 100755 src/ci/pgo.sh create mode 100644 src/doc/book/dot/trpl15-04.dot create mode 100644 src/doc/book/listings/ch14-more-about-cargo/output-only-01-adder-crate/add/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-08-final-code/404.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-08-final-code/Cargo.lock create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-08-final-code/Cargo.toml create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-08-final-code/hello.html create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-08-final-code/src/bin/main.rs create mode 100644 src/doc/book/listings/ch20-web-server/no-listing-08-final-code/src/lib.rs create mode 100644 src/doc/rustc/src/exploit-mitigations.md create mode 100644 src/doc/rustc/src/images/image1.png create mode 100644 src/doc/rustc/src/images/image2.png create mode 100644 src/doc/rustc/src/images/image3.png rename src/doc/unstable-book/src/language-features/{optin-builtin-traits.md => auto-traits.md} (95%) rename src/doc/unstable-book/src/library-features/{libstd-io-internals.md => internal-output-capture.md} (79%) delete mode 100644 src/doc/unstable-book/src/library-features/set-stdio.md create mode 100644 src/librustdoc/json/conversions.rs create mode 100644 src/librustdoc/json/types.rs create mode 100644 src/test/assembly/asm/wasm-types.rs rename src/test/codegen/{return-value-in-reg.rs => arg-return-value-in-reg.rs} (74%) create mode 100644 src/test/codegen/fewer-names.rs create mode 100644 src/test/codegen/inline-hint.rs create mode 100644 src/test/codegen/naked-noinline.rs create mode 100644 src/test/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs create mode 100644 src/test/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs create mode 100644 src/test/codegen/to_vec.rs create mode 100644 src/test/codegen/transmute-scalar.rs create mode 100644 src/test/incremental/auxiliary/issue-79661.rs create mode 100644 src/test/incremental/auxiliary/issue-79890.rs create mode 100644 src/test/incremental/issue-79661-missing-def-path-hash.rs create mode 100644 src/test/incremental/issue-79890-imported-crates-changed.rs create mode 100644 src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff create mode 100644 src/test/mir-opt/const_debuginfo.rs create mode 100644 src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir create mode 100644 src/test/mir-opt/inline/inline-generator.rs create mode 100644 src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff create mode 100644 src/test/mir-opt/inline/inline_generator.main.Inline.diff create mode 100644 src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff create mode 100644 src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir create mode 100644 src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir create mode 100644 src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff create mode 100644 src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff create mode 100644 src/test/mir-opt/lower_intrinsics.rs create mode 100644 src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff create mode 100644 src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff create mode 100644 src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff create mode 100644 src/test/pretty/qpath-associated-type-bound.rs delete mode 100644 src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile rename src/test/run-make-fulldeps/{coverage-llvmir-base => coverage-llvmir}/Makefile (63%) rename src/test/run-make-fulldeps/{coverage-llvmir-base => coverage-llvmir}/filecheck.testprog.txt (91%) rename src/test/run-make-fulldeps/{coverage-llvmir-base => coverage-llvmir}/testprog.rs (100%) delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/Makefile delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loops_branches.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.partial_eq.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.tight_inf_loop.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_ret.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loops_branches.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.partial_eq.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.closure.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.drop_trait.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.generics.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if_else.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.lazy_boolean.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loop_break_value.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loops_branches.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.partial_eq.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_match.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.tight_inf_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-base/prettify_json.py delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.closure.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.drop_trait.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.generics.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if_else.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.lazy_boolean.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loop_break_value.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loops_branches.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.partial_eq.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_loop.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_match.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.tight_inf_loop.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.try_error_result.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while_early_ret.json delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.closure.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.drop_trait.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.generics.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if_else.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.lazy_boolean.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.partial_eq.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.tight_inf_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while_early_ret.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.closure.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.drop_trait.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.generics.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if_else.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.lazy_boolean.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loop_break_value.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loops_branches.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_match.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.tight_inf_loop.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while.txt delete mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/Makefile create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.closure.txt (51%) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.dead_code.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.drop_trait.txt (94%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.generics.txt (69%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.if.txt (71%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.if_else.txt (79%) rename src/test/run-make-fulldeps/{coverage-reports-deadcode => coverage-reports}/expected_show_coverage.inner_items.txt (90%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.lazy_boolean.txt (86%) rename src/test/run-make-fulldeps/{coverage-reports-deadcode => coverage-reports}/expected_show_coverage.loop_break_value.txt (82%) rename src/test/run-make-fulldeps/{coverage-reports-deadcode => coverage-reports}/expected_show_coverage.loops_branches.txt (89%) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.nested_loops.txt (84%) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt rename src/test/run-make-fulldeps/{coverage-reports-deadcode => coverage-reports}/expected_show_coverage.simple_loop.txt (75%) rename src/test/run-make-fulldeps/{coverage-reports-deadcode => coverage-reports}/expected_show_coverage.simple_match.txt (80%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.tight_inf_loop.txt (62%) rename src/test/run-make-fulldeps/{coverage-reports-deadcode => coverage-reports}/expected_show_coverage.try_error_result.txt (87%) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.while.txt (80%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.while_early_ret.txt (77%) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt create mode 100755 src/test/run-make-fulldeps/coverage-reports/normalize_paths.py delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/Makefile delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/Makefile rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/escape_url.py (100%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.async/async.c-{closure#0}.-------.InstrumentCoverage.0.html} (63%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.async/async.d-{closure#0}.-------.InstrumentCoverage.0.html} (75%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html} (55%) rename src/test/run-make-fulldeps/{coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html} (55%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html} (60%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html} (59%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-c.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-d.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-f.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.k.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.l.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html (64%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.closure/closure.main-{closure#10}.-------.InstrumentCoverage.0.html} (64%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.closure/closure.main-{closure#11}.-------.InstrumentCoverage.0.html} (64%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html (64%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#4}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#5}.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.closure/closure.main-{closure#6}.-------.InstrumentCoverage.0.html} (58%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#7}.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.closure/closure.main-{closure#8}.-------.InstrumentCoverage.0.html} (57%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#9}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_fn.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_pub_fn_not_in_library.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html (64%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html (56%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html (87%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html (50%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html (78%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html (89%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html} (51%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html (81%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html (70%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html (71%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html (59%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html (86%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (89%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html (89%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (89%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html (89%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (89%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html (89%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (89%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html (89%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html (87%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html (69%) rename src/test/run-make-fulldeps/{coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html} (67%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html (94%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html (63%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html (69%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html (84%) rename src/test/run-make-fulldeps/{coverage-spanview-deadcode => coverage-spanview}/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html (78%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_bin_crate_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html (85%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html (82%) rename src/test/run-make-fulldeps/{coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html => coverage-spanview/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html} (60%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/abort.rs create mode 100644 src/test/run-make-fulldeps/coverage/assert.rs create mode 100644 src/test/run-make-fulldeps/coverage/async.rs create mode 100644 src/test/run-make-fulldeps/coverage/dead_code.rs create mode 100644 src/test/run-make-fulldeps/coverage/doctest.rs create mode 100644 src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs create mode 100644 src/test/run-make-fulldeps/coverage/lib/used_crate.rs create mode 100644 src/test/run-make-fulldeps/coverage/match_or_pattern.rs create mode 100644 src/test/run-make-fulldeps/coverage/overflow.rs create mode 100644 src/test/run-make-fulldeps/coverage/panic_unwind.rs create mode 100644 src/test/run-make-fulldeps/coverage/uses_crate.rs create mode 100644 src/test/run-make-fulldeps/coverage/yield.rs create mode 100644 src/test/run-make-fulldeps/separate-link/Makefile create mode 100644 src/test/run-make-fulldeps/split-dwarf/Makefile create mode 100644 src/test/run-make-fulldeps/split-dwarf/foo.rs create mode 100644 src/test/run-make/fmt-write-bloat/Makefile create mode 100644 src/test/run-make/fmt-write-bloat/main.rs create mode 100644 src/test/rustdoc-js/summaries.js create mode 100644 src/test/rustdoc-js/summaries.rs create mode 100644 src/test/rustdoc-json/check_missing_items.py create mode 100644 src/test/rustdoc-json/compare.py create mode 100644 src/test/rustdoc-json/nested.expected create mode 100644 src/test/rustdoc-json/nested.rs create mode 100644 src/test/rustdoc-json/structs.expected create mode 100644 src/test/rustdoc-json/structs.rs create mode 100644 src/test/rustdoc-ui/check-fail.rs create mode 100644 src/test/rustdoc-ui/check-fail.stderr create mode 100644 src/test/rustdoc-ui/check.rs create mode 100644 src/test/rustdoc-ui/check.stderr rename src/test/rustdoc-ui/{intra-doc-alias-ice.rs => intra-doc/alias-ice.rs} (100%) rename src/test/rustdoc-ui/{intra-doc-alias-ice.stderr => intra-doc/alias-ice.stderr} (82%) rename src/test/rustdoc-ui/{intra-links-ambiguity.rs => intra-doc/ambiguity.rs} (100%) rename src/test/rustdoc-ui/{intra-links-ambiguity.stderr => intra-doc/ambiguity.stderr} (90%) rename src/test/rustdoc-ui/{intra-links-anchors.rs => intra-doc/anchors.rs} (100%) rename src/test/rustdoc-ui/{intra-links-anchors.stderr => intra-doc/anchors.stderr} (81%) rename src/test/rustdoc-ui/{ => intra-doc}/auxiliary/intra-doc-broken.rs (100%) rename src/test/rustdoc-ui/{intra-doc-broken-reexport.rs => intra-doc/broken-reexport.rs} (100%) rename src/test/rustdoc-ui/{intra-links-disambiguator-mismatch.rs => intra-doc/disambiguator-mismatch.rs} (100%) rename src/test/rustdoc-ui/{intra-links-disambiguator-mismatch.stderr => intra-doc/disambiguator-mismatch.stderr} (80%) rename src/test/rustdoc-ui/{intra-link-double-anchor.rs => intra-doc/double-anchor.rs} (100%) rename src/test/rustdoc-ui/{intra-link-double-anchor.stderr => intra-doc/double-anchor.stderr} (85%) rename src/test/rustdoc-ui/{intra-link-errors.rs => intra-doc/errors.rs} (100%) rename src/test/rustdoc-ui/{intra-link-errors.stderr => intra-doc/errors.stderr} (83%) rename src/test/rustdoc-ui/{intra-link-malformed-generics.rs => intra-doc/malformed-generics.rs} (100%) rename src/test/rustdoc-ui/{intra-link-malformed-generics.stderr => intra-doc/malformed-generics.stderr} (73%) rename src/test/rustdoc-ui/{intra-link-prim-conflict.rs => intra-doc/prim-conflict.rs} (100%) rename src/test/rustdoc-ui/{intra-link-prim-conflict.stderr => intra-doc/prim-conflict.stderr} (84%) rename src/test/rustdoc-ui/{intra-links-private.private.stderr => intra-doc/private.private.stderr} (90%) rename src/test/rustdoc-ui/{intra-links-private.public.stderr => intra-doc/private.public.stderr} (89%) rename src/test/rustdoc-ui/{intra-links-private.rs => intra-doc/private.rs} (100%) rename src/test/rustdoc-ui/{intra-link-span-ice-55723.rs => intra-doc/span-ice-55723.rs} (100%) rename src/test/rustdoc-ui/{intra-link-span-ice-55723.stderr => intra-doc/span-ice-55723.stderr} (79%) rename src/test/rustdoc-ui/{intra-links-warning-crlf.rs => intra-doc/warning-crlf.rs} (100%) rename src/test/rustdoc-ui/{intra-links-warning-crlf.stderr => intra-doc/warning-crlf.stderr} (83%) rename src/test/rustdoc-ui/{intra-links-warning.rs => intra-doc/warning.rs} (100%) rename src/test/rustdoc-ui/{intra-links-warning.stderr => intra-doc/warning.stderr} (86%) create mode 100644 src/test/rustdoc-ui/invalid-keyword.rs create mode 100644 src/test/rustdoc-ui/invalid-keyword.stderr delete mode 100644 src/test/rustdoc-ui/reference-link-has-one-warning.rs delete mode 100644 src/test/rustdoc-ui/reference-link-has-one-warning.stderr create mode 100644 src/test/rustdoc/auxiliary/normalize-assoc-item.rs create mode 100644 src/test/rustdoc/check.rs rename src/test/rustdoc/{ => const-generics}/lazy_normalization_consts/const-equate-pred.rs (100%) create mode 100644 src/test/rustdoc/decl_macro.rs create mode 100644 src/test/rustdoc/decl_macro_priv.rs create mode 100644 src/test/rustdoc/doc-cfg-traits.rs create mode 100644 src/test/rustdoc/intra-doc-crate/auxiliary/self.rs create mode 100644 src/test/rustdoc/intra-doc-crate/self.rs delete mode 100644 src/test/rustdoc/intra-doc-link-mod-ambiguity.rs rename src/test/rustdoc/{intra-links-anchors.rs => intra-doc/anchors.rs} (50%) create mode 100644 src/test/rustdoc/intra-doc/associated-defaults.rs create mode 100644 src/test/rustdoc/intra-doc/associated-items.rs rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-link-extern-crate.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-link-pub-use.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-link-reexport-additional-docs.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-links-external-traits.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/my-core.rs (100%) rename src/test/rustdoc/{auxiliary/intra-link-proc-macro-macro.rs => intra-doc/auxiliary/proc-macro-macro.rs} (93%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/through-proc-macro-aux.rs (100%) rename src/test/rustdoc/{intra-links.rs => intra-doc/basic.rs} (52%) rename src/test/rustdoc/{intra-link-builtin-macros.rs => intra-doc/builtin-macros.rs} (66%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/additional_doc.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/additional_doc.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/hidden.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/intra-doc-basic.rs (100%) rename src/test/rustdoc/{ => intra-doc/cross-crate}/auxiliary/intra-link-cross-crate-crate.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/macro_inner.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/module.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/proc_macro.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/submodule-inner.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/submodule-outer.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/traits.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/basic.rs (100%) rename src/test/rustdoc/{intra-link-cross-crate-crate.rs => intra-doc/cross-crate/crate.rs} (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/hidden.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/macro.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/module.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/submodule-inner.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/submodule-outer.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/traits.rs (100%) create mode 100644 src/test/rustdoc/intra-doc/disambiguators-removed.rs rename src/test/rustdoc/{intra-doc-link-enum-struct-field.rs => intra-doc/enum-struct-field.rs} (100%) rename src/test/rustdoc/{intra-link-extern-crate.rs => intra-doc/extern-crate.rs} (100%) create mode 100644 src/test/rustdoc/intra-doc/extern-type.rs rename src/test/rustdoc/{intra-links-external-traits.rs => intra-doc/external-traits.rs} (100%) rename src/test/rustdoc/{intra-doc-link-generic-params.rs => intra-doc/generic-params.rs} (92%) rename src/test/rustdoc/{intra-link-in-bodies.rs => intra-doc/in-bodies.rs} (100%) rename src/test/rustdoc/{intra-link-libstd-re-export.rs => intra-doc/libstd-re-export.rs} (100%) create mode 100644 src/test/rustdoc/intra-doc/mod-ambiguity.rs create mode 100644 src/test/rustdoc/intra-doc/prim-assoc.rs rename src/test/rustdoc/{intra-link-prim-methods-external-core.rs => intra-doc/prim-methods-external-core.rs} (90%) rename src/test/rustdoc/{intra-link-prim-methods-local.rs => intra-doc/prim-methods-local.rs} (92%) rename src/test/rustdoc/{intra-link-prim-methods.rs => intra-doc/prim-methods.rs} (88%) create mode 100644 src/test/rustdoc/intra-doc/prim-precedence.rs rename src/test/rustdoc/{intra-link-primitive-non-default-impl.rs => intra-doc/primitive-non-default-impl.rs} (88%) rename src/test/rustdoc/{intra-link-private.rs => intra-doc/private-failures-ignored.rs} (100%) rename src/test/rustdoc/{intra-doc-link-private.rs => intra-doc/private.rs} (100%) create mode 100644 src/test/rustdoc/intra-doc/proc-macro.rs rename src/test/rustdoc/{intra-link-pub-use.rs => intra-doc/pub-use.rs} (100%) create mode 100644 src/test/rustdoc/intra-doc/raw-ident-self.rs rename src/test/rustdoc/{intra-link-reexport-additional-docs.rs => intra-doc/reexport-additional-docs.rs} (100%) rename src/test/rustdoc/{intra-link-self.rs => intra-doc/self.rs} (100%) rename src/test/rustdoc/{ => intra-doc}/through-proc-macro.rs (100%) rename src/test/rustdoc/{intra-link-trait-impl.rs => intra-doc/trait-impl.rs} (100%) rename src/test/rustdoc/{intra-link-trait-item.rs => intra-doc/trait-item.rs} (69%) rename src/test/rustdoc/{intra-doc-link-true-false.rs => intra-doc/true-false.rs} (100%) delete mode 100644 src/test/rustdoc/intra-link-associated-defaults.rs delete mode 100644 src/test/rustdoc/intra-link-associated-items.rs delete mode 100644 src/test/rustdoc/intra-link-disambiguators-removed.rs delete mode 100644 src/test/rustdoc/intra-link-prim-assoc.rs delete mode 100644 src/test/rustdoc/intra-link-prim-precedence.rs create mode 100644 src/test/rustdoc/intra-link-prim-self.rs delete mode 100644 src/test/rustdoc/intra-link-proc-macro.rs create mode 100644 src/test/rustdoc/intra-link-self-cache.rs create mode 100644 src/test/rustdoc/issue-78673.rs create mode 100644 src/test/rustdoc/issue-79201.rs rename src/test/rustdoc/{plain-text-summaries.rs => markdown-summaries.rs} (55%) create mode 100644 src/test/rustdoc/normalize-assoc-item.rs delete mode 100644 src/test/rustdoc/pub-restricted.rs create mode 100644 src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs create mode 100644 src/test/rustdoc/trait-src-link.rs create mode 100644 src/test/rustdoc/visibility.rs create mode 100644 src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs create mode 100644 src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr create mode 100644 src/test/ui/abi/issues/issue-22565-rust-call.rs create mode 100644 src/test/ui/abi/issues/issue-22565-rust-call.stderr create mode 100644 src/test/ui/abi/rustcall-generic.rs create mode 100644 src/test/ui/asm/naked-functions.rs create mode 100644 src/test/ui/asm/naked-functions.stderr create mode 100644 src/test/ui/asm/naked-invalid-attr.rs create mode 100644 src/test/ui/asm/naked-invalid-attr.stderr delete mode 100644 src/test/ui/assert-eq-trailing-comma.rs delete mode 100644 src/test/ui/assert-escape.rs delete mode 100644 src/test/ui/assert-ne-trailing-comma.rs create mode 100644 src/test/ui/associated-type-bounds/order-dependent-bounds-issue-54121.rs create mode 100644 src/test/ui/associated-types/project-recursion-limit-non-fatal.rs create mode 100644 src/test/ui/async-await/issue-75785-confusing-named-region.rs create mode 100644 src/test/ui/async-await/issue-75785-confusing-named-region.stderr delete mode 100644 src/test/ui/atomic-access-bool.rs delete mode 100644 src/test/ui/atomic-alignment.rs delete mode 100644 src/test/ui/atomic-compare_exchange.rs create mode 100644 src/test/ui/attributes/key-value-non-ascii.rs create mode 100644 src/test/ui/attributes/key-value-non-ascii.stderr create mode 100644 src/test/ui/auxiliary/fancy-panic.rs create mode 100644 src/test/ui/binop/issue-77910-1.rs create mode 100644 src/test/ui/binop/issue-77910-1.stderr create mode 100644 src/test/ui/binop/issue-77910-2.rs create mode 100644 src/test/ui/binop/issue-77910-2.stderr delete mode 100644 src/test/ui/bool-not.rs delete mode 100644 src/test/ui/bool.rs delete mode 100644 src/test/ui/char_unicode.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/capture-enums.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/capture-enums.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/multilevel-path-1.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/multilevel-path-1.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/multilevel-path-2.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/multilevel-path-2.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/nested-closure.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/nested-closure.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/path-with-array-access.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/path-with-array-access.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/box.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/wild_patterns.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/wild_patterns.stderr delete mode 100644 src/test/ui/cmp-default.rs create mode 100644 src/test/ui/const-generics/const-param-shadowing.rs create mode 100644 src/test/ui/const-generics/const-param-shadowing.stderr create mode 100644 src/test/ui/const-generics/infer/one-param-uninferred.full.stderr create mode 100644 src/test/ui/const-generics/infer/one-param-uninferred.min.stderr create mode 100644 src/test/ui/const-generics/infer/one-param-uninferred.rs create mode 100644 src/test/ui/const-generics/min_const_generics/inferred_const.rs create mode 100644 src/test/ui/const-generics/min_const_generics/inferred_const.stderr create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-5.rs create mode 100644 src/test/ui/const-generics/occurs-check/unused-substs-5.stderr create mode 100644 src/test/ui/const-generics/promotion.rs delete mode 100644 src/test/ui/consts/ascii_ctype.rs create mode 100644 src/test/ui/consts/assume-type-intrinsics.rs create mode 100644 src/test/ui/consts/assume-type-intrinsics.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr delete mode 100644 src/test/ui/consts/const-fn-feature-flags.rs delete mode 100644 src/test/ui/consts/const-str-ptr.rs create mode 100644 src/test/ui/consts/issue-76064.rs create mode 100644 src/test/ui/consts/issue-76064.stderr create mode 100644 src/test/ui/consts/issue-79137-monomorphic.rs create mode 100644 src/test/ui/consts/issue-79137-toogeneric.rs create mode 100644 src/test/ui/consts/issue-79137-toogeneric.stderr create mode 100644 src/test/ui/consts/issue-79152-const-array-index.rs create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs delete mode 100644 src/test/ui/deref-mut-on-ref.rs delete mode 100644 src/test/ui/deref-on-ref.rs rename src/test/ui/{issues => derives}/issue-36617.rs (68%) rename src/test/ui/{issues => derives}/issue-36617.stderr (65%) create mode 100644 src/test/ui/destructuring-assignment/drop-order.rs create mode 100644 src/test/ui/doc_keyword.rs create mode 100644 src/test/ui/doc_keyword.stderr rename src/test/ui/{issues => dropck}/issue-38868.rs (100%) rename src/test/ui/{issues => dropck}/issue-38868.stderr (100%) rename src/test/ui/{ => dropck}/reject-specialized-drops-8142.rs (88%) rename src/test/ui/{ => dropck}/reject-specialized-drops-8142.stderr (71%) delete mode 100644 src/test/ui/env-home-dir.rs create mode 100644 src/test/ui/expr/compound-assignment/eval-order.rs rename src/test/ui/{ => expr}/if-bot.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/bad-cfg.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/bad-cfg.stderr (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/builtin-if-attr.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/cfg-false-if-attr.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/else-attrs.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/else-attrs.stderr (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/gate-whole-expr.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/let-chains-attr.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/let-chains-attr.stderr (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/stmt-expr-gated.rs (100%) rename src/test/ui/{if-attrs => expr/if/attrs}/stmt-expr-gated.stderr (100%) rename src/test/ui/{ => expr}/if/expr-if-panic-fn.rs (100%) rename src/test/ui/{ => expr}/if/expr-if-panic.rs (100%) rename src/test/ui/{ => expr}/if/if-branch-types.rs (100%) rename src/test/ui/{ => expr}/if/if-branch-types.stderr (100%) rename src/test/ui/{ => expr}/if/if-check-panic.rs (100%) rename src/test/ui/{ => expr/if}/if-check.rs (100%) rename src/test/ui/{ => expr}/if/if-cond-bot.rs (100%) rename src/test/ui/{ => expr/if}/if-else-type-mismatch.rs (100%) rename src/test/ui/{ => expr/if}/if-else-type-mismatch.stderr (100%) rename src/test/ui/{ => expr}/if/if-let-arm-types.rs (100%) rename src/test/ui/{ => expr}/if/if-let-arm-types.stderr (100%) rename src/test/ui/{ => expr}/if/if-let.rs (100%) rename src/test/ui/{ => expr}/if/if-let.stderr (100%) rename src/test/ui/{ => expr}/if/if-loop.rs (100%) rename src/test/ui/{ => expr}/if/if-no-match-bindings.rs (100%) rename src/test/ui/{ => expr}/if/if-no-match-bindings.stderr (100%) rename src/test/ui/{ => expr/if}/if-ret.rs (100%) rename src/test/ui/{ => expr/if}/if-ret.stderr (100%) rename src/test/ui/{ => expr}/if/if-typeck.rs (100%) rename src/test/ui/{ => expr}/if/if-typeck.stderr (100%) rename src/test/ui/{ => expr}/if/if-without-block.rs (100%) rename src/test/ui/{ => expr}/if/if-without-block.stderr (100%) rename src/test/ui/{ => expr}/if/if-without-else-as-fn-expr.rs (100%) rename src/test/ui/{ => expr}/if/if-without-else-as-fn-expr.stderr (100%) rename src/test/ui/{ => expr}/if/if-without-else-result.rs (100%) rename src/test/ui/{ => expr}/if/if-without-else-result.stderr (100%) delete mode 100644 src/test/ui/extend-for-unit.rs rename src/test/ui/feature-gates/{feature-gate-optin-builtin-traits.rs => feature-gate-auto-traits.rs} (89%) rename src/test/ui/feature-gates/{feature-gate-optin-builtin-traits.stderr => feature-gate-auto-traits.stderr} (78%) create mode 100644 src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs create mode 100644 src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr rename src/test/ui/{if => fmt}/ifmt-bad-arg.rs (100%) rename src/test/ui/{if => fmt}/ifmt-bad-arg.stderr (100%) rename src/test/ui/{if => fmt}/ifmt-bad-format-args.rs (100%) rename src/test/ui/{if => fmt}/ifmt-bad-format-args.stderr (100%) rename src/test/ui/{if => fmt}/ifmt-unimpl.rs (100%) rename src/test/ui/{if => fmt}/ifmt-unimpl.stderr (100%) rename src/test/ui/{if => fmt}/ifmt-unknown-trait.rs (100%) rename src/test/ui/{if => fmt}/ifmt-unknown-trait.stderr (100%) create mode 100644 src/test/ui/fn/fn-recover-return-sign.fixed create mode 100644 src/test/ui/fn/fn-recover-return-sign.rs create mode 100644 src/test/ui/fn/fn-recover-return-sign.stderr create mode 100644 src/test/ui/fn/fn-recover-return-sign2.rs create mode 100644 src/test/ui/fn/fn-recover-return-sign2.stderr create mode 100644 src/test/ui/foreign/foreign-pub-super.rs create mode 100644 src/test/ui/generic-associated-types/issue-74824.rs create mode 100644 src/test/ui/generic-associated-types/issue-74824.stderr create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-expressions.rs create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-segments.rs create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-segments.stderr create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-types.rs create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-types.stderr create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs create mode 100644 src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr delete mode 100644 src/test/ui/hidden-rt-injection.rs delete mode 100644 src/test/ui/hidden-rt-injection.stderr delete mode 100644 src/test/ui/hidden-rt-injection2.rs delete mode 100644 src/test/ui/hidden-rt-injection2.stderr create mode 100644 src/test/ui/impl-trait/issues/issue-78721.rs create mode 100644 src/test/ui/impl-trait/issues/issue-78721.stderr create mode 100644 src/test/ui/impl-trait/issues/issue-78722.rs create mode 100644 src/test/ui/impl-trait/issues/issue-78722.stderr delete mode 100644 src/test/ui/import.rs delete mode 100644 src/test/ui/import2.rs delete mode 100644 src/test/ui/import3.rs delete mode 100644 src/test/ui/import4.rs rename src/test/ui/{issues => imports}/auxiliary/issue-36881-aux.rs (100%) rename src/test/ui/{issues => imports}/auxiliary/issue-52891.rs (100%) rename src/test/ui/{issues => imports}/auxiliary/issue-59764.rs (100%) rename src/test/ui/{ => imports}/double-import.rs (100%) rename src/test/ui/{ => imports}/double-import.stderr (100%) rename src/test/ui/{ => imports}/export-glob-imports-target.rs (100%) rename src/test/ui/{ => imports}/glob-resolve1.rs (100%) rename src/test/ui/{ => imports}/glob-resolve1.stderr (100%) create mode 100644 src/test/ui/imports/import-rpass.rs rename src/test/ui/{ => imports}/import.stderr (100%) create mode 100644 src/test/ui/imports/import2-rpass.rs rename src/test/ui/{ => imports}/import2.stderr (100%) create mode 100644 src/test/ui/imports/import3-rpass.rs rename src/test/ui/{ => imports}/import3.stderr (100%) create mode 100644 src/test/ui/imports/import4-rpass.rs rename src/test/ui/{ => imports}/import4.stderr (100%) rename src/test/ui/{issues => imports}/issue-13404.rs (100%) rename src/test/ui/{issues => imports}/issue-13404.stderr (100%) rename src/test/ui/{issues => imports}/issue-1697.rs (100%) rename src/test/ui/{issues => imports}/issue-1697.stderr (100%) rename src/test/ui/{issues => imports}/issue-18083.rs (100%) rename src/test/ui/{issues => imports}/issue-19498.rs (100%) rename src/test/ui/{issues => imports}/issue-19498.stderr (100%) rename src/test/ui/{issues => imports}/issue-24081.rs (100%) rename src/test/ui/{issues => imports}/issue-24081.stderr (100%) rename src/test/ui/{issues => imports}/issue-25396.rs (100%) rename src/test/ui/{issues => imports}/issue-25396.stderr (100%) rename src/test/ui/{issues => imports}/issue-26886.rs (100%) rename src/test/ui/{issues => imports}/issue-26886.stderr (100%) rename src/test/ui/{issues => imports}/issue-28134.rs (80%) rename src/test/ui/{issues => imports}/issue-28134.stderr (87%) rename src/test/ui/{issues => imports}/issue-28388-1.rs (100%) rename src/test/ui/{issues => imports}/issue-28388-1.stderr (100%) rename src/test/ui/{issues => imports}/issue-28388-2.rs (100%) rename src/test/ui/{issues => imports}/issue-28388-2.stderr (100%) rename src/test/ui/{issues => imports}/issue-2937.rs (100%) rename src/test/ui/{issues => imports}/issue-2937.stderr (100%) rename src/test/ui/{issues => imports}/issue-30560.rs (100%) rename src/test/ui/{issues => imports}/issue-30560.stderr (100%) rename src/test/ui/{issues => imports}/issue-31212.rs (100%) rename src/test/ui/{issues => imports}/issue-31212.stderr (100%) rename src/test/ui/{issues => imports}/issue-32354-suggest-import-rename.fixed (100%) rename src/test/ui/{issues => imports}/issue-32354-suggest-import-rename.rs (100%) rename src/test/ui/{issues => imports}/issue-32354-suggest-import-rename.stderr (100%) rename src/test/ui/{issues => imports}/issue-32833.rs (100%) rename src/test/ui/{issues => imports}/issue-32833.stderr (100%) rename src/test/ui/{issues => imports}/issue-33464.rs (100%) rename src/test/ui/{issues => imports}/issue-33464.stderr (100%) rename src/test/ui/{issues => imports}/issue-36881.rs (100%) rename src/test/ui/{issues => imports}/issue-36881.stderr (100%) rename src/test/ui/{issues => imports}/issue-37887.rs (100%) rename src/test/ui/{issues => imports}/issue-37887.stderr (100%) rename src/test/ui/{issues => imports}/issue-38293.rs (100%) rename src/test/ui/{issues => imports}/issue-38293.stderr (100%) rename src/test/ui/{issues => imports}/issue-4366-2.rs (100%) rename src/test/ui/{issues => imports}/issue-4366-2.stderr (100%) rename src/test/ui/{issues => imports}/issue-4366.rs (100%) rename src/test/ui/{issues => imports}/issue-4366.stderr (100%) rename src/test/ui/{issues => imports}/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed (100%) rename src/test/ui/{issues => imports}/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs (100%) rename src/test/ui/{issues => imports}/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/auxiliary/issue-45829-a.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/auxiliary/issue-45829-b.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/import-self.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/import-self.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/import-twice.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/import-twice.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/issue-45829.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/issue-45829.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-vs-use.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-vs-use.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-with-tab.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-with-tab.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-vs-extern.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-vs-extern.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-with-tabs.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-with-tabs.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-with-path.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-with-path.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename.stderr (100%) rename src/test/ui/{issues => imports}/issue-47623.rs (100%) rename src/test/ui/{issues => imports}/issue-47623.stderr (100%) rename src/test/ui/{issues => imports}/issue-4865-1.rs (100%) rename src/test/ui/{issues => imports}/issue-4865-2.rs (100%) rename src/test/ui/{issues => imports}/issue-4865-3.rs (100%) rename src/test/ui/{issues => imports}/issue-52891.fixed (100%) rename src/test/ui/{issues => imports}/issue-52891.rs (100%) rename src/test/ui/{issues => imports}/issue-52891.stderr (100%) rename src/test/ui/{issues => imports}/issue-53565.rs (100%) rename src/test/ui/{issues => imports}/issue-53565.stderr (100%) rename src/test/ui/{issues => imports}/issue-59764.rs (100%) rename src/test/ui/{issues => imports}/issue-59764.stderr (100%) rename src/test/ui/{issues => imports}/issue-8208.rs (100%) rename src/test/ui/{issues => imports}/issue-8208.stderr (100%) rename src/test/ui/{issues => imports}/issue-8640.rs (100%) rename src/test/ui/{issues => imports}/issue-8640.stderr (100%) rename src/test/ui/{ => imports}/resolve_self_super_hint.rs (100%) rename src/test/ui/{ => imports}/resolve_self_super_hint.stderr (100%) create mode 100644 src/test/ui/infinite/infinite-struct.rs create mode 100644 src/test/ui/infinite/infinite-struct.stderr create mode 100644 src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs create mode 100644 src/test/ui/inherent-impls-overlap-check/no-overlap.rs create mode 100644 src/test/ui/inherent-impls-overlap-check/overlap.rs create mode 100644 src/test/ui/inherent-impls-overlap-check/overlap.stderr delete mode 100644 src/test/ui/issues/issue-15129.rs delete mode 100644 src/test/ui/issues/issue-2111.rs delete mode 100644 src/test/ui/issues/issue-49955-2.rs create mode 100644 src/test/ui/issues/issue-73899.rs create mode 100644 src/test/ui/issues/issue-76042.rs create mode 100644 src/test/ui/issues/issue-78720.rs create mode 100644 src/test/ui/issues/issue-78720.stderr create mode 100644 src/test/ui/issues/issue-78957.rs create mode 100644 src/test/ui/issues/issue-78957.stderr create mode 100644 src/test/ui/issues/issue-79593.rs create mode 100644 src/test/ui/issues/issue-79593.stderr create mode 100644 src/test/ui/kinds-of-primitive-impl.rs create mode 100644 src/test/ui/kinds-of-primitive-impl.stderr create mode 100644 src/test/ui/label/label_misspelled.rs create mode 100644 src/test/ui/label/label_misspelled.stderr create mode 100644 src/test/ui/layout/big-type-no-err.rs create mode 100644 src/test/ui/lint/dead-code/type-in-foreign.rs create mode 100644 src/test/ui/lint/forbid-error-capped.rs create mode 100644 src/test/ui/lint/forbid-group-group-1.rs create mode 100644 src/test/ui/lint/forbid-group-group-1.stderr create mode 100644 src/test/ui/lint/forbid-group-group-2.rs create mode 100644 src/test/ui/lint/forbid-group-group-2.stderr create mode 100644 src/test/ui/lint/forbid-group-member.rs create mode 100644 src/test/ui/lint/forbid-group-member.stderr create mode 100644 src/test/ui/lint/forbid-member-group.rs create mode 100644 src/test/ui/lint/forbid-member-group.stderr create mode 100644 src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs create mode 100644 src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr create mode 100644 src/test/ui/lint/issue-80988.rs create mode 100644 src/test/ui/lint/issue-80988.stderr create mode 100644 src/test/ui/lint/issue-81218.rs create mode 100644 src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs create mode 100644 src/test/ui/lint/special-upper-lower-cases.rs create mode 100644 src/test/ui/lint/special-upper-lower-cases.stderr create mode 100644 src/test/ui/macros/issue-78333.rs create mode 100644 src/test/ui/macros/macro-pat-follow-2018.rs create mode 100644 src/test/ui/match/issue-72680.rs create mode 100644 src/test/ui/mir/issue-78496.rs create mode 100644 src/test/ui/mir/issue-80949.rs create mode 100644 src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs rename src/test/ui/{issues => modules}/issue-56411-aux.rs (100%) rename src/test/ui/{issues => modules}/issue-56411.rs (100%) rename src/test/ui/{issues => modules}/issue-56411.stderr (100%) create mode 100644 src/test/ui/no-std-macros.rs delete mode 100644 src/test/ui/offset_from.rs delete mode 100644 src/test/ui/option-ext.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs create mode 100644 src/test/ui/panic-brace.rs create mode 100644 src/test/ui/panic-brace.stderr create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.rs create mode 100644 src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr rename src/test/ui/pattern/{usefulness/irrefutable-exhaustive-integer-binding.rs => integer-range-binding.rs} (100%) create mode 100644 src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.rs create mode 100644 src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr create mode 100644 src/test/ui/pattern/or-pattern-macro-pat.rs create mode 100644 src/test/ui/pattern/usefulness/auxiliary/empty.rs rename src/test/ui/pattern/{ => usefulness}/const-pat-ice.rs (100%) rename src/test/ui/pattern/{ => usefulness}/deny-irrefutable-let-patterns.rs (100%) rename src/test/ui/pattern/{ => usefulness}/deny-irrefutable-let-patterns.stderr (100%) delete mode 100644 src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs delete mode 100644 src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr rename src/test/ui/pattern/usefulness/{non-exhaustive-float-range-match.rs => floats.rs} (66%) rename src/test/ui/pattern/usefulness/{non-exhaustive-float-range-match.stderr => floats.stderr} (53%) delete mode 100644 src/test/ui/pattern/usefulness/guards-not-exhaustive.rs create mode 100644 src/test/ui/pattern/usefulness/guards.rs create mode 100644 src/test/ui/pattern/usefulness/guards.stderr create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr rename src/test/ui/pattern/usefulness/{non-exhaustive-pattern-pointer-size-int.rs => integer-ranges/precise_pointer_matching-message.rs} (56%) rename src/test/ui/pattern/usefulness/{non-exhaustive-pattern-pointer-size-int.stderr => integer-ranges/precise_pointer_matching-message.stderr} (68%) create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/reachability.rs create mode 100644 src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr rename src/test/ui/pattern/{ => usefulness}/irrefutable-let-patterns.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-12116.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-12116.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-12369.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-12369.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-13727.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-13727.stderr (100%) create mode 100644 src/test/ui/pattern/usefulness/issue-15129.rs rename src/test/ui/{issues => pattern/usefulness}/issue-15129.stderr (64%) create mode 100644 src/test/ui/pattern/usefulness/issue-2111.rs rename src/test/ui/{issues => pattern/usefulness}/issue-2111.stderr (56%) rename src/test/ui/{issues => pattern/usefulness}/issue-30240-b.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-30240-b.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-30240-rpass.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-30240.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-30240.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-3096-1.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-3096-1.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-3096-2.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-3096-2.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-31221.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-31221.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-31561.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-31561.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-3601.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-3601.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-39362.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-39362.stderr (100%) rename src/test/ui/{missing/missing-items => pattern/usefulness}/issue-40221.rs (100%) rename src/test/ui/{missing/missing-items => pattern/usefulness}/issue-40221.stderr (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-4321.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-4321.stderr (100%) delete mode 100644 src/test/ui/pattern/usefulness/issue-43253.rs delete mode 100644 src/test/ui/pattern/usefulness/issue-43253.stderr rename src/test/ui/{match => pattern/usefulness}/issue-50900.rs (100%) rename src/test/ui/{match => pattern/usefulness}/issue-50900.stderr (100%) create mode 100644 src/test/ui/pattern/usefulness/issue-56379.rs create mode 100644 src/test/ui/pattern/usefulness/issue-56379.stderr rename src/test/ui/{issues => pattern/usefulness}/issue-57472.rs (100%) rename src/test/ui/{issues => pattern/usefulness}/issue-57472.stderr (100%) rename src/test/ui/pattern/{ => usefulness}/issue-66501.rs (100%) delete mode 100644 src/test/ui/pattern/usefulness/match-range-fail-dominate.rs delete mode 100644 src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr rename src/test/ui/{match => pattern/usefulness}/type_polymorphic_byte_str_literals.rs (100%) rename src/test/ui/{match => pattern/usefulness}/type_polymorphic_byte_str_literals.stderr (100%) rename src/test/ui/{phantom-oibit.rs => phantom-auto-trait.rs} (69%) rename src/test/ui/{phantom-oibit.stderr => phantom-auto-trait.stderr} (94%) delete mode 100644 src/test/ui/precise_pointer_size_matching.rs delete mode 100644 src/test/ui/precise_pointer_size_matching.stderr create mode 100644 src/test/ui/proc-macro/allowed-attr-stmt-expr.rs create mode 100644 src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout create mode 100644 src/test/ui/proc-macro/attr-stmt-expr.stdout create mode 100644 src/test/ui/proc-macro/auxiliary/issue-66286.rs create mode 100644 src/test/ui/proc-macro/auxiliary/issue-79242.rs create mode 100644 src/test/ui/proc-macro/capture-unglued-token.rs create mode 100644 src/test/ui/proc-macro/capture-unglued-token.stdout create mode 100644 src/test/ui/proc-macro/issue-66286.rs create mode 100644 src/test/ui/proc-macro/issue-66286.stderr create mode 100644 src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs create mode 100644 src/test/ui/proc-macro/keep-expr-tokens.stdout rename src/test/ui/{ => resolve}/auxiliary/extern-prelude-vec.rs (100%) rename src/test/ui/{ => resolve}/auxiliary/extern-prelude.rs (100%) rename src/test/ui/{ => resolve}/extern-prelude-fail.rs (100%) rename src/test/ui/{ => resolve}/extern-prelude-fail.stderr (100%) rename src/test/ui/{ => resolve}/extern-prelude.rs (100%) rename src/test/ui/{issues => resolve}/issue-49074.rs (100%) rename src/test/ui/{issues => resolve}/issue-49074.stderr (100%) create mode 100644 src/test/ui/resolve/macro-determinacy-non-module.rs rename src/test/ui/{ => resolve}/resolve-pseudo-shadowing.rs (100%) delete mode 100644 src/test/ui/result-opt-conversions.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/bindings.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/bindings.stderr create mode 100644 src/test/ui/rfc-2294-if-let-guard/run-pass.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/typeck.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/typeck.stderr create mode 100644 src/test/ui/rfc-2294-if-let-guard/warns.rs create mode 100644 src/test/ui/rfc-2294-if-let-guard/warns.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr create mode 100644 src/test/ui/simd/simd-array-trait.rs create mode 100644 src/test/ui/simd/simd-array-trait.stderr create mode 100644 src/test/ui/simd/simd-array-type.rs rename src/test/ui/{issues => stability-attribute}/auxiliary/lint-stability.rs (100%) rename src/test/ui/{issues => stability-attribute}/issue-28075.rs (100%) rename src/test/ui/{issues => stability-attribute}/issue-28075.stderr (100%) rename src/test/ui/{issues => stability-attribute}/issue-28388-3.rs (100%) rename src/test/ui/{issues => stability-attribute}/issue-28388-3.stderr (100%) create mode 100644 src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs create mode 100644 src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr create mode 100644 src/test/ui/test-passed-wasm.rs create mode 100644 src/test/ui/test-passed-wasm.run.stdout create mode 100644 src/test/ui/test-passed.rs create mode 100644 src/test/ui/test-passed.run.stdout create mode 100644 src/test/ui/traits/issue-79458.rs create mode 100644 src/test/ui/traits/issue-79458.stderr create mode 100644 src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs create mode 100644 src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr rename src/test/ui/traits/{traits-inductive-overflow-supertrait-oibit.rs => traits-inductive-overflow-supertrait-auto-trait.rs} (60%) rename src/test/ui/traits/{traits-inductive-overflow-supertrait-oibit.stderr => traits-inductive-overflow-supertrait-auto-trait.stderr} (85%) create mode 100644 src/test/ui/typeck/issue-80207-unsized-return.rs rename src/test/ui/{issues => unused}/issue-30730.rs (100%) rename src/test/ui/{issues => unused}/issue-30730.stderr (100%) rename src/test/ui/{issues => unused}/issue-46576.rs (91%) rename src/test/ui/{issues => unused}/issue-46576.stderr (80%) rename src/test/ui/{issues => unused}/issue-59896.rs (100%) rename src/test/ui/{issues => unused}/issue-59896.stderr (100%) rename src/test/ui/{issues => unused}/issue-70041.rs (100%) rename src/test/ui/{issues => unused}/issue-70041.stderr (100%) delete mode 100644 src/test/ui/utf8.rs delete mode 100644 src/test/ui/utf8_chars.rs delete mode 100644 src/test/ui/wrapping-int-api.rs create mode 100644 vendor/cfg-if/.cargo-checksum.json create mode 100644 vendor/cfg-if/Cargo.toml rename vendor/{object-0.20.0 => cfg-if}/LICENSE-APACHE (100%) create mode 100644 vendor/cfg-if/LICENSE-MIT create mode 100644 vendor/cfg-if/README.md create mode 100644 vendor/cfg-if/src/lib.rs create mode 100644 vendor/cfg-if/tests/xcrate.rs create mode 100644 vendor/dlmalloc/src/dummy.rs delete mode 100644 vendor/dlmalloc/src/sgx.rs create mode 100644 vendor/gimli/src/read/lists.rs create mode 100644 vendor/gsgdt/.cargo-checksum.json create mode 100644 vendor/gsgdt/Cargo.toml create mode 100644 vendor/gsgdt/LICENSE create mode 100644 vendor/gsgdt/README.md create mode 100644 vendor/gsgdt/src/diff/diff.rs create mode 100644 vendor/gsgdt/src/diff/diff_graph.rs create mode 100644 vendor/gsgdt/src/diff/match_graph.rs create mode 100644 vendor/gsgdt/src/diff/mod.rs create mode 100644 vendor/gsgdt/src/graph.rs create mode 100644 vendor/gsgdt/src/levenshtein.rs create mode 100644 vendor/gsgdt/src/lib.rs create mode 100644 vendor/gsgdt/src/multi_graph.rs create mode 100644 vendor/gsgdt/src/node.rs create mode 100644 vendor/gsgdt/src/util.rs create mode 100644 vendor/gsgdt/tests/graph1.json create mode 100644 vendor/gsgdt/tests/graph2.json create mode 100644 vendor/gsgdt/tests/helpers.rs create mode 100644 vendor/gsgdt/tests/small_graph.json create mode 100644 vendor/gsgdt/tests/test_diff.rs create mode 100644 vendor/gsgdt/tests/test_graph.rs create mode 100644 vendor/gsgdt/tests/test_multigraph.rs mode change 100755 => 100644 vendor/libc/src/vxworks/mod.rs delete mode 100644 vendor/object-0.20.0/.cargo-checksum.json delete mode 100644 vendor/object-0.20.0/Cargo.lock delete mode 100644 vendor/object-0.20.0/README.md delete mode 100644 vendor/object-0.20.0/src/lib.rs delete mode 100644 vendor/object-0.20.0/src/read/coff/symbol.rs delete mode 100644 vendor/object-0.20.0/src/read/macho/symbol.rs create mode 100644 vendor/object/.cargo-checksum.json create mode 100644 vendor/object/Cargo.lock rename vendor/{object-0.20.0 => object}/Cargo.toml (87%) create mode 100644 vendor/object/LICENSE-APACHE rename vendor/{object-0.20.0 => object}/LICENSE-MIT (100%) create mode 100644 vendor/object/README.md create mode 100644 vendor/object/examples/ar.rs rename vendor/{object-0.20.0 => object}/examples/nm.rs (90%) rename vendor/{object-0.20.0 => object}/examples/objcopy.rs (79%) rename vendor/{object-0.20.0 => object}/examples/objdump.rs (86%) create mode 100644 vendor/object/examples/objectmap.rs create mode 100644 vendor/object/src/archive.rs rename vendor/{object-0.20.0 => object}/src/common.rs (85%) rename vendor/{object-0.20.0 => object}/src/elf.rs (99%) rename vendor/{object-0.20.0 => object}/src/endian.rs (100%) create mode 100644 vendor/object/src/lib.rs rename vendor/{object-0.20.0 => object}/src/macho.rs (100%) rename vendor/{object-0.20.0 => object}/src/pe.rs (99%) rename vendor/{object-0.20.0 => object}/src/pod.rs (93%) rename vendor/{object-0.20.0 => object}/src/read/any.rs (66%) create mode 100644 vendor/object/src/read/archive.rs create mode 100644 vendor/object/src/read/coff/comdat.rs rename vendor/{object-0.20.0 => object}/src/read/coff/file.rs (70%) rename vendor/{object-0.20.0 => object}/src/read/coff/mod.rs (89%) rename vendor/{object-0.20.0 => object}/src/read/coff/relocation.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/coff/section.rs (98%) create mode 100644 vendor/object/src/read/coff/symbol.rs create mode 100644 vendor/object/src/read/elf/comdat.rs rename vendor/{object-0.20.0 => object}/src/read/elf/compression.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/elf/file.rs (92%) rename vendor/{object-0.20.0 => object}/src/read/elf/mod.rs (93%) rename vendor/{object-0.20.0 => object}/src/read/elf/note.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/elf/relocation.rs (80%) rename vendor/{object-0.20.0 => object}/src/read/elf/section.rs (99%) rename vendor/{object-0.20.0 => object}/src/read/elf/segment.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/elf/symbol.rs (50%) rename vendor/{object-0.20.0 => object}/src/read/macho/file.rs (72%) rename vendor/{object-0.20.0 => object}/src/read/macho/load_command.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/macho/mod.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/macho/relocation.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/macho/section.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/macho/segment.rs (100%) create mode 100644 vendor/object/src/read/macho/symbol.rs rename vendor/{object-0.20.0 => object}/src/read/mod.rs (72%) rename vendor/{object-0.20.0 => object}/src/read/pe/file.rs (80%) rename vendor/{object-0.20.0 => object}/src/read/pe/mod.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/pe/section.rs (98%) rename vendor/{object-0.20.0 => object}/src/read/traits.rs (57%) rename vendor/{object-0.20.0 => object}/src/read/util.rs (100%) rename vendor/{object-0.20.0 => object}/src/read/wasm.rs (76%) rename vendor/{object-0.20.0 => object}/src/write/coff.rs (87%) rename vendor/{object-0.20.0 => object}/src/write/elf.rs (80%) rename vendor/{object-0.20.0 => object}/src/write/macho.rs (93%) rename vendor/{object-0.20.0 => object}/src/write/mod.rs (93%) rename vendor/{object-0.20.0 => object}/src/write/string.rs (100%) rename vendor/{object-0.20.0 => object}/src/write/util.rs (72%) rename vendor/{object-0.20.0 => object}/tests/integration.rs (100%) rename vendor/{object-0.20.0 => object}/tests/parse_self.rs (100%) rename vendor/{object-0.20.0 => object}/tests/round_trip/bss.rs (91%) create mode 100644 vendor/object/tests/round_trip/comdat.rs rename vendor/{object-0.20.0 => object}/tests/round_trip/common.rs (89%) rename vendor/{object-0.20.0 => object}/tests/round_trip/elf.rs (96%) rename vendor/{object-0.20.0 => object}/tests/round_trip/mod.rs (87%) rename vendor/{object-0.20.0 => object}/tests/round_trip/tls.rs (91%) create mode 100644 vendor/socket2/9f0fbf2.diff create mode 100644 vendor/socket2/TODO create mode 100644 vendor/socket2/TODO.refactor create mode 100755 vendor/socket2/check_targets.bash create mode 100644 vendor/socket2/socket_type.diff diff --git a/Cargo.lock b/Cargo.lock index c72c7b8481..89ac858a61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" +checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" dependencies = [ "compiler_builtins", "gimli", @@ -132,13 +132,13 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.53" +version = "0.3.55" dependencies = [ "addr2line", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.21.1", + "object", "rustc-demangle", ] @@ -295,7 +295,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" [[package]] name = "cargo" -version = "0.50.0" +version = "0.51.0" dependencies = [ "anyhow", "atty", @@ -329,7 +329,7 @@ dependencies = [ "libgit2-sys", "log", "memchr", - "miow 0.3.5", + "miow 0.3.6", "num_cpus", "opener", "openssl", @@ -355,6 +355,35 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cargo-credential" +version = "0.1.0" + +[[package]] +name = "cargo-credential-1password" +version = "0.1.0" +dependencies = [ + "cargo-credential", + "serde", + "serde_json", +] + +[[package]] +name = "cargo-credential-macos-keychain" +version = "0.1.0" +dependencies = [ + "cargo-credential", + "security-framework", +] + +[[package]] +name = "cargo-credential-wincred" +version = "0.1.0" +dependencies = [ + "cargo-credential", + "winapi 0.3.9", +] + [[package]] name = "cargo-miri" version = "0.1.0" @@ -569,6 +598,7 @@ dependencies = [ "quine-mc_cluskey", "quote", "regex-syntax", + "rustc-semver", "semver 0.11.0", "serde", "smallvec 1.4.2", @@ -653,7 +683,7 @@ dependencies = [ "glob", "lazy_static", "libc", - "miow 0.3.5", + "miow 0.3.6", "regex", "rustfix", "serde", @@ -675,7 +705,7 @@ dependencies = [ "getopts", "libc", "log", - "miow 0.3.5", + "miow 0.3.6", "regex", "rustfix", "serde", @@ -721,6 +751,10 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6" +[[package]] +name = "coverage_test_macros" +version = "0.0.0" + [[package]] name = "cpuid-bool" version = "0.1.2" @@ -861,9 +895,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.31" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9447ad28eee2a5cfb031c329d46bef77487244fff6a724b378885b8691a35f78" +checksum = "e268162af1a5fe89917ae25ba3b0a77c8da752bdc58e7dbb4f15b91fbd33756e" dependencies = [ "curl-sys", "libc", @@ -876,9 +910,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.34+curl-7.71.1" +version = "0.4.39+curl-7.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad4eff0be6985b7e709f64b5a541f700e9ad1407190a29f4884319eb663ed1d6" +checksum = "07a8ce861e7b68a0b394e814d7ee9f1b2750ff8bd10372c6ad3bacc10e86f874" dependencies = [ "cc", "libc", @@ -980,9 +1014,9 @@ dependencies = [ [[package]] name = "dlmalloc" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35055b1021724f4eb5262eb49130eebff23fc59fc5a14160e05faad8eeb36673" +checksum = "332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254" dependencies = [ "compiler_builtins", "libc", @@ -1285,9 +1319,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -1296,9 +1330,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.12" +version = "0.13.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" +checksum = "186dd99cc77576e58344ad614fa9bb27bad9d048f85de3ca850c1f4e8b048260" dependencies = [ "bitflags", "libc", @@ -1311,9 +1345,9 @@ dependencies = [ [[package]] name = "git2-curl" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502d532a2d06184beb3bc869d4d90236e60934e3382c921b203fa3c33e212bd7" +checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50" dependencies = [ "curl", "git2", @@ -1340,6 +1374,15 @@ dependencies = [ "regex", ] +[[package]] +name = "gsgdt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825" +dependencies = [ + "serde", +] + [[package]] name = "handlebars" version = "3.4.0" @@ -1716,9 +1759,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.12.14+1.1.0" +version = "0.12.16+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" +checksum = "9f91b2f931ee975a98155195be8cd82d02e8e029d7d793d2bac1b8181ac97020" dependencies = [ "cc", "libc", @@ -1917,17 +1960,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -[[package]] -name = "md-5" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "opaque-debug 0.2.3", -] - [[package]] name = "md-5" version = "0.9.1" @@ -1941,9 +1973,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff" +checksum = "21251d3eb9ca5e8ac5b73384ddaa483a9bbc7d7dcd656b1fa8f266634810334a" dependencies = [ "ammonia", "anyhow", @@ -2058,7 +2090,7 @@ dependencies = [ "kernel32-sys", "libc", "log", - "miow 0.2.1", + "miow 0.2.2", "net2", "slab", "winapi 0.2.8", @@ -2072,7 +2104,7 @@ checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ "log", "mio", - "miow 0.3.5", + "miow 0.3.6", "winapi 0.3.9", ] @@ -2089,9 +2121,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ "kernel32-sys", "net2", @@ -2101,9 +2133,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ "socket2", "winapi 0.3.9", @@ -2124,13 +2156,14 @@ dependencies = [ "rustc-workspace-hack", "rustc_version", "shell-escape", + "smallvec 1.4.2", ] [[package]] name = "net2" -version = "0.2.34" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" +checksum = "d7cf75f38f16cb05ea017784dc6dbfd354f76c223dba37701734c4f5a9337d02" dependencies = [ "cfg-if 0.1.10", "libc", @@ -2174,21 +2207,15 @@ dependencies = [ [[package]] name = "object" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] -[[package]] -name = "object" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693" - [[package]] name = "once_cell" version = "1.4.1" @@ -2324,7 +2351,7 @@ dependencies = [ "futures", "log", "mio-named-pipes", - "miow 0.3.5", + "miow 0.3.6", "rand", "tokio", "tokio-named-pipes", @@ -2693,9 +2720,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.40" +version = "2.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c5fb83bc092c10e12ca863ab8922b1833382d5d248aaafca779886d3396a44" +checksum = "a2f1a4baaaf5c4a9aa30c708c339ae293d02976d2b7f1575a59f44558d25bfea" dependencies = [ "bitflags", "clap", @@ -3016,23 +3043,24 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap", + "env_logger 0.7.1", "mdbook", ] [[package]] name = "rustc-ap-rustc_arena" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "477085eefed2f12085c68577cc3827c8c39a31a4a750978aacb9af10f7903174" +checksum = "81f7b9bc5a6f79b1f230833cb4c8f8928d48c129b21df5b372c202fb826c0b5e" dependencies = [ "smallvec 1.4.2", ] [[package]] name = "rustc-ap-rustc_ast" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4ad5ec25f6b3d122354595be0d1b513f37fca3299d9b448b1db28f4a9e4b12" +checksum = "3d77f313e9f30af93f2737f1a99d6552e26b702c5cef3bb65e35f5b4fe5191f1" dependencies = [ "bitflags", "rustc-ap-rustc_data_structures", @@ -3047,9 +3075,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_passes" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6d8635298d7736decdb3c6e92e784d3eccde557462a9c10ac11a34fec3d756" +checksum = "30408fbf42fa6fbeb383d3fce0f24d2490c3d12527beb2f48e6e728765bc8695" dependencies = [ "itertools 0.9.0", "rustc-ap-rustc_ast", @@ -3066,9 +3094,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_pretty" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a61bdb5252e1a95b7715038949e10f07ce770a436fcd497cdd9bc7255471de9" +checksum = "d47b8a3adcccc204578b0ee9cd2f9952921fa43977f58343913cca04cce87043" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_span", @@ -3078,9 +3106,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_attr" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84520a16cb61bd31e9c27e87eca5d933a9c94ac84f25649bddcc19989275ab2a" +checksum = "66f5f53ecdbf7d8b47905936f93eb1fdae496137e94b7e4023a0b866b0e1a92d" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", @@ -3097,9 +3125,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cb2b6a38759cf7c0c1434c8b4cbfcab9cd24970d05f960f2ca01226ddb4d68" +checksum = "3aa913fa40b90157067b17dd7ddfd5df0d8566e339ffa8351a638bdf3fc7ee81" dependencies = [ "arrayvec", "bitflags", @@ -3128,13 +3156,14 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_errors" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46cfb19536426bf9252827a78552d635be207a4be74f4e92832aad82d7f2135c" +checksum = "5d4b4956287d7c4996409b8362aa69c0c9a6853751ff00ee0a6f78223c5ef3ad" dependencies = [ "annotate-snippets 0.8.0", "atty", "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_lint_defs", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", @@ -3147,9 +3176,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_expand" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6273e60042a0ef31f6cfe783c519873993eb426f055be2bc058a48b6ca3934d0" +checksum = "3fa908bb1b67230dd4309e93edefc6a6c2f3d8b6a195f77c47743c882114a22e" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_passes", @@ -3170,9 +3199,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_feature" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2936e8346157e2848305e509f38aa3ed4e97697975ef68027587f5db6a38703f" +checksum = "d9b7a1db115893ed7ed0db80f70d2246c1709de7854238acde76471495930f2a" dependencies = [ "rustc-ap-rustc_data_structures", "rustc-ap-rustc_span", @@ -3180,21 +3209,21 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_fs_util" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4c3ae17776b5a5aa441ca510a650f75805e1f5569edd231caa8378552195a4" +checksum = "55937887cb606cc72193ea3c5feb8bbbb810d812aa233b9a1e7749155c4a3501" [[package]] name = "rustc-ap-rustc_graphviz" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5611bf0ac0ac49c2a22c959c7d8b17f85f69959293f0e8c4f753eca832fe7ad0" +checksum = "e39e179e616356927f0c4eda43e3a35d88476f91e1ac8e4a0a09661dbab44a6e" [[package]] name = "rustc-ap-rustc_index" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca67cf37c427057192e451c7f912e94ae9a8ca5ad69fd481c011fad3f86982cb" +checksum = "572d3962d6999f3b1a71d335308e939e204339d4ad36e6ebe7a591c9d4329f5d" dependencies = [ "arrayvec", "rustc-ap-rustc_macros", @@ -3203,18 +3232,32 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_lexer" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b04cd2159495584d976d501c5394498470c2e94e4f0cebb8186562d407a678" +checksum = "44bc89d9ca7a78fb82e103b389362c55f03800745f8ba14e068b805cfaf783ec" dependencies = [ "unicode-xid", ] +[[package]] +name = "rustc-ap-rustc_lint_defs" +version = "691.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d39bda92aabd77e49ac8ad5e24fccf9d7245b8ff2bf1249ab98733e2e5a2863" +dependencies = [ + "rustc-ap-rustc_ast", + "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_macros", + "rustc-ap-rustc_serialize", + "rustc-ap-rustc_span", + "tracing", +] + [[package]] name = "rustc-ap-rustc_macros" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ec6d623853449acd3c65050d249d3674edab5f6e4d9f074c7bac183269f9c8" +checksum = "a3295fbc9625197494e356e92d8ac08370eddafa60189861c7b2f084b3b5a6b8" dependencies = [ "proc-macro2", "quote", @@ -3224,9 +3267,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_parse" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca524bafce4b04d2b49fee2d40b4b26c3ebab9f1a4f731fdf561f00617862f02" +checksum = "9ff5d0094396844efead43303a6eb25b8a4962e2c80fb0ea4a86e4101fbfd404" dependencies = [ "bitflags", "rustc-ap-rustc_ast", @@ -3244,9 +3287,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_serialize" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c67920561e58f98c4de864407c92b2dd05ace5d5e5301e17444f10f742c005b7" +checksum = "2d5cff6709a8b51a3730288a9ead17cabe8146b1c787db52298447ef7890140a" dependencies = [ "indexmap", "smallvec 1.4.2", @@ -3254,9 +3297,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_session" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0762fd855792e06ef639327237898e4e092ad68150e6a8e19aeb7dc06276ad7a" +checksum = "36bb15ef12174b5ed6419a7e4260a899ce8927e8c8fd1f0cddf178818737dcdf" dependencies = [ "bitflags", "getopts", @@ -3266,6 +3309,7 @@ dependencies = [ "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_fs_util", + "rustc-ap-rustc_lint_defs", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", @@ -3275,28 +3319,29 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_span" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf3db7b4ca5d21c14c45475df155e5e020c9a3760346945a662c9a9053b49c8" +checksum = "104d349a32be9cfd3d39a5a70ad6c5e682ce262fc5cc8717d35a01e980c0d8b2" dependencies = [ "cfg-if 0.1.10", - "md-5 0.8.0", + "md-5", "rustc-ap-rustc_arena", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "scoped-tls", - "sha-1 0.8.2", + "sha-1 0.9.1", + "sha2", "tracing", "unicode-width", ] [[package]] name = "rustc-ap-rustc_target" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa6560bb9742b276064d67ab9edb5766ecb303f8ae3854835ad3fad4b432188" +checksum = "9d7ac4ded9a6aecb534744c836a160497985f0d53b272581e95e7890d31b9e17" dependencies = [ "bitflags", "rustc-ap-rustc_data_structures", @@ -3356,6 +3401,12 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rustc-semver" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84" + [[package]] name = "rustc-std-workspace-alloc" version = "1.99.0" @@ -3383,6 +3434,8 @@ version = "1.0.0" dependencies = [ "byteorder", "crossbeam-utils 0.7.2", + "libc", + "libz-sys", "proc-macro2", "quote", "serde", @@ -3794,7 +3847,7 @@ dependencies = [ "rustc_target", "rustc_trait_selection", "rustc_traits", - "rustc_ty", + "rustc_ty_utils", "rustc_typeck", "smallvec 1.4.2", "tempfile", @@ -3823,6 +3876,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_middle", + "rustc_parse_format", "rustc_session", "rustc_span", "rustc_target", @@ -3914,6 +3968,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec 1.4.2", "tracing", ] @@ -3922,7 +3977,9 @@ dependencies = [ name = "rustc_mir" version = "0.0.0" dependencies = [ + "coverage_test_macros", "either", + "gsgdt", "itertools 0.9.0", "polonius-engine", "regex", @@ -4006,6 +4063,7 @@ dependencies = [ "rustc_errors", "rustc_hir", "rustc_index", + "rustc_lexer", "rustc_middle", "rustc_serialize", "rustc_session", @@ -4138,7 +4196,7 @@ name = "rustc_span" version = "0.0.0" dependencies = [ "cfg-if 0.1.10", - "md-5 0.9.1", + "md-5", "rustc_arena", "rustc_data_structures", "rustc_index", @@ -4231,7 +4289,7 @@ dependencies = [ ] [[package]] -name = "rustc_ty" +name = "rustc_ty_utils" version = "0.0.0" dependencies = [ "rustc_data_structures", @@ -4246,6 +4304,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "rustc_type_ir" +version = "0.0.0" +dependencies = [ + "bitflags", + "rustc_data_structures", + "rustc_index", + "rustc_serialize", +] + [[package]] name = "rustc_typeck" version = "0.0.0" @@ -4329,7 +4397,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.25" +version = "1.4.30" dependencies = [ "annotate-snippets 0.6.1", "anyhow", @@ -4404,6 +4472,29 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -4451,18 +4542,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.115" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.115" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -4614,9 +4705,9 @@ checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e" [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "7fd8b795c389288baa5f355489c65e71fd48a02104600d15c4cfbc561e9e429d" dependencies = [ "cfg-if 0.1.10", "libc", @@ -4658,7 +4749,7 @@ dependencies = [ "hermit-abi", "libc", "miniz_oxide", - "object 0.20.0", + "object", "panic_abort", "panic_unwind", "profiler_builtins", diff --git a/Cargo.toml b/Cargo.toml index e1a36d8808..204c92045b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ members = [ "src/tools/rust-installer", "src/tools/rust-demangler", "src/tools/cargo", + "src/tools/cargo/crates/credential/cargo-credential-1password", + "src/tools/cargo/crates/credential/cargo-credential-macos-keychain", + "src/tools/cargo/crates/credential/cargo-credential-wincred", "src/tools/rustdoc", "src/tools/rls", "src/tools/rustfmt", diff --git a/RELEASES.md b/RELEASES.md index 8f04980e39..18492213a5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,123 @@ +Version 1.50.0 (2021-02-11) +============================ + +Language +----------------------- +- [You can now use `const` values for `x` in `[x; N]` array expressions.][79270] + This has been technically possible since 1.38.0, as it was unintentionally stabilized. +- [Assignments to `ManuallyDrop` union fields are now considered safe.][78068] + +Compiler +----------------------- +- [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142] +- [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484] +- [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +----------------------- + +- [`proc_macro::Punct` now implements `PartialEq`.][78636] +- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989] +- [On Unix platforms, the `std::fs::File` type now has a "niche" of `-1`.][74699] + This value cannot be a valid file descriptor, and now means `Option` takes + up the same amount of space as `File`. + +Stabilized APIs +--------------- + +- [`bool::then`] +- [`btree_map::Entry::or_insert_with_key`] +- [`f32::clamp`] +- [`f64::clamp`] +- [`hash_map::Entry::or_insert_with_key`] +- [`Ord::clamp`] +- [`RefCell::take`] +- [`slice::fill`] +- [`UnsafeCell::get_mut`] + +The following previously stable methods are now `const`. + +- [`IpAddr::is_ipv4`] +- [`IpAddr::is_ipv6`] +- [`Layout::size`] +- [`Layout::align`] +- [`Layout::from_size_align`] +- `pow` for all integer types. +- `checked_pow` for all integer types. +- `saturating_pow` for all integer types. +- `wrapping_pow` for all integer types. +- `next_power_of_two` for all unsigned integer types. +- `checked_power_of_two` for all unsigned integer types. + +Cargo +----------------------- + +- [Added the `[build.rustc-workspace-wrapper]` option.][cargo/8976] + This option sets a wrapper to execute instead of `rustc`, for workspace members only. +- [`cargo:rerun-if-changed` will now, if provided a directory, scan the entire + contents of that directory for changes.][cargo/8973] +- [Added the `--workspace` flag to the `cargo update` command.][cargo/8725] + +Misc +---- + +- [The search results tab and the help button are focusable with keyboard in rustdoc.][79896] +- [Running tests will now print the total time taken to execute.][75752] + +Compatibility Notes +------------------- + +- [The `compare_and_swap` method on atomics has been deprecated.][79261] It's + recommended to use the `compare_exchange` and `compare_exchange_weak` methods instead. +- [Changes in how `TokenStream`s are checked have fixed some cases where you could write + unhygenic `macro_rules!` macros.][79472] +- [`#![test]` as an inner attribute is now considered unstable like other inner macro + attributes, and reports an error by default through the `soft_unstable` lint.][79003] +- [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864] +- [Dropped support for all cloudabi targets.][78439] +- [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's + recommended to use the `#[panic_handler]` attribute to provide your own implementation. +- [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296] + +[74989]: https://github.com/rust-lang/rust/pull/74989 +[79261]: https://github.com/rust-lang/rust/pull/79261 +[79896]: https://github.com/rust-lang/rust/pull/79896 +[79484]: https://github.com/rust-lang/rust/pull/79484 +[79472]: https://github.com/rust-lang/rust/pull/79472 +[79270]: https://github.com/rust-lang/rust/pull/79270 +[79003]: https://github.com/rust-lang/rust/pull/79003 +[78864]: https://github.com/rust-lang/rust/pull/78864 +[78636]: https://github.com/rust-lang/rust/pull/78636 +[78439]: https://github.com/rust-lang/rust/pull/78439 +[78343]: https://github.com/rust-lang/rust/pull/78343 +[78296]: https://github.com/rust-lang/rust/pull/78296 +[78068]: https://github.com/rust-lang/rust/pull/78068 +[75752]: https://github.com/rust-lang/rust/pull/75752 +[74699]: https://github.com/rust-lang/rust/pull/74699 +[78142]: https://github.com/rust-lang/rust/pull/78142 +[77484]: https://github.com/rust-lang/rust/pull/77484 +[cargo/8976]: https://github.com/rust-lang/cargo/pull/8976 +[cargo/8973]: https://github.com/rust-lang/cargo/pull/8973 +[cargo/8725]: https://github.com/rust-lang/cargo/pull/8725 +[`IpAddr::is_ipv4`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv4 +[`IpAddr::is_ipv6`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv6 +[`Layout::align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.align +[`Layout::from_size_align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.from_size_align +[`Layout::size`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.size +[`Ord::clamp`]: https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html#method.clamp +[`RefCell::take`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.take +[`UnsafeCell::get_mut`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.get_mut +[`bool::then`]: https://doc.rust-lang.org/stable/std/primitive.bool.html#method.then +[`btree_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html#method.or_insert_with_key +[`f32::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.clamp +[`f64::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.clamp +[`hash_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html#method.or_insert_with_key +[`slice::fill`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.fill + + Version 1.49.0 (2020-12-31) ============================ @@ -45,7 +165,6 @@ Libraries - [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109] - [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997] -- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989] Stabilized APIs --------------- @@ -110,7 +229,6 @@ related tools. [76199]: https://github.com/rust-lang/rust/pull/76199 [76119]: https://github.com/rust-lang/rust/pull/76119 [75914]: https://github.com/rust-lang/rust/pull/75914 -[74989]: https://github.com/rust-lang/rust/pull/74989 [79004]: https://github.com/rust-lang/rust/pull/79004 [78676]: https://github.com/rust-lang/rust/pull/78676 [79904]: https://github.com/rust-lang/rust/issues/79904 diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index b76e1e7ce6..f468bad635 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -11,9 +11,13 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] +#![feature(array_value_iter_slice)] #![feature(dropck_eyepatch)] #![feature(new_uninit)] #![feature(maybe_uninit_slice)] +#![feature(array_value_iter)] +#![feature(min_const_generics)] +#![feature(min_specialization)] #![cfg_attr(test, feature(test))] use smallvec::SmallVec; @@ -114,6 +118,72 @@ impl Default for TypedArena { } } +trait IterExt { + fn alloc_from_iter(self, arena: &TypedArena) -> &mut [T]; +} + +impl IterExt for I +where + I: IntoIterator, +{ + #[inline] + default fn alloc_from_iter(self, arena: &TypedArena) -> &mut [T] { + let vec: SmallVec<[_; 8]> = self.into_iter().collect(); + vec.alloc_from_iter(arena) + } +} + +impl IterExt for std::array::IntoIter { + #[inline] + fn alloc_from_iter(self, arena: &TypedArena) -> &mut [T] { + let len = self.len(); + if len == 0 { + return &mut []; + } + // Move the content to the arena by copying and then forgetting it + unsafe { + let start_ptr = arena.alloc_raw_slice(len); + self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len); + mem::forget(self); + slice::from_raw_parts_mut(start_ptr, len) + } + } +} + +impl IterExt for Vec { + #[inline] + fn alloc_from_iter(mut self, arena: &TypedArena) -> &mut [T] { + let len = self.len(); + if len == 0 { + return &mut []; + } + // Move the content to the arena by copying and then forgetting it + unsafe { + let start_ptr = arena.alloc_raw_slice(len); + self.as_ptr().copy_to_nonoverlapping(start_ptr, len); + self.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + } + } +} + +impl IterExt for SmallVec { + #[inline] + fn alloc_from_iter(mut self, arena: &TypedArena) -> &mut [A::Item] { + let len = self.len(); + if len == 0 { + return &mut []; + } + // Move the content to the arena by copying and then forgetting it + unsafe { + let start_ptr = arena.alloc_raw_slice(len); + self.as_ptr().copy_to_nonoverlapping(start_ptr, len); + self.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + } + } +} + impl TypedArena { /// Allocates an object in the `TypedArena`, returning a reference to it. #[inline] @@ -191,19 +261,7 @@ impl TypedArena { #[inline] pub fn alloc_from_iter>(&self, iter: I) -> &mut [T] { assert!(mem::size_of::() != 0); - let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); - if vec.is_empty() { - return &mut []; - } - // Move the content to the arena by copying it and then forgetting - // the content of the SmallVec - unsafe { - let len = vec.len(); - let start_ptr = self.alloc_raw_slice(len); - vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); - vec.set_len(0); - slice::from_raw_parts_mut(start_ptr, len) - } + iter.alloc_from_iter(self) } /// Grows the arena. diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3e953729aa..220bbed7e7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -24,7 +24,7 @@ pub use UnsafeSource::*; use crate::ptr::P; use crate::token::{self, CommentKind, DelimToken}; -use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree}; +use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -39,7 +39,6 @@ use rustc_span::{Span, DUMMY_SP}; use std::cmp::Ordering; use std::convert::TryFrom; use std::fmt; -use std::iter; #[cfg(test)] mod tests; @@ -901,10 +900,39 @@ pub struct Stmt { pub id: NodeId, pub kind: StmtKind, pub span: Span, - pub tokens: Option, } impl Stmt { + pub fn tokens(&self) -> Option<&LazyTokenStream> { + match self.kind { + StmtKind::Local(ref local) => local.tokens.as_ref(), + StmtKind::Item(ref item) => item.tokens.as_ref(), + StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.tokens.as_ref(), + StmtKind::Empty => None, + StmtKind::MacCall(ref mac) => mac.tokens.as_ref(), + } + } + + pub fn tokens_mut(&mut self) -> Option<&mut LazyTokenStream> { + match self.kind { + StmtKind::Local(ref mut local) => local.tokens.as_mut(), + StmtKind::Item(ref mut item) => item.tokens.as_mut(), + StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.tokens.as_mut(), + StmtKind::Empty => None, + StmtKind::MacCall(ref mut mac) => mac.tokens.as_mut(), + } + } + + pub fn set_tokens(&mut self, tokens: Option) { + match self.kind { + StmtKind::Local(ref mut local) => local.tokens = tokens, + StmtKind::Item(ref mut item) => item.tokens = tokens, + StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.tokens = tokens, + StmtKind::Empty => {} + StmtKind::MacCall(ref mut mac) => mac.tokens = tokens, + } + } + pub fn has_trailing_semicolon(&self) -> bool { match &self.kind { StmtKind::Semi(_) => true, @@ -912,18 +940,25 @@ impl Stmt { _ => false, } } + + /// Converts a parsed `Stmt` to a `Stmt` with + /// a trailing semicolon. + /// + /// This only modifies the parsed AST struct, not the attached + /// `LazyTokenStream`. The parser is responsible for calling + /// `CreateTokenStream::add_trailing_semi` when there is actually + /// a semicolon in the tokenstream. pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), StmtKind::MacCall(mac) => { - StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs }| MacCallStmt { - mac, - style: MacStmtStyle::Semicolon, - attrs, + StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs, tokens }| { + MacCallStmt { mac, style: MacStmtStyle::Semicolon, attrs, tokens } })) } kind => kind, }; + self } @@ -963,6 +998,7 @@ pub struct MacCallStmt { pub mac: MacCall, pub style: MacStmtStyle, pub attrs: AttrVec, + pub tokens: Option, } #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)] @@ -988,6 +1024,7 @@ pub struct Local { pub init: Option>, pub span: Span, pub attrs: AttrVec, + pub tokens: Option, } /// An arm of a 'match'. @@ -1192,6 +1229,7 @@ impl Expr { ExprKind::Field(..) => ExprPrecedence::Field, ExprKind::Index(..) => ExprPrecedence::Index, ExprKind::Range(..) => ExprPrecedence::Range, + ExprKind::Underscore => ExprPrecedence::Path, ExprKind::Path(..) => ExprPrecedence::Path, ExprKind::AddrOf(..) => ExprPrecedence::AddrOf, ExprKind::Break(..) => ExprPrecedence::Break, @@ -1324,6 +1362,8 @@ pub enum ExprKind { Index(P, P), /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment). Range(Option>, Option>, RangeLimits), + /// An underscore, used in destructuring assignment to ignore a value. + Underscore, /// Variable reference, possibly containing `::` and/or type /// parameters (e.g., `foo::bar::`). @@ -1473,20 +1513,6 @@ impl MacArgs { } } - /// Tokens together with the delimiters or `=`. - /// Use of this method generally means that something suboptimal or hacky is happening. - pub fn outer_tokens(&self) -> TokenStream { - match *self { - MacArgs::Empty => TokenStream::default(), - MacArgs::Delimited(dspan, delim, ref tokens) => { - TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into() - } - MacArgs::Eq(eq_span, ref tokens) => { - iter::once(TokenTree::token(token::Eq, eq_span)).chain(tokens.trees()).collect() - } - } - } - /// Whether a macro with these arguments needs a semicolon /// when used as a standalone item or statement. pub fn need_semicolon(&self) -> bool { @@ -1842,6 +1868,7 @@ impl UintTy { pub struct AssocTyConstraint { pub id: NodeId, pub ident: Ident, + pub gen_args: Option, pub kind: AssocTyConstraintKind, pub span: Span, } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2ff6573744..19c7c479f0 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -115,6 +115,10 @@ impl NestedMetaItem { pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } + + pub fn name_value_literal_span(&self) -> Option { + self.meta_item()?.name_value_literal_span() + } } impl Attribute { @@ -175,6 +179,22 @@ impl Attribute { pub fn is_value_str(&self) -> bool { self.value_str().is_some() } + + /// This is used in case you want the value span instead of the whole attribute. Example: + /// + /// ```text + /// #[doc(alias = "foo")] + /// ``` + /// + /// In here, it'll return a span for `"foo"`. + pub fn name_value_literal_span(&self) -> Option { + match self.kind { + AttrKind::Normal(ref item, _) => { + item.meta(self.span).and_then(|meta| meta.name_value_literal_span()) + } + AttrKind::DocComment(..) => None, + } + } } impl MetaItem { @@ -227,6 +247,17 @@ impl MetaItem { pub fn is_value_str(&self) -> bool { self.value_str().is_some() } + + /// This is used in case you want the value span instead of the whole attribute. Example: + /// + /// ```text + /// #[doc(alias = "foo")] + /// ``` + /// + /// In here, it'll return a span for `"foo"`. + pub fn name_value_literal_span(&self) -> Option { + Some(self.name_value_literal()?.span) + } } impl AttrItem { diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 6e47ff7d74..8a20dd7968 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -34,7 +34,6 @@ macro_rules! unwrap_or { pub mod util { pub mod classify; pub mod comments; - pub mod lev_distance; pub mod literal; pub mod parser; } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 26097980e8..3889ede7f4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -371,20 +371,15 @@ pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { // The value in `#[key = VALUE]` must be visited as an expression for backward // compatibility, so that macros can be expanded in that position. if !vis.token_visiting_enabled() { - if let Some(TokenTree::Token(token)) = tokens.trees_ref().next() { - if let token::Interpolated(..) = token.kind { - // ^^ Do not `make_mut` unless we have to. - match Lrc::make_mut(&mut tokens.0).get_mut(0) { - Some((TokenTree::Token(token), _spacing)) => match &mut token.kind { - token::Interpolated(nt) => match Lrc::make_mut(nt) { - token::NtExpr(expr) => vis.visit_expr(expr), - t => panic!("unexpected token in key-value attribute: {:?}", t), - }, - t => panic!("unexpected token in key-value attribute: {:?}", t), - }, + match Lrc::make_mut(&mut tokens.0).get_mut(0) { + Some((TokenTree::Token(token), _spacing)) => match &mut token.kind { + token::Interpolated(nt) => match Lrc::make_mut(nt) { + token::NtExpr(expr) => vis.visit_expr(expr), t => panic!("unexpected token in key-value attribute: {:?}", t), - } - } + }, + t => panic!("unexpected token in key-value attribute: {:?}", t), + }, + t => panic!("unexpected token in key-value attribute: {:?}", t), } } } @@ -441,11 +436,14 @@ pub fn noop_flat_map_arm(mut arm: Arm, vis: &mut T) -> SmallVec<[ } pub fn noop_visit_ty_constraint( - AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint, + AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint, vis: &mut T, ) { vis.visit_id(id); vis.visit_ident(ident); + if let Some(ref mut gen_args) = gen_args { + vis.visit_generic_args(gen_args); + } match kind { AssocTyConstraintKind::Equality { ref mut ty } => { vis.visit_ty(ty); @@ -576,13 +574,14 @@ pub fn noop_visit_parenthesized_parameter_data( } pub fn noop_visit_local(local: &mut P, vis: &mut T) { - let Local { id, pat, ty, init, span, attrs } = local.deref_mut(); + let Local { id, pat, ty, init, span, attrs, tokens } = local.deref_mut(); vis.visit_id(id); vis.visit_pat(pat); visit_opt(ty, |ty| vis.visit_ty(ty)); visit_opt(init, |init| vis.visit_expr(init)); vis.visit_span(span); visit_thin_attrs(attrs, vis); + visit_lazy_tts(tokens, vis); } pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { @@ -1232,6 +1231,7 @@ pub fn noop_visit_expr( visit_opt(e1, |e1| vis.visit_expr(e1)); visit_opt(e2, |e2| vis.visit_expr(e2)); } + ExprKind::Underscore => {} ExprKind::Path(qself, path) => { vis.visit_qself(qself); vis.visit_path(path); @@ -1324,16 +1324,12 @@ pub fn noop_filter_map_expr(mut e: P, vis: &mut T) -> Optio } pub fn noop_flat_map_stmt( - Stmt { kind, mut span, mut id, mut tokens }: Stmt, + Stmt { kind, mut span, mut id }: Stmt, vis: &mut T, ) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); vis.visit_span(&mut span); - visit_lazy_tts(&mut tokens, vis); - noop_flat_map_stmt_kind(kind, vis) - .into_iter() - .map(|kind| Stmt { id, kind, span, tokens: tokens.clone() }) - .collect() + noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect() } pub fn noop_flat_map_stmt_kind( @@ -1350,9 +1346,10 @@ pub fn noop_flat_map_stmt_kind( StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), StmtKind::Empty => smallvec![StmtKind::Empty], StmtKind::MacCall(mut mac) => { - let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut(); + let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut(); vis.visit_mac_call(mac_); visit_thin_attrs(attrs, vis); + visit_lazy_tts(tokens, vis); smallvec![StmtKind::MacCall(mac)] } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 2bba7e618c..a74464937c 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -434,7 +434,7 @@ impl Token { || self == &OpenDelim(Paren) } - /// Returns `true` if the token is any literal + /// Returns `true` if the token is any literal. pub fn is_lit(&self) -> bool { match self.kind { Literal(..) => true, @@ -785,13 +785,20 @@ impl Nonterminal { /// See issue #73345 for more details. /// FIXME(#73933): Remove this eventually. pub fn pretty_printing_compatibility_hack(&self) -> bool { - if let NtItem(item) = self { - let name = item.ident.name; - if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack { - if let ast::ItemKind::Enum(enum_def, _) = &item.kind { - if let [variant] = &*enum_def.variants { - return variant.ident.name == sym::Input; - } + let item = match self { + NtItem(item) => item, + NtStmt(stmt) => match &stmt.kind { + ast::StmtKind::Item(item) => item, + _ => return false, + }, + _ => return false, + }; + + let name = item.ident.name; + if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack { + if let ast::ItemKind::Enum(enum_def, _) = &item.kind { + if let [variant] = &*enum_def.variants { + return variant.ident.name == sym::Input; } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 1e7001c2b2..b2207f2281 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -121,10 +121,14 @@ where } pub trait CreateTokenStream: sync::Send + sync::Sync { + fn add_trailing_semi(&self) -> Box; fn create_token_stream(&self) -> TokenStream; } impl CreateTokenStream for TokenStream { + fn add_trailing_semi(&self) -> Box { + panic!("Cannot call `add_trailing_semi` on a `TokenStream`!"); + } fn create_token_stream(&self) -> TokenStream { self.clone() } @@ -141,6 +145,13 @@ impl LazyTokenStream { LazyTokenStream(Lrc::new(Box::new(inner))) } + /// Extends the captured stream by one token, + /// which must be a trailing semicolon. This + /// affects the `TokenStream` created by `make_tokenstream`. + pub fn add_trailing_semi(&self) -> LazyTokenStream { + LazyTokenStream(Lrc::new(self.0.add_trailing_semi())) + } + pub fn create_token_stream(&self) -> TokenStream { self.0.create_token_stream() } @@ -221,7 +232,7 @@ impl TokenStream { } } if let Some((pos, comma, sp)) = suggestion { - let mut new_stream = vec![]; + let mut new_stream = Vec::with_capacity(self.0.len() + 1); let parts = self.0.split_at(pos + 1); new_stream.extend_from_slice(parts.0); new_stream.push(comma); diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index e97c8cc456..5d994c9037 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -25,9 +25,8 @@ pub struct Comment { /// Makes a doc string more presentable to users. /// Used by rustdoc and perhaps other tools, but not by rustc. -pub fn beautify_doc_string(data: Symbol) -> String { - /// remove whitespace-only lines from the start/end of lines - fn vertical_trim(lines: Vec) -> Vec { +pub fn beautify_doc_string(data: Symbol) -> Symbol { + fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> { let mut i = 0; let mut j = lines.len(); // first line of all-stars should be omitted @@ -47,55 +46,58 @@ pub fn beautify_doc_string(data: Symbol) -> String { j -= 1; } - lines[i..j].to_vec() + if i != 0 || j != lines.len() { Some((i, j)) } else { None } } - /// remove a "[ \t]*\*" block from each line, if possible - fn horizontal_trim(lines: Vec) -> Vec { + fn get_horizontal_trim(lines: &[&str]) -> Option { let mut i = usize::MAX; - let mut can_trim = true; let mut first = true; - for line in &lines { + for line in lines { for (j, c) in line.chars().enumerate() { if j > i || !"* \t".contains(c) { - can_trim = false; - break; + return None; } if c == '*' { if first { i = j; first = false; } else if i != j { - can_trim = false; + return None; } break; } } if i >= line.len() { - can_trim = false; - } - if !can_trim { - break; + return None; } } + Some(i) + } - if can_trim { - lines.iter().map(|line| (&line[i + 1..line.len()]).to_string()).collect() + let data_s = data.as_str(); + if data_s.contains('\n') { + let mut lines = data_s.lines().collect::>(); + let mut changes = false; + let lines = if let Some((i, j)) = get_vertical_trim(&lines) { + changes = true; + // remove whitespace-only lines from the start/end of lines + &mut lines[i..j] } else { - lines + &mut lines + }; + if let Some(horizontal) = get_horizontal_trim(&lines) { + changes = true; + // remove a "[ \t]*\*" block from each line, if possible + for line in lines.iter_mut() { + *line = &line[horizontal + 1..]; + } + } + if changes { + return Symbol::intern(&lines.join("\n")); } } - - let data = data.as_str(); - if data.contains('\n') { - let lines = data.lines().map(|s| s.to_string()).collect::>(); - let lines = vertical_trim(lines); - let lines = horizontal_trim(lines); - lines.join("\n") - } else { - data.to_string() - } + data } /// Returns `None` if the first `col` chars of `s` contain a non-whitespace char. diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs index e19198f863..98ab653e45 100644 --- a/compiler/rustc_ast/src/util/comments/tests.rs +++ b/compiler/rustc_ast/src/util/comments/tests.rs @@ -6,7 +6,7 @@ fn test_block_doc_comment_1() { with_default_session_globals(|| { let comment = "\n * Test \n ** Test\n * Test\n"; let stripped = beautify_doc_string(Symbol::intern(comment)); - assert_eq!(stripped, " Test \n* Test\n Test"); + assert_eq!(stripped.as_str(), " Test \n* Test\n Test"); }) } @@ -15,7 +15,7 @@ fn test_block_doc_comment_2() { with_default_session_globals(|| { let comment = "\n * Test\n * Test\n"; let stripped = beautify_doc_string(Symbol::intern(comment)); - assert_eq!(stripped, " Test\n Test"); + assert_eq!(stripped.as_str(), " Test\n Test"); }) } @@ -24,7 +24,7 @@ fn test_block_doc_comment_3() { with_default_session_globals(|| { let comment = "\n let a: *i32;\n *a = 5;\n"; let stripped = beautify_doc_string(Symbol::intern(comment)); - assert_eq!(stripped, " let a: *i32;\n *a = 5;"); + assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;"); }) } @@ -32,12 +32,12 @@ fn test_block_doc_comment_3() { fn test_line_doc_comment() { with_default_session_globals(|| { let stripped = beautify_doc_string(Symbol::intern(" test")); - assert_eq!(stripped, " test"); + assert_eq!(stripped.as_str(), " test"); let stripped = beautify_doc_string(Symbol::intern("! test")); - assert_eq!(stripped, "! test"); + assert_eq!(stripped.as_str(), "! test"); let stripped = beautify_doc_string(Symbol::intern("test")); - assert_eq!(stripped, "test"); + assert_eq!(stripped.as_str(), "test"); let stripped = beautify_doc_string(Symbol::intern("!test")); - assert_eq!(stripped, "!test"); + assert_eq!(stripped.as_str(), "!test"); }) } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 49b521afcd..a420bb5635 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -485,6 +485,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>( constraint: &'a AssocTyConstraint, ) { visitor.visit_ident(constraint.ident); + if let Some(ref gen_args) = constraint.gen_args { + visitor.visit_generic_args(gen_args.span(), gen_args); + } match constraint.kind { AssocTyConstraintKind::Equality { ref ty } => { visitor.visit_ty(ty); @@ -686,7 +689,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr), StmtKind::Empty => {} StmtKind::MacCall(ref mac) => { - let MacCallStmt { ref mac, style: _, ref attrs } = **mac; + let MacCallStmt { ref mac, style: _, ref attrs, tokens: _ } = **mac; visitor.visit_mac_call(mac); for attr in attrs.iter() { visitor.visit_attribute(attr); @@ -806,6 +809,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_expr, start); walk_list!(visitor, visit_expr, end); } + ExprKind::Underscore => {} ExprKind::Path(ref maybe_qself, ref path) => { if let Some(ref qself) = *maybe_qself { visitor.visit_ty(&qself.ty); @@ -902,7 +906,6 @@ pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) { token::NtExpr(expr) => visitor.visit_expr(expr), t => panic!("unexpected token in key-value attribute: {:?}", t), }, - token::Literal(..) | token::Ident(..) => {} t => panic!("unexpected token in key-value attribute: {:?}", t), }, t => panic!("unexpected token in key-value attribute: {:?}", t), diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 330776fc8c..9b1642df11 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -164,6 +164,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Range(ref e1, ref e2, lims) => { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) } + ExprKind::Underscore => { + self.sess + .struct_span_err( + e.span, + "in expressions, `_` can only be used on the left-hand side of an assignment", + ) + .span_label(e.span, "`_` not allowed here") + .emit(); + hir::ExprKind::Err + } ExprKind::Path(ref qself, ref path) => { let qpath = self.lower_qpath( e.id, @@ -337,13 +347,12 @@ impl<'hir> LoweringContext<'_, 'hir> { // `_ => else_block` where `else_block` is `{}` if there's `None`: let else_pat = self.pat_wild(span); let (else_expr, contains_else_clause) = match else_opt { - None => (self.expr_block_empty(span), false), + None => (self.expr_block_empty(span.shrink_to_hi()), false), Some(els) => (self.lower_expr(els), true), }; let else_arm = self.arm(else_pat, else_expr); // Handle then + scrutinee: - let then_expr = self.lower_block_expr(then); let (then_pat, scrutinee, desugar) = match cond.kind { // ` => `: ExprKind::Let(ref pat, ref scrutinee) => { @@ -365,6 +374,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (pat, cond, hir::MatchSource::IfDesugar { contains_else_clause }) } }; + let then_expr = self.lower_block_expr(then); let then_arm = self.arm(then_pat, self.arena.alloc(then_expr)); hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar) @@ -390,7 +400,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }; // Handle then + scrutinee: - let then_expr = self.lower_block_expr(body); let (then_pat, scrutinee, desugar, source) = match cond.kind { ExprKind::Let(ref pat, ref scrutinee) => { // to: @@ -430,6 +439,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While) } }; + let then_expr = self.lower_block_expr(body); let then_arm = self.arm(then_pat, self.arena.alloc(then_expr)); // `match { ... }` @@ -495,14 +505,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { + let pat = self.lower_pat(&arm.pat); + let guard = arm.guard.as_ref().map(|cond| { + if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind { + hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee)) + } else { + hir::Guard::If(self.lower_expr(cond)) + } + }); hir::Arm { hir_id: self.next_id(), attrs: self.lower_attrs(&arm.attrs), - pat: self.lower_pat(&arm.pat), - guard: match arm.guard { - Some(ref x) => Some(hir::Guard::If(self.lower_expr(x))), - _ => None, - }, + pat, + guard, body: self.lower_expr(&arm.body), span: arm.span, } @@ -863,7 +878,10 @@ impl<'hir> LoweringContext<'_, 'hir> { // Return early in case of an ordinary assignment. fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool { match &lhs.kind { - ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false, + ExprKind::Array(..) + | ExprKind::Struct(..) + | ExprKind::Tup(..) + | ExprKind::Underscore => false, // Check for tuple struct constructor. ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(), ExprKind::Paren(e) => { @@ -943,6 +961,10 @@ impl<'hir> LoweringContext<'_, 'hir> { assignments: &mut Vec>, ) -> &'hir hir::Pat<'hir> { match &lhs.kind { + // Underscore pattern. + ExprKind::Underscore => { + return self.pat_without_dbm(lhs.span, hir::PatKind::Wild); + } // Slice patterns. ExprKind::Array(elements) => { let (pats, rest) = @@ -1290,7 +1312,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) } } }; - Some(op) + Some((op, *op_sp)) }) .collect(); @@ -1309,7 +1331,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } = *p { let op_sp = asm.operands[operand_idx].1; - match &operands[operand_idx] { + match &operands[operand_idx].0 { hir::InlineAsmOperand::In { reg, .. } | hir::InlineAsmOperand::Out { reg, .. } | hir::InlineAsmOperand::InOut { reg, .. } @@ -1367,14 +1389,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut used_input_regs = FxHashMap::default(); let mut used_output_regs = FxHashMap::default(); - for (idx, op) in operands.iter().enumerate() { - let op_sp = asm.operands[idx].1; + let mut required_features: Vec<&str> = vec![]; + for (idx, &(ref op, op_sp)) in operands.iter().enumerate() { if let Some(reg) = op.reg() { + // Make sure we don't accidentally carry features from the + // previous iteration. + required_features.clear(); + // Validate register classes against currently enabled target // features. We check that at least one type is available for // the current target. let reg_class = reg.reg_class(); - let mut required_features: Vec<&str> = vec![]; for &(_, feature) in reg_class.supported_types(asm_arch) { if let Some(feature) = feature { if self.sess.target_features.contains(&Symbol::intern(feature)) { @@ -1437,8 +1462,7 @@ impl<'hir> LoweringContext<'_, 'hir> { skip = true; let idx2 = *o.get(); - let op2 = &operands[idx2]; - let op_sp2 = asm.operands[idx2].1; + let &(ref op2, op_sp2) = &operands[idx2]; let reg2 = match op2.reg() { Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r, _ => unreachable!(), diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d353bc19f7..eef6d38aa0 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -43,6 +43,7 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { items: BTreeSet::new(), trait_items: BTreeSet::new(), impl_items: BTreeSet::new(), + foreign_items: BTreeSet::new(), }, ); @@ -105,6 +106,18 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { visit::walk_assoc_item(self, item, ctxt); } + + fn visit_foreign_item(&mut self, item: &'a ForeignItem) { + self.lctx.allocate_hir_id_counter(item.id); + self.lctx.with_hir_id_owner(item.id, |lctx| { + let hir_item = lctx.lower_foreign_item(item); + let id = hir::ForeignItemId { hir_id: hir_item.hir_id }; + lctx.foreign_items.insert(id, hir_item); + lctx.modules.get_mut(&lctx.current_module).unwrap().foreign_items.insert(id); + }); + + visit::walk_foreign_item(self, item); + } } impl<'hir> LoweringContext<'_, 'hir> { @@ -304,7 +317,12 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), - ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)), + ItemKind::ForeignMod(ref fm) => hir::ItemKind::ForeignMod { + abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)), + items: self + .arena + .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), + }, ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)), ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => { // We lower @@ -704,10 +722,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod<'hir> { - hir::ForeignMod { - abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)), - items: self.arena.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item(x))), + fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef<'hir> { + hir::ForeignItemRef { + id: hir::ForeignItemId { hir_id: self.lower_node_id(i.id) }, + ident: i.ident, + span: i.span, + vis: self.lower_visibility(&i.vis, Some(i.id)), } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 549b66e2d3..2e1b5a74a7 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -53,7 +53,6 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_session::config::nightly_options; use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::ParseSess; use rustc_session::Session; @@ -102,6 +101,7 @@ struct LoweringContext<'a, 'hir: 'a> { trait_items: BTreeMap>, impl_items: BTreeMap>, + foreign_items: BTreeMap>, bodies: BTreeMap>, exported_macros: Vec>, non_exported_macro_attrs: Vec, @@ -299,6 +299,7 @@ pub fn lower_crate<'a, 'hir>( items: BTreeMap::new(), trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), + foreign_items: BTreeMap::new(), bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), modules: BTreeMap::new(), @@ -426,7 +427,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// declared for every type and trait definition. struct MiscCollector<'tcx, 'lowering, 'hir> { lctx: &'tcx mut LoweringContext<'lowering, 'hir>, - hir_id_owner: Option, } impl MiscCollector<'_, '_, '_> { @@ -453,30 +453,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - - fn with_hir_id_owner( - &mut self, - owner: Option, - f: impl FnOnce(&mut Self) -> T, - ) -> T { - let old = mem::replace(&mut self.hir_id_owner, owner); - let r = f(self); - self.hir_id_owner = old; - r - } } impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> { - fn visit_pat(&mut self, p: &'tcx Pat) { - if let PatKind::Paren(..) | PatKind::Rest = p.kind { - // Doesn't generate a HIR node - } else if let Some(owner) = self.hir_id_owner { - self.lctx.lower_node_id_with_owner(p.id, owner); - } - - visit::walk_pat(self, p) - } - fn visit_item(&mut self, item: &'tcx Item) { let hir_id = self.lctx.allocate_hir_id_counter(item.id); @@ -500,24 +479,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => {} } - self.with_hir_id_owner(Some(item.id), |this| { - visit::walk_item(this, item); - }); + visit::walk_item(self, item); } fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) { self.lctx.allocate_hir_id_counter(item.id); - let owner = match (&item.kind, ctxt) { - // Ignore patterns in trait methods without bodies. - (AssocItemKind::Fn(_, _, _, None), AssocCtxt::Trait) => None, - _ => Some(item.id), - }; - self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt)); + visit::walk_assoc_item(self, item, ctxt); } - fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { - // Ignore patterns in foreign items - self.with_hir_id_owner(None, |this| visit::walk_foreign_item(this, i)); + fn visit_foreign_item(&mut self, item: &'tcx ForeignItem) { + self.lctx.allocate_hir_id_counter(item.id); + visit::walk_foreign_item(self, item); } fn visit_ty(&mut self, t: &'tcx Ty) { @@ -528,18 +500,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Mirrors visit::walk_fn_decl for parameter in &f.decl.inputs { // We don't lower the ids of argument patterns - self.with_hir_id_owner(None, |this| { - this.visit_pat(¶meter.pat); - }); + self.visit_pat(¶meter.pat); self.visit_ty(¶meter.ty) } self.visit_fn_ret_ty(&f.decl.output) } TyKind::ImplTrait(def_node_id, _) => { self.lctx.allocate_hir_id_counter(def_node_id); - self.with_hir_id_owner(Some(def_node_id), |this| { - visit::walk_ty(this, t); - }); + visit::walk_ty(self, t); } _ => visit::walk_ty(self, t), } @@ -549,7 +517,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_node_id(CRATE_NODE_ID); debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == Some(hir::CRATE_HIR_ID)); - visit::walk_crate(&mut MiscCollector { lctx: &mut self, hir_id_owner: None }, c); + visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c); let module = self.lower_mod(&c.module); @@ -587,6 +555,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { items: self.items, trait_items: self.trait_items, impl_items: self.impl_items, + foreign_items: self.foreign_items, bodies: self.bodies, body_ids, trait_impls: self.trait_impls, @@ -1039,6 +1008,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); + if let Some(ref gen_args) = constraint.gen_args { + self.sess.span_fatal( + gen_args.span(), + "generic associated types in trait paths are currently not implemented", + ); + } + let kind = match constraint.kind { AssocTyConstraintKind::Equality { ref ty } => { hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) } @@ -1398,8 +1374,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { "`impl Trait` not allowed outside of {}", allowed_in, ); - if pos == ImplTraitPosition::Binding && nightly_options::is_nightly_build() - { + if pos == ImplTraitPosition::Binding && self.sess.is_nightly_build() { err.help( "add `#![feature(impl_trait_in_bindings)]` to the crate \ attributes to enable", @@ -2011,17 +1986,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // For the "output" lifetime parameters, we just want to // generate `'_`. - let mut generic_args: Vec<_> = lifetime_params[..input_lifetimes_count] - .iter() - .map(|&(span, hir_name)| { + let mut generic_args = Vec::with_capacity(lifetime_params.len()); + generic_args.extend(lifetime_params[..input_lifetimes_count].iter().map( + |&(span, hir_name)| { // Input lifetime like `'a` or `'1`: GenericArg::Lifetime(hir::Lifetime { hir_id: self.next_id(), span, name: hir::LifetimeName::Param(hir_name), }) - }) - .collect(); + }, + )); generic_args.extend(lifetime_params[input_lifetimes_count..].iter().map(|&(span, _)| // Output lifetime like `'_`. GenericArg::Lifetime(hir::Lifetime { @@ -2312,29 +2287,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_block_noalloc(&mut self, b: &Block, targeted_by_break: bool) -> hir::Block<'hir> { - let mut stmts = vec![]; let mut expr: Option<&'hir _> = None; - for (index, stmt) in b.stmts.iter().enumerate() { - if index == b.stmts.len() - 1 { - if let StmtKind::Expr(ref e) = stmt.kind { - expr = Some(self.lower_expr(e)); - } else { - stmts.extend(self.lower_stmt(stmt)); - } - } else { - stmts.extend(self.lower_stmt(stmt)); - } - } + let stmts = self.arena.alloc_from_iter( + b.stmts + .iter() + .enumerate() + .filter_map(|(index, stmt)| { + if index == b.stmts.len() - 1 { + if let StmtKind::Expr(ref e) = stmt.kind { + expr = Some(self.lower_expr(e)); + None + } else { + Some(self.lower_stmt(stmt)) + } + } else { + Some(self.lower_stmt(stmt)) + } + }) + .flatten(), + ); + let rules = self.lower_block_check_mode(&b.rules); + let hir_id = self.lower_node_id(b.id); - hir::Block { - hir_id: self.lower_node_id(b.id), - stmts: self.arena.alloc_from_iter(stmts), - expr, - rules: self.lower_block_check_mode(&b.rules), - span: b.span, - targeted_by_break, - } + hir::Block { hir_id, stmts, expr, rules, span: b.span, targeted_by_break } } /// Lowers a block directly to an expression, presuming that it diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bb1d2967d6..bf6d332217 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -400,7 +400,7 @@ impl<'a> AstValidator<'a> { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); self.err_handler() - .struct_span_err(span, "`default` is only allowed on items in `impl` definitions") + .struct_span_err(span, "`default` is only allowed on items in trait impls") .span_label(def_span, "`default` because of this") .emit(); } @@ -522,7 +522,7 @@ impl<'a> AstValidator<'a> { self.err_handler() .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers") .span_label(self.current_extern_span(), "in this `extern` block") - .span_suggestion( + .span_suggestion_verbose( span.until(ident.span.shrink_to_lo()), "remove the qualifiers", "fn ".to_string(), @@ -1372,16 +1372,18 @@ fn deny_equality_constraints( if param.ident == *ident { let param = ident; match &full_path.segments[qself.position..] { - [PathSegment { ident, .. }] => { + [PathSegment { ident, args, .. }] => { // Make a new `Path` from `foo::Bar` to `Foo`. let mut assoc_path = full_path.clone(); // Remove `Bar` from `Foo::Bar`. assoc_path.segments.pop(); let len = assoc_path.segments.len() - 1; + let gen_args = args.as_ref().map(|p| (**p).clone()); // Build ``. let arg = AngleBracketedArg::Constraint(AssocTyConstraint { id: rustc_ast::node_id::DUMMY_NODE_ID, ident: *ident, + gen_args, kind: AssocTyConstraintKind::Equality { ty: predicate.rhs_ty.clone(), }, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2831675cb3..bb22267523 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -370,7 +370,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { gate_feature_post!( &self, - optin_builtin_traits, + auto_traits, i.span, "auto traits are experimental and possibly buggy" ); @@ -620,7 +620,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { } }; } - gate_all!(if_let_guard, "`if let` guard is not implemented"); + gate_all!(if_let_guard, "`if let` guards are experimental"); gate_all!(let_chains, "`let` expressions in this position are experimental"); gate_all!(async_closure, "async closures are unstable"); gate_all!(generators, "yield syntax is experimental"); @@ -630,7 +630,15 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_trait_impl, "const trait impls are experimental"); gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); gate_all!(inline_const, "inline-const is experimental"); - gate_all!(destructuring_assignment, "destructuring assignments are unstable"); + gate_all!( + extended_key_value_attributes, + "arbitrary expressions in key-value attributes are unstable" + ); + if sess.parse_sess.span_diagnostic.err_count() == 0 { + // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is + // involved, so we only emit errors where there are no other parsing errors. + gate_all!(destructuring_assignment, "destructuring assignments are unstable"); + } // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index bfe3044198..7487421e70 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -6,6 +6,7 @@ #![feature(bindings_after_at)] #![feature(iter_is_partitioned)] +#![recursion_limit = "256"] pub mod ast_validation; pub mod feature_gate; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a566200c33..dcb6e115ed 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -109,7 +109,6 @@ pub fn print_crate<'a>( ann: &'a dyn PpAnn, is_expanded: bool, edition: Edition, - has_injected_crate: bool, ) -> String { let mut s = State { s: pp::mk_printer(), @@ -119,7 +118,7 @@ pub fn print_crate<'a>( insert_extra_parens: true, }; - if is_expanded && has_injected_crate { + if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. // However, we don't want these attributes in the AST because @@ -2068,6 +2067,7 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(e, fake_prec); } } + ast::ExprKind::Underscore => self.s.word("_"), ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0), ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true), ast::ExprKind::Break(opt_label, ref opt_expr) => { @@ -2327,11 +2327,12 @@ impl<'a> State<'a> { self.print_path(path, false, depth); } self.s.word(">"); - self.s.word("::"); - let item_segment = path.segments.last().unwrap(); - self.print_ident(item_segment.ident); - if let Some(ref args) = item_segment.args { - self.print_generic_args(args, colons_before_params) + for item_segment in &path.segments[qself.position..] { + self.s.word("::"); + self.print_ident(item_segment.ident); + if let Some(ref args) = item_segment.args { + self.print_generic_args(args, colons_before_params) + } } } @@ -2419,7 +2420,15 @@ impl<'a> State<'a> { if mutbl == ast::Mutability::Mut { self.s.word("mut "); } - self.print_pat(inner); + if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) = + inner.kind + { + self.popen(); + self.print_pat(inner); + self.pclose(); + } else { + self.print_pat(inner); + } } PatKind::Lit(ref e) => self.print_expr(&**e), PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => { diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2fd625c2a6..ead90f23ce 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -67,7 +67,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { } } -#[derive(Clone, PartialEq, Encodable, Decodable)] +#[derive(Copy, Clone, PartialEq, Encodable, Decodable)] pub enum InlineAttr { None, Hint, @@ -294,7 +294,7 @@ where or \"none\"", ) .span_label( - mi.name_value_literal().unwrap().span, + mi.name_value_literal_span().unwrap(), msg, ) .emit(); @@ -621,7 +621,7 @@ pub fn eval_condition( } } -#[derive(Encodable, Decodable, Clone, HashStable_Generic)] +#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic)] pub struct Deprecation { pub since: Option, /// The note to issue a reason. diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 5bfd8a2bf5..bb6d3f6a00 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,8 +1,8 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, TokenKind}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; +use rustc_ast::token; +use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; use rustc_expand::base::*; @@ -26,31 +26,39 @@ pub fn expand_assert<'cx>( // `core::panic` and `std::panic` are different macros, so we use call-site // context to pick up whichever is currently in scope. let sp = cx.with_call_site_ctxt(sp); - let tokens = custom_message.unwrap_or_else(|| { - TokenStream::from(TokenTree::token( - TokenKind::lit( - token::Str, + + let panic_call = if let Some(tokens) = custom_message { + // Pass the custom message to panic!(). + cx.expr( + sp, + ExprKind::MacCall(MacCall { + path: Path::from_ident(Ident::new(sym::panic, sp)), + args: P(MacArgs::Delimited( + DelimSpan::from_single(sp), + MacDelimiter::Parenthesis, + tokens, + )), + prior_type_ascription: None, + }), + ) + } else { + // Pass our own message directly to $crate::panicking::panic(), + // because it might contain `{` and `}` that should always be + // passed literally. + cx.expr_call_global( + sp, + cx.std_path(&[sym::panicking, sym::panic]), + vec![cx.expr_str( + DUMMY_SP, Symbol::intern(&format!( "assertion failed: {}", pprust::expr_to_string(&cond_expr).escape_debug() )), - None, - ), - DUMMY_SP, - )) - }); - let args = P(MacArgs::Delimited(DelimSpan::from_single(sp), MacDelimiter::Parenthesis, tokens)); - let panic_call = MacCall { - path: Path::from_ident(Ident::new(sym::panic, sp)), - args, - prior_type_ascription: None, + )], + ) }; - let if_expr = cx.expr_if( - sp, - cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), - cx.expr(sp, ExprKind::MacCall(panic_call)), - None, - ); + let if_expr = + cx.expr_if(sp, cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), panic_call, None); MacEager::expr(if_expr) } diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 75f4b07764..09ed1af345 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -1,7 +1,7 @@ //! Implementation of the `#[cfg_accessible(path)]` attribute macro. use rustc_ast as ast; -use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; +use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_span::symbol::sym; @@ -31,7 +31,7 @@ impl MultiItemModifier for Expander { fn expand( &self, ecx: &mut ExtCtxt<'_>, - _span: Span, + span: Span, meta_item: &ast::MetaItem, item: Annotatable, ) -> ExpandResult, Annotatable> { @@ -49,11 +49,14 @@ impl MultiItemModifier for Expander { None => return ExpandResult::Ready(Vec::new()), }; - let failure_msg = "cannot determine whether the path is accessible or not"; match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) { Ok(true) => ExpandResult::Ready(vec![item]), Ok(false) => ExpandResult::Ready(Vec::new()), - Err(_) => ExpandResult::Retry(item, failure_msg.into()), + Err(Indeterminate) if ecx.force_mode => { + ecx.span_err(span, "cannot determine whether the path is accessible or not"); + ExpandResult::Ready(vec![item]) + } + Err(Indeterminate) => ExpandResult::Retry(item), } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index d84b395647..5c21329069 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -66,7 +66,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> let fmt = substr.nonself_args[0].clone(); - let mut stmts = vec![]; + let mut stmts = Vec::with_capacity(fields.len() + 2); match vdata { ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { // tuple struct/"normal" variant @@ -132,6 +132,7 @@ fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P) -> as id: ast::DUMMY_NODE_ID, span: sp, attrs: ast::AttrVec::new(), + tokens: None, }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp, tokens: None } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 0642edff6b..6531e68be9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -257,7 +257,10 @@ pub struct Substructure<'a> { pub type_ident: Ident, /// ident of the method pub method_ident: Ident, - /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments + /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)][ptr]` arguments + /// + /// [`Self_`]: ty::Ty::Self_ + /// [ptr]: ty::Ty::Ptr pub self_args: &'a [P], /// verbatim access to any other arguments pub nonself_args: &'a [P], @@ -407,13 +410,7 @@ impl<'a> TraitDef<'a> { _ => false, }) } - _ => { - // Non-ADT derive is an error, but it should have been - // set earlier; see - // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment() - // librustc_expand/base.rs:Annotatable::derive_allowed() - return; - } + _ => unreachable!(), }; let container_id = cx.current_expansion.id.expn_data().parent; let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); @@ -475,12 +472,7 @@ impl<'a> TraitDef<'a> { ); push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() }))) } - _ => { - // Non-Item derive is an error, but it should have been - // set earlier; see - // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment() - // librustc_expand/base.rs:Annotatable::derive_allowed() - } + _ => unreachable!(), } } @@ -608,10 +600,7 @@ impl<'a> TraitDef<'a> { let mut ty_params = params .iter() - .filter_map(|param| match param.kind { - ast::GenericParamKind::Type { .. } => Some(param), - _ => None, - }) + .filter(|param| matches!(param.kind, ast::GenericParamKind::Type{..})) .peekable(); if ty_params.peek().is_some() { diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index bf95093492..1651180817 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -54,7 +54,26 @@ impl MultiItemModifier for BuiltinDerive { // so we are doing it here in a centralized way. let span = ecx.with_def_site_ctxt(span); let mut items = Vec::new(); - (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); + match item { + Annotatable::Stmt(stmt) => { + if let ast::StmtKind::Item(item) = stmt.into_inner().kind { + (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| { + // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' + // to the function + items.push(Annotatable::Stmt(P(ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Item(a.expect_item()), + span, + }))); + }); + } else { + unreachable!("should have already errored on non-item statement") + } + } + _ => { + (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); + } + } ExpandResult::Ready(items) } } @@ -98,13 +117,7 @@ fn inject_impl_of_structural_trait( ) { let item = match *item { Annotatable::Item(ref item) => item, - _ => { - // Non-Item derive is an error, but it should have been - // set earlier; see - // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment() - // librustc_expand/base.rs:Annotatable::derive_allowed() - return; - } + _ => unreachable!(), }; let generics = match item.kind { diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index b69b00d65f..f00dfd1241 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -649,17 +649,13 @@ pub mod shell { impl<'a> Iterator for Substitutions<'a> { type Item = Substitution<'a>; fn next(&mut self) -> Option { - match parse_next_substitution(self.s) { - Some((mut sub, tail)) => { - self.s = tail; - if let Some(InnerSpan { start, end }) = sub.position() { - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; - } - Some(sub) - } - None => None, + let (mut sub, tail) = parse_next_substitution(self.s)?; + self.s = tail; + if let Some(InnerSpan { start, end }) = sub.position() { + sub.set_position(start + self.pos, end + self.pos); + self.pos += end; } + Some(sub) } fn size_hint(&self) -> (usize, Option) { diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 8478fcfbf0..e976805d9d 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -4,7 +4,7 @@ use rustc_ast::expand::allocator::{ AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS, }; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param}; +use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind}; use rustc_ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -14,7 +14,7 @@ pub fn expand( ecx: &mut ExtCtxt<'_>, _span: Span, meta_item: &ast::MetaItem, - item: Annotatable, + mut item: Annotatable, ) -> Vec { check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator); @@ -22,6 +22,17 @@ pub fn expand( ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics"); vec![item] }; + let orig_item = item.clone(); + let mut is_stmt = false; + + // Allow using `#[global_allocator]` on an item statement + if let Annotatable::Stmt(stmt) = &item { + if let StmtKind::Item(item_) = &stmt.kind { + item = Annotatable::Item(item_.clone()); + is_stmt = true; + } + } + let item = match item { Annotatable::Item(item) => match item.kind { ItemKind::Static(..) => item, @@ -41,9 +52,14 @@ pub fn expand( let const_ty = ecx.ty(span, TyKind::Tup(Vec::new())); let const_body = ecx.expr_block(ecx.block(span, stmts)); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); + let const_item = if is_stmt { + Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) + } else { + Annotatable::Item(const_item) + }; // Return the original item and the new methods. - vec![Annotatable::Item(item), Annotatable::Item(const_item)] + vec![orig_item, const_item] } struct AllocFnFactory<'a, 'b> { diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e801b5c7b0..91566ec1ef 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -13,12 +13,12 @@ pub fn inject( resolver: &mut dyn ResolverExpand, sess: &Session, alt_std_name: Option, -) -> (ast::Crate, Option) { +) -> ast::Crate { let rust_2018 = sess.parse_sess.edition >= Edition::Edition2018; // the first name in this list is the crate name of the crate with the prelude let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) { - return (krate, None); + return krate; } else if sess.contains_name(&krate.attrs, sym::no_std) { if sess.contains_name(&krate.attrs, sym::compiler_builtins) { &[sym::core] @@ -81,5 +81,5 @@ pub fn inject( krate.module.items.insert(0, use_item); - (krate, Some(name)) + krate } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1de0b32f51..25d3f46da6 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -4,6 +4,7 @@ use crate::util::check_builtin_macro_attribute; use rustc_ast as ast; use rustc_ast::attr; +use rustc_ast::ptr::P; use rustc_ast_pretty::pprust; use rustc_expand::base::*; use rustc_session::Session; @@ -78,8 +79,16 @@ pub fn expand_test_or_bench( return vec![]; } - let item = match item { - Annotatable::Item(i) => i, + let (item, is_stmt) = match item { + Annotatable::Item(i) => (i, false), + Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { + // FIXME: Use an 'if let' guard once they are implemented + if let ast::StmtKind::Item(i) = stmt.into_inner().kind { + (i, true) + } else { + unreachable!() + } + } other => { cx.struct_span_err( other.span(), @@ -304,14 +313,25 @@ pub fn expand_test_or_bench( tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); - vec![ - // Access to libtest under a hygienic name - Annotatable::Item(test_extern), - // The generated test case - Annotatable::Item(test_const), - // The original item - Annotatable::Item(item), - ] + if is_stmt { + vec![ + // Access to libtest under a hygienic name + Annotatable::Stmt(P(cx.stmt_item(sp, test_extern))), + // The generated test case + Annotatable::Stmt(P(cx.stmt_item(sp, test_const))), + // The original item + Annotatable::Stmt(P(cx.stmt_item(sp, item))), + ] + } else { + vec![ + // Access to libtest under a hygienic name + Annotatable::Item(test_extern), + // The generated test case + Annotatable::Item(test_const), + // The original item + Annotatable::Item(item), + ] + } } fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String { diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 2889fac77f..67ed41e765 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "anyhow" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" +checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" [[package]] name = "ar" @@ -31,9 +31,9 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cc" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" +checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" [[package]] name = "cfg-if" @@ -41,18 +41,24 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "cranelift-bforest" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "byteorder", "cranelift-bforest", @@ -69,8 +75,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -78,18 +84,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" [[package]] name = "cranelift-entity" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" [[package]] name = "cranelift-frontend" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen", "log", @@ -99,8 +105,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "anyhow", "cranelift-codegen", @@ -111,8 +117,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -121,8 +127,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "anyhow", "cranelift-codegen", @@ -134,8 +140,8 @@ dependencies = [ [[package]] name = "cranelift-simplejit" -version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" +version = "0.68.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -151,18 +157,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] name = "errno" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eab5ee3df98a279d9b316b1af6ac95422127b1290317e6d18c1743c99418b01" +checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" dependencies = [ "errno-dragonfly", "libc", @@ -187,9 +193,9 @@ checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] name = "gimli" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" dependencies = [ "indexmap", ] @@ -212,17 +218,17 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "libloading" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3557c9384f7f757f6d139cd3a4c62ef4e850696c16bf27924a5538c8a09717a1" +checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "winapi", ] @@ -232,7 +238,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -246,9 +252,9 @@ dependencies = [ [[package]] name = "object" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ "crc32fast", "indexmap", @@ -274,9 +280,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "7.0.3" +version = "8.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" +checksum = "1fdf7d9dbd43f3d81d94a49c1c3df73cc2b3827995147e6cf7f89d4ec5483e73" dependencies = [ "bitflags", "cc", @@ -361,9 +367,9 @@ checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "syn" -version = "1.0.44" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" +checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" dependencies = [ "proc-macro2", "quote", @@ -372,24 +378,24 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe2635952a442a01fd4cb53d98858b5e4bb461b02c0d111f22f31772e3e7a8b2" +checksum = "4ee5a98e506fb7231a304c3a1bd7c132a55016cf65001e0282480665870dfcb9" [[package]] name = "thiserror" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" +checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" +checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" dependencies = [ "proc-macro2", "quote", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 1c8e350d24..cbff06749d 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -15,8 +15,8 @@ cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", bran cranelift-simplejit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true } cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } target-lexicon = "0.11.0" -gimli = { version = "0.22.0", default-features = false, features = ["write"]} -object = { version = "0.21.1", default-features = false, features = ["std", "read_core", "write", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.23.0", default-features = false, features = ["write"]} +object = { version = "0.22.0", default-features = false, features = ["std", "read_core", "write", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.0.2" diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index f8a5e13ed5..de54bf67f4 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -51,7 +51,7 @@ This should build and run your project with rustc_codegen_cranelift instead of t > You should prefer using the Cargo method. ```bash -$ $cg_clif_dir/build/cg_clif my_crate.rs +$ $cg_clif_dir/build/bin/cg_clif my_crate.rs ``` ### Jit mode @@ -68,7 +68,7 @@ $ $cg_clif_dir/build/cargo.sh jit or ```bash -$ $cg_clif_dir/build/cg_clif --jit my_crate.rs +$ $cg_clif_dir/build/bin/cg_clif --jit my_crate.rs ``` ### Shell @@ -77,7 +77,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/build/cg_clif - --jit + echo "$@" | $cg_clif_dir/build/bin/cg_clif - --jit } function jit() { diff --git a/compiler/rustc_codegen_cranelift/build.sh b/compiler/rustc_codegen_cranelift/build.sh index f9a87e68a0..26041b59cc 100755 --- a/compiler/rustc_codegen_cranelift/build.sh +++ b/compiler/rustc_codegen_cranelift/build.sh @@ -26,22 +26,35 @@ while [[ $# != 0 ]]; do done # Build cg_clif +unset CARGO_TARGET_DIR export RUSTFLAGS="-Zrun_dsymutil=no" +unamestr=$(uname) +if [[ "$unamestr" == 'Linux' ]]; then + export RUSTFLAGS='-Clink-arg=-Wl,-rpath=$ORIGIN/../lib '$RUSTFLAGS +elif [[ "$unamestr" == 'Darwin' ]]; then + export RUSTFLAGS='-Clink-arg=-Wl,-rpath,@loader_path/../lib -Zosx-rpath-install-name '$RUSTFLAGS + dylib_ext='dylib' +else + echo "Unsupported os" + exit 1 +fi if [[ "$CHANNEL" == "release" ]]; then cargo build --release else cargo build fi -rm -rf $target_dir -mkdir $target_dir -cp -a target/$CHANNEL/cg_clif{,_build_sysroot} target/$CHANNEL/*rustc_codegen_cranelift* $target_dir/ -cp -a rust-toolchain scripts/config.sh scripts/cargo.sh $target_dir +rm -rf "$target_dir" +mkdir "$target_dir" +mkdir "$target_dir"/bin "$target_dir"/lib +ln target/$CHANNEL/cg_clif{,_build_sysroot} "$target_dir"/bin +ln target/$CHANNEL/*rustc_codegen_cranelift* "$target_dir"/lib +ln rust-toolchain scripts/config.sh scripts/cargo.sh "$target_dir" if [[ "$build_sysroot" == "1" ]]; then echo "[BUILD] sysroot" export CG_CLIF_INCR_CACHE_DISABLED=1 dir=$(pwd) - cd $target_dir - time $dir/build_sysroot/build_sysroot.sh + cd "$target_dir" + time "$dir/build_sysroot/build_sysroot.sh" fi diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index 03ba5b53d2..a2b8f449f0 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" +checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" dependencies = [ "compiler_builtins", "gimli", @@ -47,9 +47,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "cc" -version = "1.0.61" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" +checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" [[package]] name = "cfg-if" @@ -76,9 +76,9 @@ version = "0.0.0" [[package]] name = "dlmalloc" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35055b1021724f4eb5262eb49130eebff23fc59fc5a14160e05faad8eeb36673" +checksum = "332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254" dependencies = [ "compiler_builtins", "libc", @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -163,9 +163,9 @@ dependencies = [ [[package]] name = "object" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/alloc_system/lib.rs b/compiler/rustc_codegen_cranelift/build_sysroot/alloc_system/lib.rs index ca145e4f2a..c832d5e5eb 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/alloc_system/lib.rs +++ b/compiler/rustc_codegen_cranelift/build_sysroot/alloc_system/lib.rs @@ -23,7 +23,7 @@ all(target_arch = "wasm32", not(target_os = "emscripten")), feature(integer_atomics, stdsimd) )] -#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))] +#![cfg_attr(any(unix, target_os = "redox"), feature(libc))] // The minimum alignment guaranteed by the architecture. This value is used to // add fast paths for low alignment values. #[cfg(all(any(target_arch = "x86", @@ -69,7 +69,7 @@ const MIN_ALIGN: usize = 16; /// independently of the standard library’s global allocator. #[stable(feature = "alloc_system_type", since = "1.28.0")] pub struct System; -#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] +#[cfg(any(windows, unix, target_os = "redox"))] mod realloc_fallback { use core::alloc::{GlobalAlloc, Layout}; use core::cmp; @@ -89,7 +89,7 @@ mod realloc_fallback { } } } -#[cfg(any(unix, target_os = "cloudabi", target_os = "redox"))] +#[cfg(any(unix, target_os = "redox"))] mod platform { extern crate libc; use core::ptr; diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh index eba15c0dd4..d7a72df2eb 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh @@ -10,10 +10,10 @@ dir=$(pwd) # Use rustc with cg_clif as hotpluggable backend instead of the custom cg_clif driver so that # build scripts are still compiled using cg_llvm. -export RUSTC=$dir"/cg_clif_build_sysroot" +export RUSTC=$dir"/bin/cg_clif_build_sysroot" export RUSTFLAGS=$RUSTFLAGS" --clif" -cd $(dirname "$0") +cd "$(dirname "$0")" # Cleanup for previous run # v Clean target dir except for build scripts and incremental cache @@ -28,12 +28,13 @@ if [[ "$1" != "--debug" ]]; then sysroot_channel='release' # FIXME Enable incremental again once rust-lang/rust#74946 is fixed # FIXME Enable -Zmir-opt-level=2 again once it doesn't ice anymore - CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS" cargo build --target $TARGET_TRIPLE --release + CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS" cargo build --target "$TARGET_TRIPLE" --release else sysroot_channel='debug' - cargo build --target $TARGET_TRIPLE + cargo build --target "$TARGET_TRIPLE" fi # Copy files to sysroot -mkdir -p $dir/sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ -cp -a target/$TARGET_TRIPLE/$sysroot_channel/deps/* $dir/sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +mkdir -p "$dir/lib/rustlib/$TARGET_TRIPLE/lib/" +ln "target/$TARGET_TRIPLE/$sysroot_channel/deps/"* "$dir/lib/rustlib/$TARGET_TRIPLE/lib/" +rm "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"*.{rmeta,d} diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh index d0fb09ce74..40fbaf646a 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh @@ -1,18 +1,18 @@ #!/bin/bash set -e -cd $(dirname "$0") +cd "$(dirname "$0")" -SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/" +SRC_DIR="$(dirname "$(rustup which rustc)")/../lib/rustlib/src/rust/" DST_DIR="sysroot_src" -if [ ! -e $SRC_DIR ]; then +if [ ! -e "$SRC_DIR" ]; then echo "Please install rust-src component" exit 1 fi rm -rf $DST_DIR mkdir -p $DST_DIR/library -cp -a $SRC_DIR/library $DST_DIR/ +cp -a "$SRC_DIR/library" $DST_DIR/ pushd $DST_DIR echo "[GIT] init" @@ -22,8 +22,8 @@ git add . echo "[GIT] commit" git commit -m "Initial commit" -q for file in $(ls ../../patches/ | grep -v patcha); do -echo "[GIT] apply" $file -git apply ../../patches/$file +echo "[GIT] apply" "$file" +git apply ../../patches/"$file" git add -A git commit --no-gpg-sign -m "Patch $file" done diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index ce07fe83df..10cba99205 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -1,6 +1,6 @@ #![feature( no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, - untagged_unions, decl_macro, rustc_attrs, transparent_unions, optin_builtin_traits, + untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits, thread_local, )] #![no_core] diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index cb512a4aa3..b38e25328a 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -53,6 +53,7 @@ fn main() { assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); + assert_eq!(core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), 170141183460469231731687303715884105727i128); let _d = 0i128.checked_div(2i128); let _d = 0u128.checked_div(2u128); diff --git a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch index ee8548783d..8cfffe580a 100644 --- a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch @@ -52,8 +52,8 @@ index 0475aeb..9558198 100644 fn test_rotate() { assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); @@ -112,6 +113,7 @@ mod tests { - assert_eq!(B.rotate_left(64), B); - assert_eq!(C.rotate_left(64), C); + assert_eq!(B.rotate_left(128), B); + assert_eq!(C.rotate_left(128), C); } + */ @@ -72,8 +72,8 @@ index 04ed14f..a6e372e 100644 fn test_rotate() { assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); @@ -76,6 +77,7 @@ mod tests { - assert_eq!(B.rotate_left(64), B); - assert_eq!(C.rotate_left(64), C); + assert_eq!(B.rotate_left(128), B); + assert_eq!(C.rotate_left(128), C); } + */ diff --git a/compiler/rustc_codegen_cranelift/prepare.sh b/compiler/rustc_codegen_cranelift/prepare.sh index 87f96f5dcf..08e7cb1802 100755 --- a/compiler/rustc_codegen_cranelift/prepare.sh +++ b/compiler/rustc_codegen_cranelift/prepare.sh @@ -24,6 +24,7 @@ git checkout -- . git checkout 804a7a21b9e673a482797aa289a18ed480e4d813 # build with cg_llvm for perf comparison +unset CARGO_TARGET_DIR cargo build mv target/debug/main raytracer_cg_llvm popd diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 0ca96be9ae..ed1e64f45d 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1 +1 @@ -nightly-2020-10-31 +nightly-2020-11-27 diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.sh b/compiler/rustc_codegen_cranelift/scripts/cargo.sh index 947b4a2879..dcd40acc02 100755 --- a/compiler/rustc_codegen_cranelift/scripts/cargo.sh +++ b/compiler/rustc_codegen_cranelift/scripts/cargo.sh @@ -1,16 +1,16 @@ #!/bin/bash dir=$(dirname "$0") -source $dir/config.sh +source "$dir/config.sh" # read nightly compiler from rust-toolchain file -TOOLCHAIN=$(cat $dir/rust-toolchain) +TOOLCHAIN=$(cat "$dir/rust-toolchain") cmd=$1 shift || true if [[ "$cmd" = "jit" ]]; then -cargo +${TOOLCHAIN} rustc "$@" -- --jit +cargo "+${TOOLCHAIN}" rustc "$@" -- --jit else -cargo +${TOOLCHAIN} $cmd "$@" +cargo "+${TOOLCHAIN}" "$cmd" "$@" fi diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh index 6120a550a2..dea037e2bc 100644 --- a/compiler/rustc_codegen_cranelift/scripts/config.sh +++ b/compiler/rustc_codegen_cranelift/scripts/config.sh @@ -1,7 +1,8 @@ -#!/usr/bin/env bash +# Note to people running shellcheck: this file should only be sourced, not executed directly. + set -e -unamestr=`uname` +unamestr=$(uname) if [[ "$unamestr" == 'Linux' ]]; then dylib_ext='so' elif [[ "$unamestr" == 'Darwin' ]]; then @@ -40,19 +41,19 @@ echo export RUSTC_WRAPPER= fi -dir=$(cd $(dirname "$BASH_SOURCE"); pwd) +dir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd) -export RUSTC=$dir"/cg_clif" -export RUSTFLAGS=$linker -export RUSTDOCFLAGS=$linker' -Ztrim-diagnostic-paths=no -Cpanic=abort -Zpanic-abort-tests '\ -'-Zcodegen-backend='$dir'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir'/sysroot' +export RUSTC=$dir"/bin/cg_clif" +export RUSTFLAGS=$linker" "$RUSTFLAGS +export RUSTDOCFLAGS=$linker' -Cpanic=abort -Zpanic-abort-tests '\ +'-Zcodegen-backend='$dir'/lib/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir # FIXME remove once the atomic shim is gone -if [[ `uname` == 'Darwin' ]]; then +if [[ $(uname) == 'Darwin' ]]; then export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" fi -export LD_LIBRARY_PATH="$dir:$(rustc --print sysroot)/lib:$dir/target/out:$dir/sysroot/lib/rustlib/"$TARGET_TRIPLE"/lib" +export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib" export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH export CG_CLIF_DISPLAY_CG_TIME=1 diff --git a/compiler/rustc_codegen_cranelift/scripts/rustup.sh b/compiler/rustc_codegen_cranelift/scripts/rustup.sh index 541b3c6563..430f5c469b 100755 --- a/compiler/rustc_codegen_cranelift/scripts/rustup.sh +++ b/compiler/rustc_codegen_cranelift/scripts/rustup.sh @@ -7,13 +7,13 @@ case $1 in TOOLCHAIN=$(date +%Y-%m-%d) echo "=> Installing new nightly" - rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists - echo nightly-${TOOLCHAIN} > rust-toolchain + rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists + echo "nightly-${TOOLCHAIN}" > rust-toolchain rustup component add rustfmt || true echo "=> Uninstalling all old nighlies" - for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do - rustup toolchain uninstall $nightly + for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do + rustup toolchain uninstall "$nightly" done ./clean_all.sh @@ -27,14 +27,30 @@ case $1 in git commit -m "Rustup to $(rustc -V)" ;; "push") - cg_clif=$(pwd) - pushd ../rust - branch=update_cg_clif-$(date +%Y-%m-%d) - git checkout -b $branch - git subtree pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master - git push -u my $branch - popd + cg_clif=$(pwd) + pushd ../rust + git pull origin master + branch=sync_cg_clif-$(date +%Y-%m-%d) + git checkout -b "$branch" + git subtree pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master + git push -u my "$branch" + + # immediately merge the merge commit into cg_clif to prevent merge conflicts when syncing + # from rust-lang/rust later + git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust + popd + git merge sync_from_rust ;; + "pull") + cg_clif=$(pwd) + pushd ../rust + git pull origin master + rust_vers="$(git rev-parse HEAD)" + git subtree push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust + popd + git merge sync_from_rust -m "Sync from rust $rust_vers" + git branch -d sync_from_rust + ;; *) echo "Unknown command '$1'" echo "Usage: ./rustup.sh prepare|commit" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh index 7f43f81a6c..db69541b22 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -cd $(dirname "$0")/../ +cd "$(dirname "$0")/../" ./build.sh source build/config.sh @@ -11,7 +11,7 @@ git clone https://github.com/rust-lang/rust.git || true pushd rust git fetch git checkout -- . -git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') +git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" git apply - < config.toml <(tcx: TyCtxt<'tcx>, instance: Instance<'tcx ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let env_region = ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv }); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); let pin_did = tcx.require_lang_item(rustc_hir::LangItem::Pin, None); @@ -214,10 +214,8 @@ pub(crate) fn get_function_name_and_sig<'tcx>( support_vararg: bool, ) -> (String, Signature) { assert!(!inst.substs.needs_infer()); - let fn_sig = tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - &fn_sig_for_fn_abi(tcx, inst), - ); + let fn_sig = tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_sig_for_fn_abi(tcx, inst)); if fn_sig.c_variadic && !support_vararg { tcx.sess.span_fatal( tcx.def_span(inst.def_id()), @@ -372,7 +370,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>( .mir .args_iter() .map(|local| { - let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty); + let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty); // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482 if Some(local) == fx.mir.spread_arg { @@ -470,7 +468,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>( } for local in fx.mir.vars_and_temps_iter() { - let ty = fx.monomorphize(&fx.mir.local_decls[local].ty); + let ty = fx.monomorphize(fx.mir.local_decls[local].ty); let layout = fx.layout_of(ty); let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa; @@ -492,10 +490,10 @@ pub(crate) fn codegen_terminator_call<'tcx>( args: &[Operand<'tcx>], destination: Option<(Place<'tcx>, BasicBlock)>, ) { - let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx)); + let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx)); let fn_sig = fx .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx)); + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx)); let destination = destination.map(|(place, bb)| (codegen_place(fx, place), bb)); @@ -711,7 +709,7 @@ pub(crate) fn codegen_drop<'tcx>( let drop_fn_ty = drop_fn.ty(fx.tcx, ParamEnv::reveal_all()); let fn_sig = fx.tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &drop_fn_ty.fn_sig(fx.tcx), + drop_fn_ty.fn_sig(fx.tcx), ); assert_eq!(fn_sig.output(), fx.tcx.mk_unit()); diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs index fd25b19a58..adf5c7ac4f 100644 --- a/compiler/rustc_codegen_cranelift/src/analyze.rs +++ b/compiler/rustc_codegen_cranelift/src/analyze.rs @@ -17,7 +17,7 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Module>) -> IndexVec ArchiveBuilder<'a> for ArArchiveBuilder<'a> { entry_name.as_bytes().to_vec(), object .symbols() - .filter_map(|(_index, symbol)| { + .filter_map(|symbol| { if symbol.is_undefined() || symbol.is_local() || symbol.kind() != SymbolKind::Data @@ -193,7 +193,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { { None } else { - symbol.name().map(|name| name.as_bytes().to_vec()) + symbol.name().map(|name| name.as_bytes().to_vec()).ok() } }) .collect::>(), diff --git a/compiler/rustc_codegen_cranelift/src/atomic_shim.rs b/compiler/rustc_codegen_cranelift/src/atomic_shim.rs index 2f0157c257..674e6d9075 100644 --- a/compiler/rustc_codegen_cranelift/src/atomic_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/atomic_shim.rs @@ -7,8 +7,7 @@ use crate::prelude::*; #[cfg(all(feature = "jit", unix))] #[no_mangle] -static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t = - libc::PTHREAD_MUTEX_INITIALIZER; +static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; pub(crate) fn init_global_lock( module: &mut impl Module, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index bfe5514b6d..72073896a7 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -12,6 +12,10 @@ pub(crate) fn codegen_fn<'tcx>( ) { let tcx = cx.tcx; + let _inst_guard = + crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name)); + debug_assert!(!instance.substs.needs_infer()); + let mir = tcx.instance_mir(instance.def); // Declare function @@ -445,43 +449,43 @@ fn codegen_stmt<'tcx>( StatementKind::Assign(to_place_and_rval) => { let lval = codegen_place(fx, to_place_and_rval.0); let dest_layout = lval.layout(); - match &to_place_and_rval.1 { - Rvalue::Use(operand) => { + match to_place_and_rval.1 { + Rvalue::Use(ref operand) => { let val = codegen_operand(fx, operand); lval.write_cvalue(fx, val); } Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - let place = codegen_place(fx, *place); + let place = codegen_place(fx, place); let ref_ = place.place_ref(fx, lval.layout()); lval.write_cvalue(fx, ref_); } Rvalue::ThreadLocalRef(def_id) => { - let val = crate::constant::codegen_tls_ref(fx, *def_id, lval.layout()); + let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout()); lval.write_cvalue(fx, val); } - Rvalue::BinaryOp(bin_op, lhs, rhs) => { + Rvalue::BinaryOp(bin_op, ref lhs, ref rhs) => { let lhs = codegen_operand(fx, lhs); let rhs = codegen_operand(fx, rhs); - let res = crate::num::codegen_binop(fx, *bin_op, lhs, rhs); + let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs); lval.write_cvalue(fx, res); } - Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => { + Rvalue::CheckedBinaryOp(bin_op, ref lhs, ref rhs) => { let lhs = codegen_operand(fx, lhs); let rhs = codegen_operand(fx, rhs); let res = if !fx.tcx.sess.overflow_checks() { let val = - crate::num::codegen_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx); + crate::num::codegen_int_binop(fx, bin_op, lhs, rhs).load_scalar(fx); let is_overflow = fx.bcx.ins().iconst(types::I8, 0); CValue::by_val_pair(val, is_overflow, lval.layout()) } else { - crate::num::codegen_checked_int_binop(fx, *bin_op, lhs, rhs) + crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs) }; lval.write_cvalue(fx, res); } - Rvalue::UnaryOp(un_op, operand) => { + Rvalue::UnaryOp(un_op, ref operand) => { let operand = codegen_operand(fx, operand); let layout = operand.layout(); let val = operand.load_scalar(fx); @@ -499,7 +503,8 @@ fn codegen_stmt<'tcx>( UnOp::Neg => match layout.ty.kind() { ty::Int(IntTy::I128) => { // FIXME remove this case once ineg.i128 works - let zero = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); + let zero = + CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand) } ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), @@ -509,8 +514,12 @@ fn codegen_stmt<'tcx>( }; lval.write_cvalue(fx, res); } - Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), operand, to_ty) => { - let from_ty = fx.monomorphize(&operand.ty(&fx.mir.local_decls, fx.tcx)); + Rvalue::Cast( + CastKind::Pointer(PointerCast::ReifyFnPointer), + ref operand, + to_ty, + ) => { + let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx)); let to_layout = fx.layout_of(fx.monomorphize(to_ty)); match *from_ty.kind() { ty::FnDef(def_id, substs) => { @@ -530,14 +539,26 @@ fn codegen_stmt<'tcx>( _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty), } } - Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), operand, to_ty) - | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, to_ty) - | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, to_ty) => { + Rvalue::Cast( + CastKind::Pointer(PointerCast::UnsafeFnPointer), + ref operand, + to_ty, + ) + | Rvalue::Cast( + CastKind::Pointer(PointerCast::MutToConstPointer), + ref operand, + to_ty, + ) + | Rvalue::Cast( + CastKind::Pointer(PointerCast::ArrayToPointer), + ref operand, + to_ty, + ) => { let to_layout = fx.layout_of(fx.monomorphize(to_ty)); let operand = codegen_operand(fx, operand); lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); } - Rvalue::Cast(CastKind::Misc, operand, to_ty) => { + Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => { let operand = codegen_operand(fx, operand); let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); @@ -577,12 +598,12 @@ fn codegen_stmt<'tcx>( use rustc_target::abi::{Int, TagEncoding, Variants}; - match &operand.layout().variants { + match operand.layout().variants { Variants::Single { index } => { let discr = operand .layout() .ty - .discriminant_for_variant(fx.tcx, *index) + .discriminant_for_variant(fx.tcx, index) .unwrap(); let discr = if discr.ty.is_signed() { fx.layout_of(discr.ty).size.sign_extend(discr.val) @@ -595,7 +616,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, discr); } Variants::Multiple { - tag, + ref tag, tag_field, tag_encoding: TagEncoding::Direct, variants: _, @@ -604,7 +625,7 @@ fn codegen_stmt<'tcx>( // Read the tag/niche-encoded discriminant from memory. let encoded_discr = - operand.value_field(fx, mir::Field::new(*tag_field)); + operand.value_field(fx, mir::Field::new(tag_field)); let encoded_discr = encoded_discr.load_scalar(fx); // Decode the discriminant (specifically if it's niche-encoded). @@ -634,7 +655,7 @@ fn codegen_stmt<'tcx>( } Rvalue::Cast( CastKind::Pointer(PointerCast::ClosureFnPointer(_)), - operand, + ref operand, _to_ty, ) => { let operand = codegen_operand(fx, operand); @@ -654,18 +675,18 @@ fn codegen_stmt<'tcx>( _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty), } } - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, _to_ty) => { + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => { let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } Rvalue::Discriminant(place) => { - let place = codegen_place(fx, *place); + let place = codegen_place(fx, place); let value = place.to_cvalue(fx); let discr = crate::discriminant::codegen_get_discriminant(fx, value, dest_layout); lval.write_cvalue(fx, discr); } - Rvalue::Repeat(operand, times) => { + Rvalue::Repeat(ref operand, times) => { let operand = codegen_operand(fx, operand); let times = fx .monomorphize(times) @@ -704,7 +725,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Len(place) => { - let place = codegen_place(fx, *place); + let place = codegen_place(fx, place); let usize_layout = fx.layout_of(fx.tcx.types.usize); let len = codegen_array_len(fx, place); lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); @@ -749,7 +770,7 @@ fn codegen_stmt<'tcx>( CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into()); lval.write_cvalue(fx, val); } - Rvalue::Aggregate(kind, operands) => match **kind { + Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() { AggregateKind::Array(_ty) => { for (i, operand) in operands.iter().enumerate() { let operand = codegen_operand(fx, operand); @@ -877,8 +898,7 @@ fn codegen_array_len<'tcx>( match *place.layout().ty.kind() { ty::Array(_elem_ty, len) => { let len = fx - .monomorphize(&len) - .eval(fx.tcx, ParamEnv::reveal_all()) + .monomorphize(len) .eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64; fx.bcx.ins().iconst(fx.pointer_type, len) } diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs index cd01acc9a8..f4d23ebcf4 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs @@ -26,15 +26,15 @@ impl rustc_driver::Callbacks for CraneliftPassesCallbacks { config.opts.cg.panic = Some(PanicStrategy::Abort); config.opts.debugging_opts.panic_abort_tests = true; - config.opts.maybe_sysroot = Some( - config.opts.maybe_sysroot.clone().unwrap_or_else( - || std::env::current_exe() - .unwrap() - .parent() - .unwrap() - .join("sysroot"), - ), - ); + config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| { + std::env::current_exe() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .to_owned() + })); } } diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 466758f2f8..1485d4451b 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -233,7 +233,7 @@ pub(crate) fn type_min_max_value( let min_msb = bcx.ins().iconst(types::I64, (min >> 64) as u64 as i64); let min = bcx.ins().iconcat(min_lsb, min_msb); - let max = i128::MIN as u128; + let max = i128::MAX as u128; let max_lsb = bcx.ins().iconst(types::I64, max as u64 as i64); let max_msb = bcx.ins().iconst(types::I64, (max >> 64) as u64 as i64); let max = bcx.ins().iconcat(max_lsb, max_msb); @@ -357,14 +357,14 @@ impl<'tcx, M: Module> HasTargetSpec for FunctionCx<'_, 'tcx, M> { } impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { - pub(crate) fn monomorphize(&self, value: &T) -> T + pub(crate) fn monomorphize(&self, value: T) -> T where T: TypeFoldable<'tcx> + Copy, { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - value + value, ) } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 41cfae4ca6..544b020b71 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -38,7 +38,7 @@ impl ConstantCx { pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, impl Module>) { for constant in &fx.mir.required_consts { - let const_ = fx.monomorphize(&constant.literal); + let const_ = fx.monomorphize(constant.literal); match const_.val { ConstKind::Value(_) => {} ConstKind::Unevaluated(def, ref substs, promoted) => { @@ -110,7 +110,7 @@ pub(crate) fn codegen_constant<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, constant: &Constant<'tcx>, ) -> CValue<'tcx> { - let const_ = fx.monomorphize(&constant.literal); + let const_ = fx.monomorphize(constant.literal); let const_val = match const_.val { ConstKind::Value(const_val) => const_val, ConstKind::Unevaluated(def, ref substs, promoted) if fx.tcx.is_static(def.did) => { @@ -163,10 +163,7 @@ pub(crate) fn codegen_const_value<'tcx>( assert!(!layout.is_unsized(), "sized const value"); if layout.is_zst() { - return CValue::by_ref( - crate::Pointer::dangling(layout.align.pref), - layout, - ); + return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout); } match const_val { @@ -186,9 +183,7 @@ pub(crate) fn codegen_const_value<'tcx>( } match x { - Scalar::Int(int) => { - CValue::const_val(fx, layout, int) - } + Scalar::Int(int) => CValue::const_val(fx, layout, int), Scalar::Ptr(ptr) => { let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id); let base_addr = match alloc_kind { @@ -466,7 +461,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( match operand { Operand::Copy(_) | Operand::Move(_) => None, Operand::Constant(const_) => Some( - fx.monomorphize(&const_.literal) + fx.monomorphize(const_.literal) .eval(fx.tcx, ParamEnv::reveal_all()), ), } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index f6f795e456..c21835b1fc 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -76,7 +76,7 @@ impl WriterRelocate { #[cfg(feature = "jit")] pub(super) fn relocate_for_jit( mut self, - jit_product: &cranelift_simplejit::SimpleJITProduct, + jit_module: &cranelift_simplejit::SimpleJITModule, ) -> Vec { use std::convert::TryInto; @@ -84,8 +84,9 @@ impl WriterRelocate { match reloc.name { super::DebugRelocName::Section(_) => unreachable!(), super::DebugRelocName::Symbol(sym) => { - let addr = jit_product - .lookup_func(cranelift_module::FuncId::from_u32(sym.try_into().unwrap())); + let addr = jit_module.get_finalized_function( + cranelift_module::FuncId::from_u32(sym.try_into().unwrap()), + ); let val = (addr as u64 as i64 + reloc.addend) as u64; self.writer .write_udata_at(reloc.offset as usize, val, reloc.size) diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 85e8158af2..a6f4ded41b 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -365,7 +365,7 @@ impl<'tcx> DebugContext<'tcx> { let ty = self.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &mir.local_decls[local].ty, + mir.local_decls[local].ty, ); let var_id = self.define_local(entry_id, format!("{:?}", local), ty); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 68138404c2..e0f62b64e6 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -80,7 +80,7 @@ impl<'tcx> UnwindContext<'tcx> { #[cfg(feature = "jit")] pub(crate) unsafe fn register_jit( self, - jit_product: &cranelift_simplejit::SimpleJITProduct, + jit_module: &cranelift_simplejit::SimpleJITModule, ) -> Option { let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian( self.tcx, @@ -91,7 +91,7 @@ impl<'tcx> UnwindContext<'tcx> { return None; } - let mut eh_frame = eh_frame.0.relocate_for_jit(jit_product); + let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module); // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. eh_frame.extend(&[0, 0, 0, 0]); diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index 1e8e86add1..ad635016a9 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -30,8 +30,16 @@ pub(crate) fn codegen_set_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, variant_index) .unwrap() - .val - .into(); + .val; + let to = if ptr.layout().abi.is_signed() { + ty::ScalarInt::try_from_int( + ptr.layout().size.sign_extend(to) as i128, + ptr.layout().size, + ) + .unwrap() + } else { + ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap() + }; let discr = CValue::const_val(fx, ptr.layout(), to); ptr.write_cvalue(fx, discr); } @@ -49,8 +57,12 @@ pub(crate) fn codegen_set_discriminant<'tcx>( if variant_index != dataful_variant { let niche = place.place_field(fx, mir::Field::new(tag_field)); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); - let niche_value = u128::from(niche_value).wrapping_add(niche_start); - let niche_llval = CValue::const_val(fx, niche.layout(), niche_value.into()); + let niche_value = ty::ScalarInt::try_from_uint( + u128::from(niche_value).wrapping_add(niche_start), + niche.layout().size, + ) + .unwrap(); + let niche_llval = CValue::const_val(fx, niche.layout(), niche_value); niche.write_cvalue(fx, niche_llval); } } @@ -78,7 +90,16 @@ pub(crate) fn codegen_get_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, *index) .map_or(u128::from(index.as_u32()), |discr| discr.val); - return CValue::const_val(fx, dest_layout, discr_val.into()); + let discr_val = if dest_layout.abi.is_signed() { + ty::ScalarInt::try_from_int( + dest_layout.size.sign_extend(discr_val) as i128, + dest_layout.size, + ) + .unwrap() + } else { + ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap() + }; + return CValue::const_val(fx, dest_layout, discr_val); } Variants::Multiple { tag, diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index c0245aa1e0..78d6ff0cb0 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -75,6 +75,7 @@ fn emit_module( name, kind, object: Some(tmp_file), + dwarf_object: None, bytecode: None, }, work_product, @@ -111,6 +112,7 @@ fn reuse_workproduct_for_cgu( name: cgu.name().to_string(), kind: ModuleKind::Regular, object, + dwarf_object: None, bytecode: None, } } @@ -145,7 +147,11 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege } let mut cx = crate::CodegenCx::new(tcx, module, tcx.sess.opts.debuginfo != DebugInfo::None); - super::codegen_mono_items(&mut cx, mono_items); + super::predefine_mono_items(&mut cx, &mono_items); + for (mono_item, (linkage, visibility)) in mono_items { + let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + super::codegen_mono_item(&mut cx, mono_item, linkage); + } let (mut module, global_asm, debug, mut unwind_context) = tcx.sess.time("finalize CodegenCx", || cx.finalize()); crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context, false); @@ -286,6 +292,7 @@ pub(super) fn run_aot( name: metadata_cgu_name, kind: ModuleKind::Metadata, object: Some(tmp_file), + dwarf_object: None, bytecode: None, }) } else { diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 3f47df7d84..5a844841c2 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -70,7 +70,11 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! { let (mut jit_module, global_asm, _debug, mut unwind_context) = super::time(tcx, "codegen mono items", || { - super::codegen_mono_items(&mut cx, mono_items); + super::predefine_mono_items(&mut cx, &mono_items); + for (mono_item, (linkage, visibility)) in mono_items { + let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + super::codegen_mono_item(&mut cx, mono_item, linkage); + } tcx.sess.time("finalize CodegenCx", || cx.finalize()) }); if !global_asm.is_empty() { @@ -81,11 +85,11 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! { tcx.sess.abort_if_errors(); - let jit_product = jit_module.finish(); + jit_module.finalize_definitions(); - let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_product) }; + let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_module) }; - let finalized_main: *const u8 = jit_product.lookup_func(main_func_id); + let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed"); @@ -140,11 +144,11 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { let mut imported_symbols = Vec::new(); for path in dylib_paths { - use object::Object; + use object::{Object, ObjectSymbol}; let lib = libloading::Library::new(&path).unwrap(); let obj = std::fs::read(path).unwrap(); let obj = object::File::parse(&obj).unwrap(); - imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| { + imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| { let name = symbol.name().unwrap().to_string(); if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { return None; diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index a11dc57ee6..7b8cc2ddd4 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -1,4 +1,4 @@ -//! Drivers are responsible for calling [`codegen_mono_items`] and performing any further actions +//! Drivers are responsible for calling [`codegen_mono_item`] and performing any further actions //! like JIT executing or writing object files. use std::any::Any; @@ -40,12 +40,12 @@ pub(crate) fn codegen_crate( aot::run_aot(tcx, metadata, need_metadata_module) } -fn codegen_mono_items<'tcx>( +fn predefine_mono_items<'tcx>( cx: &mut crate::CodegenCx<'tcx, impl Module>, - mono_items: Vec<(MonoItem<'tcx>, (RLinkage, Visibility))>, + mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))], ) { cx.tcx.sess.time("predefine functions", || { - for &(mono_item, (linkage, visibility)) in &mono_items { + for &(mono_item, (linkage, visibility)) in mono_items { match mono_item { MonoItem::Fn(instance) => { let (name, sig) = get_function_name_and_sig( @@ -61,11 +61,6 @@ fn codegen_mono_items<'tcx>( } } }); - - for (mono_item, (linkage, visibility)) in mono_items { - let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); - codegen_mono_item(cx, mono_item, linkage); - } } fn codegen_mono_item<'tcx, M: Module>( @@ -73,20 +68,15 @@ fn codegen_mono_item<'tcx, M: Module>( mono_item: MonoItem<'tcx>, linkage: Linkage, ) { - let tcx = cx.tcx; match mono_item { MonoItem::Fn(inst) => { - let _inst_guard = - crate::PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name)); - debug_assert!(!inst.substs.needs_infer()); - tcx.sess + cx.tcx + .sess .time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage)); } - MonoItem::Static(def_id) => { - crate::constant::codegen_static(&mut cx.constants_cx, def_id); - } + MonoItem::Static(def_id) => crate::constant::codegen_static(&mut cx.constants_cx, def_id), MonoItem::GlobalAsm(hir_id) => { - let item = tcx.hir().expect_item(hir_id); + let item = cx.tcx.hir().expect_item(hir_id); if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind { cx.global_asm.push_str(&*asm.as_str()); cx.global_asm.push_str("\n\n"); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index ab16fabd34..df8aa1b3e6 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -146,12 +146,12 @@ macro atomic_minmax($fx:expr, $cc:expr, <$T:ident> ($ptr:ident, $src:ident) -> $ macro validate_atomic_type($fx:ident, $intrinsic:ident, $span:ident, $ty:expr) { match $ty.kind() { - ty::Uint(_) | ty::Int(_) => {} + ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { $fx.tcx.sess.span_err( $span, &format!( - "`{}` intrinsic: expected basic integer type, found `{:?}`", + "`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`", $intrinsic, $ty ), ); @@ -263,6 +263,48 @@ fn simd_pair_for_each_lane<'tcx, M: Module>( } } +fn simd_reduce<'tcx, M: Module>( + fx: &mut FunctionCx<'_, 'tcx, M>, + val: CValue<'tcx>, + ret: CPlace<'tcx>, + f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, TyAndLayout<'tcx>, Value, Value) -> Value, +) { + let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout()); + assert_eq!(lane_layout, ret.layout()); + + let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx); + for lane_idx in 1..lane_count { + let lane = val + .value_field(fx, mir::Field::new(lane_idx.into())) + .load_scalar(fx); + res_val = f(fx, lane_layout, res_val, lane); + } + let res = CValue::by_val(res_val, lane_layout); + ret.write_cvalue(fx, res); +} + +fn simd_reduce_bool<'tcx, M: Module>( + fx: &mut FunctionCx<'_, 'tcx, M>, + val: CValue<'tcx>, + ret: CPlace<'tcx>, + f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, Value, Value) -> Value, +) { + let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout()); + assert!(ret.layout().ty.is_bool()); + + let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx); + let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean + for lane_idx in 1..lane_count { + let lane = val + .value_field(fx, mir::Field::new(lane_idx.into())) + .load_scalar(fx); + let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean + res_val = f(fx, res_val, lane); + } + let res = CValue::by_val(res_val, ret.layout()); + ret.write_cvalue(fx, res); +} + fn bool_to_zero_or_max_uint<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, layout: TyAndLayout<'tcx>, @@ -287,7 +329,7 @@ fn bool_to_zero_or_max_uint<'tcx>( } macro simd_cmp { - ($fx:expr, $cc:ident($x:ident, $y:ident) -> $ret:ident) => { + ($fx:expr, $cc:ident|$cc_f:ident($x:ident, $y:ident) -> $ret:ident) => { let vector_ty = clif_vector_type($fx.tcx, $x.layout()); if let Some(vector_ty) = vector_ty { @@ -308,6 +350,7 @@ macro simd_cmp { |fx, lane_layout, res_lane_layout, x_lane, y_lane| { let res_lane = match lane_layout.ty.kind() { ty::Uint(_) | ty::Int(_) => fx.bcx.ins().icmp(IntCC::$cc, x_lane, y_lane), + ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::$cc_f, x_lane, y_lane), _ => unreachable!("{:?}", lane_layout.ty), }; bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane) @@ -315,7 +358,7 @@ macro simd_cmp { ); } }, - ($fx:expr, $cc_u:ident|$cc_s:ident($x:ident, $y:ident) -> $ret:ident) => { + ($fx:expr, $cc_u:ident|$cc_s:ident|$cc_f:ident($x:ident, $y:ident) -> $ret:ident) => { // FIXME use vector icmp when possible simd_pair_for_each_lane( $fx, @@ -326,6 +369,7 @@ macro simd_cmp { let res_lane = match lane_layout.ty.kind() { ty::Uint(_) => fx.bcx.ins().icmp(IntCC::$cc_u, x_lane, y_lane), ty::Int(_) => fx.bcx.ins().icmp(IntCC::$cc_s, x_lane, y_lane), + ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::$cc_f, x_lane, y_lane), _ => unreachable!("{:?}", lane_layout.ty), }; bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane) @@ -497,12 +541,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; copy | copy_nonoverlapping, (v src, v dst, v count) { let elem_size: u64 = fx.layout_of(elem_ty).size.bytes(); - let elem_size = fx - .bcx - .ins() - .iconst(fx.pointer_type, elem_size as i64); assert_eq!(args.len(), 3); - let byte_amount = fx.bcx.ins().imul(count, elem_size); + let byte_amount = if elem_size != 1 { + fx.bcx.ins().imul_imm(count, elem_size as i64) + } else { + count + }; if intrinsic.contains("nonoverlapping") { // FIXME emit_small_memcpy @@ -515,12 +559,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( // NOTE: the volatile variants have src and dst swapped volatile_copy_memory | volatile_copy_nonoverlapping_memory, (v dst, v src, v count) { let elem_size: u64 = fx.layout_of(elem_ty).size.bytes(); - let elem_size = fx - .bcx - .ins() - .iconst(fx.pointer_type, elem_size as i64); assert_eq!(args.len(), 3); - let byte_amount = fx.bcx.ins().imul(count, elem_size); + let byte_amount = if elem_size != 1 { + fx.bcx.ins().imul_imm(count, elem_size as i64) + } else { + count + }; // FIXME make the copy actually volatile when using emit_small_mem{cpy,move} if intrinsic.contains("nonoverlapping") { @@ -676,7 +720,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( offset | arith_offset, (c base, v offset) { let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; let pointee_size = fx.layout_of(pointee_ty).size.bytes(); - let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); + let ptr_diff = if pointee_size != 1 { + fx.bcx.ins().imul_imm(offset, pointee_size as i64) + } else { + offset + }; let base_val = base.load_scalar(fx); let res = fx.bcx.ins().iadd(base_val, ptr_diff); ret.write_cvalue(fx, CValue::by_val(res, base.layout())); @@ -688,7 +736,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( write_bytes | volatile_set_memory, (c dst, v val, v count) { let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty; let pointee_size = fx.layout_of(pointee_ty).size.bytes(); - let count = fx.bcx.ins().imul_imm(count, pointee_size as i64); + let count = if pointee_size != 1 { + fx.bcx.ins().imul_imm(count, pointee_size as i64) + } else { + count + }; let dst_ptr = dst.load_scalar(fx); // FIXME make the memset actually volatile when switching to emit_small_memset // FIXME use emit_small_memset diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 2e31c4669e..2b32e866e5 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -35,30 +35,33 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); }; - // FIXME support float comparisons simd_eq, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, Equal(x, y) -> ret); + simd_cmp!(fx, Equal|Equal(x, y) -> ret); }; simd_ne, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, NotEqual(x, y) -> ret); + simd_cmp!(fx, NotEqual|NotEqual(x, y) -> ret); }; simd_lt, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedLessThan|SignedLessThan(x, y) -> ret); + simd_cmp!(fx, UnsignedLessThan|SignedLessThan|LessThan(x, y) -> ret); }; simd_le, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedLessThanOrEqual|SignedLessThanOrEqual(x, y) -> ret); + simd_cmp!(fx, UnsignedLessThanOrEqual|SignedLessThanOrEqual|LessThanOrEqual(x, y) -> ret); }; simd_gt, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedGreaterThan|SignedGreaterThan(x, y) -> ret); + simd_cmp!(fx, UnsignedGreaterThan|SignedGreaterThan|GreaterThan(x, y) -> ret); }; simd_ge, (c x, c y) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - simd_cmp!(fx, UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual(x, y) -> ret); + simd_cmp!( + fx, + UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual|GreaterThanOrEqual + (x, y) -> ret + ); }; // simd_shuffle32(x: T, y: T, idx: [u32; 32]) -> U @@ -107,9 +110,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( for (out_idx, in_idx) in indexes.into_iter().enumerate() { let in_lane = if in_idx < lane_count { - x.value_field(fx, mir::Field::new(in_idx.try_into().unwrap())) + x.value_field(fx, mir::Field::new(in_idx.into())) } else { - y.value_field(fx, mir::Field::new((in_idx - lane_count).try_into().unwrap())) + y.value_field(fx, mir::Field::new((in_idx - lane_count).into())) }; let out_lane = ret.place_field(fx, mir::Field::new(out_idx)); out_lane.write_cvalue(fx, in_lane); @@ -143,10 +146,17 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) { idx_const } else { - fx.tcx.sess.span_fatal( + fx.tcx.sess.span_warn( span, "Index argument for `simd_extract` is not a constant", ); + let res = crate::trap::trap_unimplemented_ret_value( + fx, + ret.layout(), + "Index argument for `simd_extract` is not a constant", + ); + ret.write_cvalue(fx, res); + return; }; let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); @@ -207,7 +217,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( assert_eq!(lane_count, ret_lane_count); for lane in 0..lane_count { - let lane = mir::Field::new(lane.try_into().unwrap()); + let lane = mir::Field::new(lane.into()); let a_lane = a.value_field(fx, lane).load_scalar(fx); let b_lane = b.value_field(fx, lane).load_scalar(fx); let c_lane = c.value_field(fx, lane).load_scalar(fx); @@ -228,11 +238,42 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( simd_flt_binop!(fx, fmax(x, y) -> ret); }; + simd_reduce_add_ordered | simd_reduce_add_unordered, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce(fx, v, ret, |fx, lane_layout, a, b| { + if lane_layout.ty.is_floating_point() { + fx.bcx.ins().fadd(a, b) + } else { + fx.bcx.ins().iadd(a, b) + } + }); + }; + + simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce(fx, v, ret, |fx, lane_layout, a, b| { + if lane_layout.ty.is_floating_point() { + fx.bcx.ins().fmul(a, b) + } else { + fx.bcx.ins().imul(a, b) + } + }); + }; + + simd_reduce_all, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce_bool(fx, v, ret, |fx, a, b| fx.bcx.ins().band(a, b)); + }; + + simd_reduce_any, (c v) { + validate_simd_type!(fx, intrinsic, span, v.layout().ty); + simd_reduce_bool(fx, v, ret, |fx, a, b| fx.bcx.ins().bor(a, b)); + }; + // simd_fabs // simd_saturating_add // simd_bitmask // simd_select - // simd_reduce_add_{,un}ordered // simd_rem } } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 10f515e38e..6c472e6774 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -50,7 +50,7 @@ pub(crate) fn maybe_create_entry_wrapper( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); let cmain_sig = Signature { params: vec![ diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index ff878af7f5..a9f060e51d 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -80,7 +80,7 @@ impl CommentWriter { "sig {:?}", tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &crate::abi::fn_sig_for_fn_abi(tcx, instance) + crate::abi::fn_sig_for_fn_abi(tcx, instance) ) ), String::new(), diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index 690d96764a..67495c7414 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -67,3 +67,15 @@ pub(crate) fn trap_unimplemented(fx: &mut FunctionCx<'_, '_, impl Module>, msg: let true_ = fx.bcx.ins().iconst(types::I32, 1); fx.bcx.ins().trapnz(true_, TrapCode::User(!0)); } + +/// Like `trap_unimplemented` but returns a fake value of the specified type. +/// +/// Trap code: user65535 +pub(crate) fn trap_unimplemented_ret_value<'tcx>( + fx: &mut FunctionCx<'_, 'tcx, impl Module>, + dest_layout: TyAndLayout<'tcx>, + msg: impl AsRef, +) -> CValue<'tcx> { + trap_unimplemented(fx, msg); + CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout) +} diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 0000866c4f..5bcb11fd51 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -455,7 +455,7 @@ impl<'tcx> CPlace<'tcx> { from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) { - match (&from_ty.kind(), &to_ty.kind()) { + match (from_ty.kind(), to_ty.kind()) { (ty::Ref(_, a, _), ty::Ref(_, b, _)) | ( ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), @@ -466,11 +466,11 @@ impl<'tcx> CPlace<'tcx> { (ty::FnPtr(_), ty::FnPtr(_)) => { let from_sig = fx.tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &from_ty.fn_sig(fx.tcx), + from_ty.fn_sig(fx.tcx), ); let to_sig = fx.tcx.normalize_erasing_late_bound_regions( ParamEnv::reveal_all(), - &to_ty.fn_sig(fx.tcx), + to_ty.fn_sig(fx.tcx), ); assert_eq!( from_sig, to_sig, @@ -479,18 +479,20 @@ impl<'tcx> CPlace<'tcx> { ); // fn(&T) -> for<'l> fn(&'l T) is allowed } - (ty::Dynamic(from_traits, _), ty::Dynamic(to_traits, _)) => { - let from_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from_traits); - let to_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_traits); - assert_eq!( - from_traits, to_traits, - "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", - from_traits, to_traits, fx, - ); + (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { + for (from, to) in from_traits.iter().zip(to_traits) { + let from = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); + let to = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + assert_eq!( + from, to, + "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", + from_traits, to_traits, fx, + ); + } // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed } _ => { diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 7857ccb613..915dd3d9ed 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -36,17 +36,17 @@ impl ArgAttributeExt for ArgAttribute { where F: FnMut(llvm::Attribute), { - for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg) + for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg) } } pub trait ArgAttributesExt { - fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>); - fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>); + fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value); + fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value); } impl ArgAttributesExt for ArgAttributes { - fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) { + fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value) { let mut regular = self.regular; unsafe { let deref = self.pointee_size.bytes(); @@ -61,14 +61,20 @@ impl ArgAttributesExt for ArgAttributes { if let Some(align) = self.pointee_align { llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32); } - if regular.contains(ArgAttribute::ByVal) { - llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap()); - } regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn)); + match self.arg_ext { + ArgExtension::None => {} + ArgExtension::Zext => { + llvm::Attribute::ZExt.apply_llfn(idx, llfn); + } + ArgExtension::Sext => { + llvm::Attribute::SExt.apply_llfn(idx, llfn); + } + } } } - fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) { + fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value) { let mut regular = self.regular; unsafe { let deref = self.pointee_size.bytes(); @@ -91,10 +97,16 @@ impl ArgAttributesExt for ArgAttributes { align.bytes() as u32, ); } - if regular.contains(ArgAttribute::ByVal) { - llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap()); - } regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite)); + match self.arg_ext { + ArgExtension::None => {} + ArgExtension::Zext => { + llvm::Attribute::ZExt.apply_callsite(idx, callsite); + } + ArgExtension::Sext => { + llvm::Attribute::SExt.apply_callsite(idx, callsite); + } + } } } } @@ -146,7 +158,7 @@ impl LlvmType for CastTarget { .prefix .iter() .flat_map(|option_kind| { - option_kind.map(|kind| Reg { kind, size: self.prefix_chunk }.llvm_type(cx)) + option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx)) }) .chain((0..rest_count).map(|_| rest_ll_unit)) .collect(); @@ -267,10 +279,12 @@ impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } - PassMode::Indirect(_, Some(_)) => { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); } - PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => { + PassMode::Direct(_) + | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } + | PassMode::Cast(_) => { let next_arg = next(); self.store(bx, next_arg, dst); } @@ -315,14 +329,14 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 } ).sum(); let mut llargument_tys = Vec::with_capacity( - if let PassMode::Indirect(..) = self.ret.mode { 1 } else { 0 } + args_capacity, + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } + args_capacity, ); let llreturn_ty = match self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx), PassMode::Cast(cast) => cast.llvm_type(cx), - PassMode::Indirect(..) => { + PassMode::Indirect { .. } => { llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); cx.type_void() } @@ -342,7 +356,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } - PassMode::Indirect(_, Some(_)) => { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty); let ptr_layout = cx.layout_of(ptr_ty); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true)); @@ -350,7 +364,9 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { continue; } PassMode::Cast(cast) => cast.llvm_type(cx), - PassMode::Indirect(_, None) => cx.type_ptr_to(arg.memory_ty(cx)), + PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + cx.type_ptr_to(arg.memory_ty(cx)) + } }; llargument_tys.push(llarg_ty); } @@ -402,35 +418,54 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { } let mut i = 0; - let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| { - attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty); + let mut apply = |attrs: &ArgAttributes| { + attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), llfn); i += 1; + i - 1 }; match self.ret.mode { PassMode::Direct(ref attrs) => { - attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None); + attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, llfn); + } + PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => { + assert!(!on_stack); + let i = apply(attrs); + llvm::Attribute::StructRet.apply_llfn(llvm::AttributePlace::Argument(i), llfn); } - PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))), _ => {} } for arg in &self.args { if arg.pad.is_some() { - apply(&ArgAttributes::new(), None); + apply(&ArgAttributes::new()); } match arg.mode { PassMode::Ignore => {} - PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => { - apply(attrs, Some(arg.layout.llvm_type(cx))) + PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => { + let i = apply(attrs); + unsafe { + llvm::LLVMRustAddByValAttr( + llfn, + llvm::AttributePlace::Argument(i).as_uint(), + arg.layout.llvm_type(cx), + ); + } } - PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { - apply(attrs, None); - apply(extra_attrs, None); + PassMode::Direct(ref attrs) + | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => { + apply(attrs); + } + PassMode::Indirect { ref attrs, extra_attrs: Some(ref extra_attrs), on_stack } => { + assert!(!on_stack); + apply(attrs); + apply(extra_attrs); } PassMode::Pair(ref a, ref b) => { - apply(a, None); - apply(b, None); + apply(a); + apply(b); + } + PassMode::Cast(_) => { + apply(&ArgAttributes::new()); } - PassMode::Cast(_) => apply(&ArgAttributes::new(), None), } } } @@ -439,15 +474,21 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { // FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite. let mut i = 0; - let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| { - attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty); + let mut apply = |attrs: &ArgAttributes| { + attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), callsite); i += 1; + i - 1 }; match self.ret.mode { PassMode::Direct(ref attrs) => { - attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None); + attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, callsite); + } + PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => { + assert!(!on_stack); + let i = apply(attrs); + llvm::Attribute::StructRet + .apply_callsite(llvm::AttributePlace::Argument(i), callsite); } - PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))), _ => {} } if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi { @@ -465,22 +506,39 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { } for arg in &self.args { if arg.pad.is_some() { - apply(&ArgAttributes::new(), None); + apply(&ArgAttributes::new()); } match arg.mode { PassMode::Ignore => {} - PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => { - apply(attrs, Some(arg.layout.llvm_type(bx))) + PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => { + let i = apply(attrs); + unsafe { + llvm::LLVMRustAddByValCallSiteAttr( + callsite, + llvm::AttributePlace::Argument(i).as_uint(), + arg.layout.llvm_type(bx), + ); + } } - PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { - apply(attrs, None); - apply(extra_attrs, None); + PassMode::Direct(ref attrs) + | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => { + apply(attrs); + } + PassMode::Indirect { + ref attrs, + extra_attrs: Some(ref extra_attrs), + on_stack: _, + } => { + apply(attrs); + apply(extra_attrs); } PassMode::Pair(ref a, ref b) => { - apply(a, None); - apply(b, None); + apply(a); + apply(b); + } + PassMode::Cast(_) => { + apply(&ArgAttributes::new()); } - PassMode::Cast(_) => apply(&ArgAttributes::new(), None), } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index b5d279eeb6..8801211d51 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -261,6 +261,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::Hexagon => {} InlineAsmArch::Mips | InlineAsmArch::Mips64 => {} InlineAsmArch::SpirV => {} + InlineAsmArch::Wasm32 => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -519,6 +520,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk", + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } @@ -584,6 +586,7 @@ fn modifier_to_llvm( _ => unreachable!(), }, InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None, InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } @@ -626,6 +629,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 87bcce07b3..97c38e04bc 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -35,11 +35,7 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { Attribute::NoInline.apply_llfn(Function, val); } } - None => { - Attribute::InlineHint.unapply_llfn(Function, val); - Attribute::AlwaysInline.unapply_llfn(Function, val); - Attribute::NoInline.unapply_llfn(Function, val); - } + None => {} }; } @@ -131,9 +127,6 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { return; } - // FIXME(richkadel): Make sure probestack plays nice with `-Z instrument-coverage` - // or disable it if not, similar to above early exits. - // Flag our internal `__rust_probestack` function as the stack probe symbol. // This is defined in the `compiler-builtins` crate for each architecture. llvm::AddFunctionAttrStringValue( @@ -144,25 +137,6 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { ); } -fn translate_obsolete_target_features(feature: &str) -> &str { - const LLVM9_FEATURE_CHANGES: &[(&str, &str)] = - &[("+fp-only-sp", "-fp64"), ("-fp-only-sp", "+fp64"), ("+d16", "-d32"), ("-d16", "+d32")]; - if llvm_util::get_major_version() >= 9 { - for &(old, new) in LLVM9_FEATURE_CHANGES { - if feature == old { - return new; - } - } - } else { - for &(old, new) in LLVM9_FEATURE_CHANGES { - if feature == new { - return old; - } - } - } - feature -} - pub fn llvm_target_features(sess: &Session) -> impl Iterator { const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"]; @@ -172,12 +146,7 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator { .target_feature .split(',') .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); - sess.target - .features - .split(',') - .chain(cmdline) - .filter(|l| !l.is_empty()) - .map(translate_obsolete_target_features) + sess.target.features.split(',').chain(cmdline).filter(|l| !l.is_empty()) } pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { @@ -253,12 +222,14 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: } } - // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites). - if instance.def.requires_inline(cx.tcx) { - inline(cx, llfn, attributes::InlineAttr::Hint); - } - - inline(cx, llfn, codegen_fn_attrs.inline.clone()); + let inline_attr = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + InlineAttr::Never + } else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) { + InlineAttr::Hint + } else { + codegen_fn_attrs.inline + }; + inline(cx, llfn, inline_attr); // The `uwtable` attribute according to LLVM is: // diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 64fd1d09cc..29415973ed 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -6,7 +6,9 @@ use crate::llvm::{self, build_string, False, True}; use crate::{LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::FxHashMap; @@ -728,7 +730,14 @@ pub unsafe fn optimize_thin_module( cgcx: &CodegenContext, ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - let tm = (cgcx.tm_factory.0)().map_err(|e| write::llvm_err(&diag_handler, &e))?; + + let module_name = &thin_module.shared.module_names[thin_module.idx]; + let split_dwarf_file = cgcx + .output_filenames + .split_dwarf_filename(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap())); + let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; + let tm = + (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?; // Right now the implementation we've got only works over serialized // modules, so we create a fresh new LLVM context and parse the module @@ -736,12 +745,8 @@ pub unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = parse_module( - llcx, - &thin_module.shared.module_names[thin_module.idx], - thin_module.data(), - &diag_handler, - )? as *const _; + let llmod_raw = + parse_module(llcx, &module_name, thin_module.data(), &diag_handler)? as *const _; let module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm }, name: thin_module.name().to_string(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index e6acb6860b..3fda1e26da 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -11,7 +11,10 @@ use crate::llvm_util; use crate::type_::Type; use crate::LlvmCodegenBackend; use crate::ModuleLlvm; -use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig, + TargetMachineFactoryFn, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::small_c_str::SmallCStr; @@ -20,7 +23,9 @@ use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath}; +use rustc_session::config::{ + self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath, +}; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::InnerSpan; @@ -49,11 +54,31 @@ pub fn write_output_file( pm: &llvm::PassManager<'ll>, m: &'ll llvm::Module, output: &Path, + dwo_output: Option<&Path>, file_type: llvm::FileType, ) -> Result<(), FatalError> { unsafe { let output_c = path_to_c_string(output); - let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type); + let result = if let Some(dwo_output) = dwo_output { + let dwo_output_c = path_to_c_string(dwo_output); + llvm::LLVMRustWriteOutputFile( + target, + pm, + m, + output_c.as_ptr(), + dwo_output_c.as_ptr(), + file_type, + ) + } else { + llvm::LLVMRustWriteOutputFile( + target, + pm, + m, + output_c.as_ptr(), + std::ptr::null(), + file_type, + ) + }; result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); llvm_err(handler, &msg) @@ -62,12 +87,17 @@ pub fn write_output_file( } pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine { - target_machine_factory(sess, config::OptLevel::No)() + let config = TargetMachineFactoryConfig { split_dwarf_file: None }; + target_machine_factory(sess, config::OptLevel::No)(config) .unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise()) } -pub fn create_target_machine(tcx: TyCtxt<'_>) -> &'static mut llvm::TargetMachine { - target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))() +pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine { + let split_dwarf_file = tcx + .output_filenames(LOCAL_CRATE) + .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name)); + let config = TargetMachineFactoryConfig { split_dwarf_file }; + target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) } @@ -122,7 +152,7 @@ fn to_llvm_code_model(code_model: Option) -> llvm::CodeModel { pub fn target_machine_factory( sess: &Session, optlvl: config::OptLevel, -) -> Arc Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { +) -> TargetMachineFactoryFn { let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); @@ -152,7 +182,8 @@ pub fn target_machine_factory( let features = features.join(","); let features = CString::new(features).unwrap(); let abi = SmallCStr::new(&sess.target.llvm_abiname); - let trap_unreachable = sess.target.trap_unreachable; + let trap_unreachable = + sess.opts.debugging_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); @@ -162,7 +193,10 @@ pub fn target_machine_factory( let use_init_array = !sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); - Arc::new(move || { + Arc::new(move |config: TargetMachineFactoryConfig| { + let split_dwarf_file = config.split_dwarf_file.unwrap_or_default(); + let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap(); + let tm = unsafe { llvm::LLVMRustCreateTargetMachine( triple.as_ptr(), @@ -181,6 +215,7 @@ pub fn target_machine_factory( emit_stack_size_section, relax_elf_relocations, use_init_array, + split_dwarf_file.as_ptr(), ) }; @@ -377,11 +412,6 @@ fn get_pgo_use_path(config: &ModuleConfig) -> Option { } pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { - // We only support the new pass manager starting with LLVM 9. - if llvm_util::get_major_version() < 9 { - return false; - } - // The new pass manager is disabled by default. config.new_llvm_pass_manager } @@ -789,7 +819,15 @@ pub(crate) unsafe fn codegen( llmod }; with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) + write_output_file( + diag_handler, + tm, + cpm, + llmod, + &path, + None, + llvm::FileType::AssemblyFile, + ) })?; } @@ -798,6 +836,15 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]); + + let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name); + let dwo_out = match cgcx.split_dwarf_kind { + // Don't change how DWARF is emitted in single mode (or when disabled). + SplitDwarfKind::None | SplitDwarfKind::Single => None, + // Emit (a subset of the) DWARF into a separate file in split mode. + SplitDwarfKind::Split => Some(dwo_out.as_path()), + }; + with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file( diag_handler, @@ -805,6 +852,7 @@ pub(crate) unsafe fn codegen( cpm, llmod, &obj_out, + dwo_out, llvm::FileType::ObjectFile, ) })?; @@ -832,6 +880,7 @@ pub(crate) unsafe fn codegen( Ok(module.into_compiled_module( config.emit_obj != EmitObj::None, + cgcx.split_dwarf_kind == SplitDwarfKind::Split, config.emit_bc, &cgcx.output_filenames, )) @@ -925,9 +974,7 @@ unsafe fn embed_bitcode( || cgcx.opts.target_triple.triple().starts_with("asmjs") { // nothing to do here - } else if cgcx.opts.target_triple.triple().contains("windows") - || cgcx.opts.target_triple.triple().contains("uefi") - { + } else if cgcx.is_pe_coff { let asm = " .section .llvmbc,\"n\" .section .llvmcmd,\"n\" diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 1090d4a25c..7d01f6a549 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -97,14 +97,12 @@ pub fn compile_codegen_unit( tcx: TyCtxt<'tcx>, cgu_name: Symbol, ) -> (ModuleCodegen, u64) { - let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string()); let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); let time_to_codegen = start_time.elapsed(); - drop(prof_timer); // We assume that the cost to run LLVM on a CGU is proportional to // the time we needed for codegenning it. @@ -112,6 +110,10 @@ pub fn compile_codegen_unit( fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); + let _prof_timer = tcx.prof.generic_activity_with_args( + "codegen_module", + &[cgu_name.to_string(), cgu.size_estimate().to_string()], + ); // Instantiate monomorphizations without filling out definitions yet... let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index b6e922ca54..8dd4030807 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -100,11 +100,6 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { } } -fn strip_function_ptr_alignment(data_layout: String) -> String { - // FIXME: Make this more general. - data_layout.replace("-Fi8-", "-") -} - fn strip_x86_address_spaces(data_layout: String) -> String { data_layout.replace("-p270:32:32-p271:32:32-p272:64:64-", "-") } @@ -119,9 +114,6 @@ pub unsafe fn create_module( let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); let mut target_data_layout = sess.target.data_layout.clone(); - if llvm_util::get_major_version() < 9 { - target_data_layout = strip_function_ptr_alignment(target_data_layout); - } if llvm_util::get_major_version() < 10 && (sess.target.arch == "x86" || sess.target.arch == "x86_64") { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 41827a91ba..72ba5bbd5f 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -3,11 +3,14 @@ use crate::coverageinfo; use crate::llvm; use llvm::coverageinfo::CounterMappingRegion; -use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression}; -use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods}; -use rustc_data_structures::fx::FxIndexSet; +use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression, FunctionCoverage}; +use rustc_codegen_ssa::traits::ConstMethods; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_llvm::RustString; use rustc_middle::mir::coverage::CodeRegion; +use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_span::Symbol; use std::ffi::CString; @@ -15,9 +18,9 @@ use tracing::debug; /// Generates and exports the Coverage Map. /// -/// This Coverage Map complies with Coverage Mapping Format version 3 (zero-based encoded as 2), -/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format) -/// and published in Rust's current (July 2020) fork of LLVM. This version is supported by the +/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3), +/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format) +/// and published in Rust's current (November 2020) fork of LLVM. This version is supported by the /// LLVM coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM. /// /// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with @@ -26,7 +29,17 @@ use tracing::debug; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { - let function_coverage_map = match cx.coverage_context() { + let tcx = cx.tcx; + // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3). + // If not, the LLVM Version must be less than 11. + let version = coverageinfo::mapping_version(); + if version != 3 { + tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); + } + + debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); + + let mut function_coverage_map = match cx.coverage_context() { Some(ctx) => ctx.take_function_coverage_map(), None => return, }; @@ -35,49 +48,54 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { return; } + add_unreachable_coverage(tcx, &mut function_coverage_map); + let mut mapgen = CoverageMapGenerator::new(); // Encode coverage mappings and generate function records - let mut function_records = Vec::<&'ll llvm::Value>::new(); - let coverage_mappings_buffer = llvm::build_byte_buffer(|coverage_mappings_buffer| { - for (instance, function_coverage) in function_coverage_map.into_iter() { - debug!("Generate coverage map for: {:?}", instance); - - let mangled_function_name = cx.tcx.symbol_name(instance).to_string(); - let function_source_hash = function_coverage.source_hash(); - let (expressions, counter_regions) = - function_coverage.get_expressions_and_counter_regions(); - - let old_len = coverage_mappings_buffer.len(); - mapgen.write_coverage_mappings(expressions, counter_regions, coverage_mappings_buffer); - let mapping_data_size = coverage_mappings_buffer.len() - old_len; - debug_assert!( - mapping_data_size > 0, - "Every `FunctionCoverage` should have at least one counter" - ); - - let function_record = mapgen.make_function_record( - cx, - mangled_function_name, - function_source_hash, - mapping_data_size, - ); - function_records.push(function_record); - } - }); + let mut function_data = Vec::new(); + for (instance, function_coverage) in function_coverage_map { + debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance); + let mangled_function_name = tcx.symbol_name(instance).to_string(); + let function_source_hash = function_coverage.source_hash(); + let (expressions, counter_regions) = + function_coverage.get_expressions_and_counter_regions(); + + let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| { + mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer); + }); + debug_assert!( + coverage_mapping_buffer.len() > 0, + "Every `FunctionCoverage` should have at least one counter" + ); + + function_data.push((mangled_function_name, function_source_hash, coverage_mapping_buffer)); + } // Encode all filenames referenced by counters/expressions in this module let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| { coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer); }); + let filenames_size = filenames_buffer.len(); + let filenames_val = cx.const_bytes(&filenames_buffer[..]); + let filenames_ref = coverageinfo::hash_bytes(filenames_buffer); + // Generate the LLVM IR representation of the coverage map and store it in a well-known global - mapgen.save_generated_coverage_map( - cx, - function_records, - filenames_buffer, - coverage_mappings_buffer, - ); + let cov_data_val = mapgen.generate_coverage_map(cx, version, filenames_size, filenames_val); + + for (mangled_function_name, function_source_hash, coverage_mapping_buffer) in function_data { + save_function_record( + cx, + mangled_function_name, + function_source_hash, + filenames_ref, + coverage_mapping_buffer, + ); + } + + // Save the coverage data value to LLVM IR + coverageinfo::save_cov_data_to_mod(cx, cov_data_val); } struct CoverageMapGenerator { @@ -92,12 +110,12 @@ impl CoverageMapGenerator { /// Using the `expressions` and `counter_regions` collected for the current function, generate /// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use /// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into - /// the given `coverage_mappings` byte buffer, compliant with the LLVM Coverage Mapping format. - fn write_coverage_mappings( + /// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format. + fn write_coverage_mapping( &mut self, expressions: Vec, counter_regions: impl Iterator, - coverage_mappings_buffer: &RustString, + coverage_mapping_buffer: &RustString, ) { let mut counter_regions = counter_regions.collect::>(); if counter_regions.is_empty() { @@ -145,89 +163,228 @@ impl CoverageMapGenerator { virtual_file_mapping, expressions, mapping_regions, - coverage_mappings_buffer, + coverage_mapping_buffer, ); } - /// Generate and return the function record `Value` - fn make_function_record( - &mut self, - cx: &CodegenCx<'ll, 'tcx>, - mangled_function_name: String, - function_source_hash: u64, - mapping_data_size: usize, - ) -> &'ll llvm::Value { - let name_ref = coverageinfo::compute_hash(&mangled_function_name); - let name_ref_val = cx.const_u64(name_ref); - let mapping_data_size_val = cx.const_u32(mapping_data_size as u32); - let func_hash_val = cx.const_u64(function_source_hash); - cx.const_struct( - &[name_ref_val, mapping_data_size_val, func_hash_val], - /*packed=*/ true, - ) - } - - /// Combine the filenames and coverage mappings buffers, construct coverage map header and the - /// array of function records, and combine everything into the complete coverage map. Save the - /// coverage map data into the LLVM IR as a static global using a specific, well-known section - /// and name. - fn save_generated_coverage_map( + /// Construct coverage map header and the array of function records, and combine them into the + /// coverage map. Save the coverage map data into the LLVM IR as a static global using a + /// specific, well-known section and name. + fn generate_coverage_map( self, cx: &CodegenCx<'ll, 'tcx>, - function_records: Vec<&'ll llvm::Value>, - filenames_buffer: Vec, - mut coverage_mappings_buffer: Vec, - ) { - // Concatenate the encoded filenames and encoded coverage mappings, and add additional zero - // bytes as-needed to ensure 8-byte alignment. - let mut coverage_size = coverage_mappings_buffer.len(); - let filenames_size = filenames_buffer.len(); - let remaining_bytes = - (filenames_size + coverage_size) % coverageinfo::COVMAP_VAR_ALIGN_BYTES; - if remaining_bytes > 0 { - let pad = coverageinfo::COVMAP_VAR_ALIGN_BYTES - remaining_bytes; - coverage_mappings_buffer.append(&mut [0].repeat(pad)); - coverage_size += pad; - } - let filenames_and_coverage_mappings = [filenames_buffer, coverage_mappings_buffer].concat(); - let filenames_and_coverage_mappings_val = - cx.const_bytes(&filenames_and_coverage_mappings[..]); - - debug!( - "cov map: n_records = {}, filenames_size = {}, coverage_size = {}, 0-based version = {}", - function_records.len(), - filenames_size, - coverage_size, - coverageinfo::mapping_version() - ); + version: u32, + filenames_size: usize, + filenames_val: &'ll llvm::Value, + ) -> &'ll llvm::Value { + debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version); - // Create the coverage data header - let n_records_val = cx.const_u32(function_records.len() as u32); + // Create the coverage data header (Note, fields 0 and 2 are now always zero, + // as of `llvm::coverage::CovMapVersion::Version4`.) + let zero_was_n_records_val = cx.const_u32(0); let filenames_size_val = cx.const_u32(filenames_size as u32); - let coverage_size_val = cx.const_u32(coverage_size as u32); - let version_val = cx.const_u32(coverageinfo::mapping_version()); + let zero_was_coverage_size_val = cx.const_u32(0); + let version_val = cx.const_u32(version); let cov_data_header_val = cx.const_struct( - &[n_records_val, filenames_size_val, coverage_size_val, version_val], + &[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val], /*packed=*/ false, ); - // Create the function records array - let name_ref_from_u64 = cx.type_i64(); - let mapping_data_size_from_u32 = cx.type_i32(); - let func_hash_from_u64 = cx.type_i64(); - let function_record_ty = cx.type_struct( - &[name_ref_from_u64, mapping_data_size_from_u32, func_hash_from_u64], - /*packed=*/ true, - ); - let function_records_val = cx.const_array(function_record_ty, &function_records[..]); - // Create the complete LLVM coverage data value to add to the LLVM IR - let cov_data_val = cx.const_struct( - &[cov_data_header_val, function_records_val, filenames_and_coverage_mappings_val], - /*packed=*/ false, - ); + cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false) + } +} + +/// Construct a function record and combine it with the function's coverage mapping data. +/// Save the function record into the LLVM IR as a static global using a +/// specific, well-known section and name. +fn save_function_record( + cx: &CodegenCx<'ll, 'tcx>, + mangled_function_name: String, + function_source_hash: u64, + filenames_ref: u64, + coverage_mapping_buffer: Vec, +) { + // Concatenate the encoded coverage mappings + let coverage_mapping_size = coverage_mapping_buffer.len(); + let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer[..]); + + let func_name_hash = coverageinfo::hash_str(&mangled_function_name); + let func_name_hash_val = cx.const_u64(func_name_hash); + let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32); + let func_hash_val = cx.const_u64(function_source_hash); + let filenames_ref_val = cx.const_u64(filenames_ref); + let func_record_val = cx.const_struct( + &[ + func_name_hash_val, + coverage_mapping_size_val, + func_hash_val, + filenames_ref_val, + coverage_mapping_val, + ], + /*packed=*/ true, + ); - // Save the coverage data value to LLVM IR - coverageinfo::save_map_to_mod(cx, cov_data_val); + // At the present time, the coverage map for Rust assumes every instrumented function `is_used`. + // Note that Clang marks functions as "unused" in `CodeGenPGO::emitEmptyCounterMapping`. (See: + // https://github.com/rust-lang/llvm-project/blob/de02a75e398415bad4df27b4547c25b896c8bf3b/clang%2Flib%2FCodeGen%2FCodeGenPGO.cpp#L877-L878 + // for example.) + // + // It's not yet clear if or how this may be applied to Rust in the future, but the `is_used` + // argument is available and handled similarly. + let is_used = true; + coverageinfo::save_func_record_to_mod(cx, func_name_hash, func_record_val, is_used); +} + +/// When finalizing the coverage map, `FunctionCoverage` only has the `CodeRegion`s and counters for +/// the functions that went through codegen; such as public functions and "used" functions +/// (functions referenced by other "used" or public items). Any other functions considered unused, +/// or "Unreachable" were still parsed and processed through the MIR stage. +/// +/// We can find the unreachable functions by the set difference of all MIR `DefId`s (`tcx` query +/// `mir_keys`) minus the codegenned `DefId`s (`tcx` query `collect_and_partition_mono_items`). +/// +/// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and +/// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`) +/// allocated to only one of those CGUs. We must NOT inject any "Unreachable" functions's +/// `CodeRegion`s more than once, so we have to pick which CGU's `function_coverage_map` to add +/// each "Unreachable" function to. +/// +/// Some constraints: +/// +/// 1. The file name of an "Unreachable" function must match the file name of the existing +/// codegenned (covered) function to which the unreachable code regions will be added. +/// 2. The function to which the unreachable code regions will be added must not be a genaric +/// function (must not have type parameters) because the coverage tools will get confused +/// if the codegenned function has more than one instantiation and additional `CodeRegion`s +/// attached to only one of those instantiations. +fn add_unreachable_coverage<'tcx>( + tcx: TyCtxt<'tcx>, + function_coverage_map: &mut FxHashMap, FunctionCoverage<'tcx>>, +) { + // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources + // of compiler state data that might help (or better sources that could be exposed, but + // aren't yet)? + + // Note: If the crate *only* defines generic functions, there are no codegenerated non-generic + // functions to add any unreachable code to. In this case, the unreachable code regions will + // have no coverage, instead of having coverage with zero executions. + // + // This is probably still an improvement over Clang, which does not generate any coverage + // for uninstantiated template functions. + + let has_non_generic_def_ids = + function_coverage_map.keys().any(|instance| instance.def.attrs(tcx).len() == 0); + + if !has_non_generic_def_ids { + // There are no non-generic functions to add unreachable `CodeRegion`s to + return; + } + + let all_def_ids: DefIdSet = + tcx.mir_keys(LOCAL_CRATE).iter().map(|local_def_id| local_def_id.to_def_id()).collect(); + + let (codegenned_def_ids, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + + let mut unreachable_def_ids_by_file: FxHashMap> = FxHashMap::default(); + for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) { + // Make sure the non-codegenned (unreachable) function has a file_name + if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) { + let def_ids = unreachable_def_ids_by_file + .entry(*non_codegenned_file_name) + .or_insert_with(|| Vec::new()); + def_ids.push(non_codegenned_def_id); + } + } + + if unreachable_def_ids_by_file.is_empty() { + // There are no unreachable functions with file names to add (in any CGU) + return; + } + + // Since there may be multiple `CodegenUnit`s, some codegenned_def_ids may be codegenned in a + // different CGU, and will be added to the function_coverage_map for each CGU. Determine which + // function_coverage_map has the responsibility for publishing unreachable coverage + // based on file name: + // + // For each covered file name, sort ONLY the non-generic codegenned_def_ids, and if + // covered_def_ids.contains(the first def_id) for a given file_name, add the unreachable code + // region in this function_coverage_map. Otherwise, ignore it and assume another CGU's + // function_coverage_map will be adding it (because it will be first for one, and only one, + // of them). + let mut sorted_codegenned_def_ids: Vec = + codegenned_def_ids.iter().map(|def_id| *def_id).collect(); + sorted_codegenned_def_ids.sort_unstable(); + + let mut first_covered_def_id_by_file: FxHashMap = FxHashMap::default(); + for &def_id in sorted_codegenned_def_ids.iter() { + // Only consider non-generic functions, to potentially add unreachable code regions + if tcx.generics_of(def_id).count() == 0 { + if let Some(covered_file_name) = tcx.covered_file_name(def_id) { + // Only add files known to have unreachable functions + if unreachable_def_ids_by_file.contains_key(covered_file_name) { + first_covered_def_id_by_file.entry(*covered_file_name).or_insert(def_id); + } + } + } + } + + // Get the set of def_ids with coverage regions, known by *this* CoverageContext. + let cgu_covered_def_ids: DefIdSet = + function_coverage_map.keys().map(|instance| instance.def.def_id()).collect(); + + let mut cgu_covered_files: FxHashSet = first_covered_def_id_by_file + .iter() + .filter_map( + |(&file_name, def_id)| { + if cgu_covered_def_ids.contains(def_id) { Some(file_name) } else { None } + }, + ) + .collect(); + + // Find the first covered, non-generic function (instance) for each cgu_covered_file. Take the + // unreachable code regions for that file, and add them to the function. + // + // There are three `for` loops here, but (a) the lists have already been reduced to the minimum + // required values, the lists are further reduced (by `remove()` calls) when elements are no + // longer needed, and there are several opportunities to branch out of loops early. + for (instance, function_coverage) in function_coverage_map.iter_mut() { + if instance.def.attrs(tcx).len() > 0 { + continue; + } + // The covered function is not generic... + let covered_def_id = instance.def.def_id(); + if let Some(covered_file_name) = tcx.covered_file_name(covered_def_id) { + if !cgu_covered_files.remove(&covered_file_name) { + continue; + } + // The covered function's file is one of the files with unreachable code regions, so + // all of the unreachable code regions for this file will be added to this function. + for def_id in + unreachable_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() + { + // Note, this loop adds an unreachable code regions for each MIR-derived region. + // Alternatively, we could add a single code region for the maximum span of all + // code regions here. + // + // Observed downsides of this approach are: + // + // 1. The coverage results will appear inconsistent compared with the same (or + // similar) code in a function that is reached. + // 2. If the function is unreachable from one crate but reachable when compiling + // another referencing crate (such as a cross-crate reference to a + // generic function or inlined function), actual coverage regions overlaid + // on a single larger code span of `Zero` coverage can appear confusing or + // wrong. Chaning the unreachable coverage from a `code_region` to a + // `gap_region` can help, but still can look odd with `0` line counts for + // lines between executed (> 0) lines (such as for blank lines or comments). + for ®ion in tcx.covered_code_regions(def_id) { + function_coverage.add_unreachable_region(region.clone()); + } + } + if cgu_covered_files.is_empty() { + break; + } + } } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index e21e03822e..e777f363eb 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -23,7 +23,7 @@ use tracing::debug; pub mod mapgen; -const COVMAP_VAR_ALIGN_BYTES: usize = 8; +const VAR_ALIGN_BYTES: usize = 8; /// A context object for maintaining all state needed by the coverageinfo module. pub struct CrateCoverageContext<'tcx> { @@ -177,17 +177,20 @@ pub(crate) fn write_mapping_to_buffer( ); } } +pub(crate) fn hash_str(strval: &str) -> u64 { + let strval = CString::new(strval).expect("null error converting hashable str to C string"); + unsafe { llvm::LLVMRustCoverageHashCString(strval.as_ptr()) } +} -pub(crate) fn compute_hash(name: &str) -> u64 { - let name = CString::new(name).expect("null error converting hashable name to C string"); - unsafe { llvm::LLVMRustCoverageComputeHash(name.as_ptr()) } +pub(crate) fn hash_bytes(bytes: Vec) -> u64 { + unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) } } pub(crate) fn mapping_version() -> u32 { unsafe { llvm::LLVMRustCoverageMappingVersion() } } -pub(crate) fn save_map_to_mod<'ll, 'tcx>( +pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, cov_data_val: &'ll llvm::Value, ) { @@ -198,7 +201,7 @@ pub(crate) fn save_map_to_mod<'ll, 'tcx>( debug!("covmap var name: {:?}", covmap_var_name); let covmap_section_name = llvm::build_string(|s| unsafe { - llvm::LLVMRustCoverageWriteSectionNameToString(cx.llmod, s); + llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s); }) .expect("Rust Coverage section name failed UTF-8 conversion"); debug!("covmap section name: {:?}", covmap_section_name); @@ -206,8 +209,43 @@ pub(crate) fn save_map_to_mod<'ll, 'tcx>( let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name); llvm::set_initializer(llglobal, cov_data_val); llvm::set_global_constant(llglobal, true); - llvm::set_linkage(llglobal, llvm::Linkage::InternalLinkage); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::set_section(llglobal, &covmap_section_name); - llvm::set_alignment(llglobal, COVMAP_VAR_ALIGN_BYTES); + llvm::set_alignment(llglobal, VAR_ALIGN_BYTES); + cx.add_used_global(llglobal); +} + +pub(crate) fn save_func_record_to_mod<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + func_name_hash: u64, + func_record_val: &'ll llvm::Value, + is_used: bool, +) { + // Assign a name to the function record. This is used to merge duplicates. + // + // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that + // are included-but-not-used. If (or when) Rust generates functions that are + // included-but-not-used, note that a dummy description for a function included-but-not-used + // in a Crate can be replaced by full description provided by a different Crate. The two kinds + // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by + // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging. + let func_record_var_name = + format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }); + debug!("function record var name: {:?}", func_record_var_name); + + let func_record_section_name = llvm::build_string(|s| unsafe { + llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s); + }) + .expect("Rust Coverage function record section name failed UTF-8 conversion"); + debug!("function record section name: {:?}", func_record_section_name); + + let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name); + llvm::set_initializer(llglobal, func_record_val); + llvm::set_global_constant(llglobal, true); + llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); + llvm::set_visibility(llglobal, llvm::Visibility::Hidden); + llvm::set_section(llglobal, &func_record_section_name); + llvm::set_alignment(llglobal, VAR_ALIGN_BYTES); + llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); cx.add_used_global(llglobal); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 6737872f20..7673dfb744 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -92,7 +92,7 @@ fn make_mir_scope( let callee = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &callee, + callee, ); let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]); cx.dbg_scope_fn(callee, &callee_fn_abi, None) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 27b81ebcff..fa285f3488 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -189,7 +189,7 @@ impl TypeMap<'ll, 'tcx> { // something that provides more than the 64 bits of the DefaultHasher. let mut hasher = StableHasher::new(); let mut hcx = cx.tcx.create_stable_hashing_context(); - let type_ = cx.tcx.erase_regions(&type_); + let type_ = cx.tcx.erase_regions(type_); hcx.while_hashing_spans(false, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { type_.hash_stable(hcx, &mut hasher); @@ -427,7 +427,7 @@ fn subroutine_type_metadata( span: Span, ) -> MetadataCreationResult<'ll> { let signature = - cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &signature); + cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature); let signature_metadata: Vec<_> = iter::once( // return type @@ -993,9 +993,15 @@ pub fn compile_unit_metadata( let producer = format!("clang LLVM ({})", rustc_producer); let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); - let work_dir = tcx.sess.working_dir.0.to_string_lossy(); let flags = "\0"; - let split_name = ""; + + let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory; + let split_name = tcx + .output_filenames(LOCAL_CRATE) + .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name)) + .unwrap_or_default(); + let out_dir = out_dir.to_str().unwrap(); + let split_name = split_name.to_str().unwrap(); // FIXME(#60020): // @@ -1020,8 +1026,8 @@ pub fn compile_unit_metadata( debug_context.builder, name_in_debuginfo.as_ptr().cast(), name_in_debuginfo.len(), - work_dir.as_ptr().cast(), - work_dir.len(), + out_dir.as_ptr().cast(), + out_dir.len(), llvm::ChecksumKind::None, ptr::null(), 0, @@ -1039,6 +1045,8 @@ pub fn compile_unit_metadata( split_name.as_ptr().cast(), split_name.len(), kind, + 0, + tcx.sess.opts.debugging_opts.split_dwarf_inlining, ); if tcx.sess.opts.debugging_opts.profile { @@ -1152,10 +1160,7 @@ impl<'ll> MemberDescription<'ll> { self.size.bits(), self.align.bits() as u32, self.offset.bits(), - match self.discriminant { - None => None, - Some(value) => Some(cx.const_u64(value)), - }, + self.discriminant.map(|v| cx.const_u64(v)), self.flags, self.type_metadata, ) @@ -1412,10 +1417,11 @@ fn generator_layout_and_saved_local_names( let state_arg = mir::Local::new(1); for var in &body.var_debug_info { - if var.place.local != state_arg { + let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue }; + if place.local != state_arg { continue; } - match var.place.projection[..] { + match place.projection[..] { [ // Deref of the `Pin<&mut Self>` state argument. mir::ProjectionElem::Field(..), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 5065ff01ae..ccbe7325cc 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -501,7 +501,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &cx.tcx.type_of(impl_def_id), + cx.tcx.type_of(impl_def_id), ); // Only "class" methods are generally understood by LLVM, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index d52b3be8cd..bf0d499e6c 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -91,7 +91,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { }; let sig = callee_ty.fn_sig(tcx); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = tcx.item_name(def_id); @@ -777,8 +777,8 @@ fn generic_simd_intrinsic( } let tcx = bx.tcx(); - let sig = tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &callee_ty.fn_sig(tcx)); + let sig = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); let name_str = &*name.as_str(); @@ -792,7 +792,7 @@ fn generic_simd_intrinsic( _ => return_error!("`{}` is not an integral type", in_ty), }; require_simd!(arg_tys[1], "argument"); - let v_len = arg_tys[1].simd_size(tcx); + let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( // Allow masks for vectors with fewer than 8 elements to be // represented with a u8 or i8. @@ -812,8 +812,6 @@ fn generic_simd_intrinsic( // every intrinsic below takes a SIMD vector as its first argument require_simd!(arg_tys[0], "input"); let in_ty = arg_tys[0]; - let in_elem = arg_tys[0].simd_type(tcx); - let in_len = arg_tys[0].simd_size(tcx); let comparison = match name { sym::simd_eq => Some(hir::BinOpKind::Eq), @@ -825,14 +823,15 @@ fn generic_simd_intrinsic( _ => None, }; + let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx()); if let Some(cmp_op) = comparison { require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", in_len, in_ty, ret_ty, @@ -842,7 +841,7 @@ fn generic_simd_intrinsic( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, "expected return type with integer elements, found `{}` with non-integer `{}`", ret_ty, - ret_ty.simd_type(tcx) + out_ty ); return Ok(compare_simd_types( @@ -855,14 +854,14 @@ fn generic_simd_intrinsic( )); } - if name_str.starts_with("simd_shuffle") { - let n: u64 = name_str["simd_shuffle".len()..].parse().unwrap_or_else(|_| { + if let Some(stripped) = name_str.strip_prefix("simd_shuffle") { + let n: u64 = stripped.parse().unwrap_or_else(|_| { span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") }); require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( out_len == n, "expected return type of length {}, found `{}` with length {}", @@ -871,13 +870,13 @@ fn generic_simd_intrinsic( out_len ); require!( - in_elem == ret_ty.simd_type(tcx), + in_elem == out_ty, "expected return element type `{}` (element of input `{}`), \ - found `{}` with element type `{}`", + found `{}` with element type `{}`", in_elem, in_ty, ret_ty, - ret_ty.simd_type(tcx) + out_ty ); let total_len = u128::from(in_len) * 2; @@ -946,7 +945,7 @@ fn generic_simd_intrinsic( let m_elem_ty = in_elem; let m_len = in_len; require_simd!(arg_tys[1], "argument"); - let v_len = arg_tys[1].simd_size(tcx); + let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( m_len == v_len, "mismatched lengths: mask length `{}` != other vector length `{}`", @@ -1173,25 +1172,27 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); // Of the same length: + let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); require!( - in_len == arg_tys[1].simd_size(tcx), + in_len == out_len, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], - arg_tys[1].simd_size(tcx) + out_len ); require!( - in_len == arg_tys[2].simd_size(tcx), + in_len == out_len2, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], - arg_tys[2].simd_size(tcx) + out_len2 ); // The return type must match the first argument type @@ -1215,39 +1216,40 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { - ty::RawPtr(p) if p.ty == in_elem => { - (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) - } + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (pointer_count, underlying_ty) = match element_ty1.kind() { + ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)), _ => { require!( false, "expected element type `{}` of second argument `{}` \ - to be a pointer to the element type `{}` of the first \ - argument `{}`, found `{}` != `*_ {}`", - arg_tys[1].simd_type(tcx), + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*_ {}`", + element_ty1, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx), + element_ty1, in_elem ); unreachable!(); } }; assert!(pointer_count > 0); - assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx))); - assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind() { + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); + match element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, "expected element type `{}` of third argument `{}` \ to be a signed integer type", - arg_tys[2].simd_type(tcx), + element_ty2, arg_tys[2] ); } @@ -1299,25 +1301,27 @@ fn generic_simd_intrinsic( require_simd!(arg_tys[2], "third"); // Of the same length: + let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); require!( - in_len == arg_tys[1].simd_size(tcx), + in_len == element_len1, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], - arg_tys[1].simd_size(tcx) + element_len1 ); require!( - in_len == arg_tys[2].simd_size(tcx), + in_len == element_len2, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], - arg_tys[2].simd_size(tcx) + element_len2 ); // This counts how many pointers @@ -1338,39 +1342,42 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); + let (pointer_count, underlying_ty) = match element_ty1.kind() { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { - (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) + (ptr_count(element_ty1), non_ptr(element_ty1)) } _ => { require!( false, "expected element type `{}` of second argument `{}` \ - to be a pointer to the element type `{}` of the first \ - argument `{}`, found `{}` != `*mut {}`", - arg_tys[1].simd_type(tcx), + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*mut {}`", + element_ty1, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx), + element_ty1, in_elem ); unreachable!(); } }; assert!(pointer_count > 0); - assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx))); - assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind() { + match element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, "expected element type `{}` of third argument `{}` \ - to be a signed integer type", - arg_tys[2].simd_type(tcx), + be a signed integer type", + element_ty2, arg_tys[2] ); } @@ -1567,7 +1574,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, if name == sym::simd_cast { require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ @@ -1578,8 +1585,6 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, out_len ); // casting cares about nominal type, not just structural type - let out_elem = ret_ty.simd_type(tcx); - if in_elem == out_elem { return Ok(args[0].immediate()); } @@ -1695,7 +1700,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, return_error!( "expected element type `{}` of vector type `{}` \ to be a signed or unsigned integer type", - arg_tys[0].simd_type(tcx), + arg_tys[0].simd_size_and_type(bx.tcx()).1, arg_tys[0] ); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 5974b59d39..a58c2fbd8a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -19,7 +19,9 @@ use back::write::{create_informational_target_machine, create_target_machine}; pub use llvm_util::target_features; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; @@ -34,7 +36,6 @@ use rustc_span::symbol::Symbol; use std::any::Any; use std::ffi::CStr; -use std::sync::Arc; mod back { pub mod archive; @@ -109,7 +110,7 @@ impl ExtraBackendMethods for LlvmCodegenBackend { &self, sess: &Session, optlvl: OptLevel, - ) -> Arc Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { + ) -> TargetMachineFactoryFn { back::write::target_machine_factory(sess, optlvl) } fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str { @@ -331,7 +332,7 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; - ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx) } + ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) } } } @@ -352,7 +353,13 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; - let tm = match (cgcx.tm_factory.0)() { + + let split_dwarf_file = cgcx + .output_filenames + .split_dwarf_filename(cgcx.split_dwarf_kind, Some(name.to_str().unwrap())); + let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; + + let tm = match (cgcx.tm_factory)(tm_factory_config) { Ok(m) => m, Err(e) => { handler.struct_err(&e).emit(); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 8b15c8b0eb..707aaa2b53 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -642,7 +642,7 @@ pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_voi pub mod coverageinfo { use super::coverage_map; - /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L205-L221) + /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum RegionKind { @@ -665,13 +665,13 @@ pub mod coverageinfo { /// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the /// coverage map, in accordance with the - /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). + /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). /// The struct composes fields representing the `Counter` type and value(s) (injected counter /// ID, or expression type and operands), the source file (an indirect index into a "filenames /// array", encoded separately), and source location (start and end positions of the represented /// code region). /// - /// Aligns with [llvm::coverage::CounterMappingRegion](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L223-L226) + /// Aligns with [llvm::coverage::CounterMappingRegion](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L224-L227) /// Important: The Rust struct layout (order and types of fields) must match its C++ /// counterpart. #[derive(Copy, Clone, Debug)] @@ -1791,10 +1791,14 @@ extern "C" { pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &'a Value, FuncName: *const c_char) -> &'a Value; - pub fn LLVMRustCoverageComputeHash(Name: *const c_char) -> u64; + pub fn LLVMRustCoverageHashCString(StrVal: *const c_char) -> u64; + pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64; #[allow(improper_ctypes)] - pub fn LLVMRustCoverageWriteSectionNameToString(M: &Module, Str: &RustString); + pub fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString); + + #[allow(improper_ctypes)] + pub fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString); #[allow(improper_ctypes)] pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString); @@ -1826,6 +1830,8 @@ extern "C" { SplitName: *const c_char, SplitNameLen: size_t, kind: DebugEmissionKind, + DWOId: u64, + SplitDebugInlining: bool, ) -> &'a DIDescriptor; pub fn LLVMRustDIBuilderCreateFile( @@ -2147,6 +2153,7 @@ extern "C" { EmitStackSizeSection: bool, RelaxELFRelocations: bool, UseInitArray: bool, + SplitDwarfFile: *const c_char, ) -> Option<&'static mut TargetMachine>; pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine); pub fn LLVMRustAddBuilderLibraryInfo( @@ -2175,6 +2182,7 @@ extern "C" { PM: &PassManager<'a>, M: &'a Module, Output: *const c_char, + DwoOutput: *const c_char, FileType: FileType, ) -> LLVMRustResult; pub fn LLVMRustOptimizeWithNewPassManager( diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 53a404ee01..fc40065a96 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -220,12 +220,24 @@ pub fn set_linkage(llglobal: &Value, linkage: Linkage) { } } +pub fn set_visibility(llglobal: &Value, visibility: Visibility) { + unsafe { + LLVMRustSetVisibility(llglobal, visibility); + } +} + pub fn set_alignment(llglobal: &Value, bytes: usize) { unsafe { ffi::LLVMSetAlignment(llglobal, bytes as c_uint); } } +pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &str) { + unsafe { + LLVMRustSetComdat(llmod, llglobal, name.as_ptr().cast(), name.len()); + } +} + /// Safe wrapper around `LLVMGetParam`, because segfaults are no fun. pub fn get_param(llfn: &Value, index: c_uint) -> &Value { unsafe { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ab70f72dc6..a3139ce5a3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -3,7 +3,6 @@ use crate::llvm; use libc::c_int; use rustc_codegen_ssa::target_features::supported_target_features; use rustc_data_structures::fx::FxHashSet; -use rustc_feature::UnstableFeatures; use rustc_middle::bug; use rustc_session::config::PrintRequest; use rustc_session::Session; @@ -104,7 +103,7 @@ unsafe fn configure_llvm(sess: &Session) { } } - if sess.opts.debugging_opts.llvm_time_trace && get_major_version() >= 9 { + if sess.opts.debugging_opts.llvm_time_trace { // time-trace is not thread safe and running it in parallel will cause seg faults. if !sess.opts.debugging_opts.no_parallel_llvm { bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm") @@ -122,16 +121,21 @@ unsafe fn configure_llvm(sess: &Session) { pub fn time_trace_profiler_finish(file_name: &str) { unsafe { - if get_major_version() >= 9 { - let file_name = CString::new(file_name).unwrap(); - llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr()); - } + let file_name = CString::new(file_name).unwrap(); + llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr()); } } // WARNING: the features after applying `to_llvm_feature` must be known // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. +// To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def +// where the * matches the architecture's name +// Beware to not use the llvm github project for this, but check the git submodule +// found in src/llvm-project +// Though note that Rust can also be build with an external precompiled version of LLVM +// which might lead to failures if the oldest tested / supported LLVM version +// doesn't yet support the relevant intrinsics pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { @@ -139,6 +143,9 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { ("x86", "rdrand") => "rdrnd", ("x86", "bmi1") => "bmi", ("x86", "cmpxchg16b") => "cx16", + ("x86", "avx512vaes") => "vaes", + ("x86", "avx512gfni") => "gfni", + ("x86", "avx512vpclmulqdq") => "vpclmulqdq", ("aarch64", "fp") => "fp-armv8", ("aarch64", "fp16") => "fullfp16", (_, s) => s, @@ -149,13 +156,11 @@ pub fn target_features(sess: &Session) -> Vec { let target_machine = create_informational_target_machine(sess); supported_target_features(sess) .iter() - .filter_map(|&(feature, gate)| { - if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() { - Some(feature) - } else { - None - } - }) + .filter_map( + |&(feature, gate)| { + if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } + }, + ) .filter(|feature| { let llvm_feature = to_llvm_feature(sess, feature); let cstr = CString::new(llvm_feature).unwrap(); diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index e0754d21df..0876907e11 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -40,9 +40,7 @@ fn uncached_llvm_type<'a, 'tcx>( // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str - if !cx.sess().fewer_names() => - { + ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str => { let mut name = with_no_trimmed_paths(|| layout.ty.to_string()); if let (&ty::Adt(def, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) @@ -58,12 +56,6 @@ fn uncached_llvm_type<'a, 'tcx>( } Some(name) } - ty::Adt(..) => { - // If `Some` is returned then a named struct is created in LLVM. Name collisions are - // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that - // can improve perf. - Some(String::new()) - } _ => None, }; @@ -252,7 +244,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(&self.ty); + let normal_ty = cx.tcx.erase_regions(self.ty); let mut defer = None; let llty = if self.ty != normal_ty { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5a627a0efa..a3a2ef0417 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{EncodedMetadata, LibSource}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet}; @@ -21,7 +21,10 @@ use super::archive::ArchiveBuilder; use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; -use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME}; +use crate::{ + looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, + METADATA_FILENAME, +}; use cc::windows_registry; use tempfile::Builder as TempFileBuilder; @@ -96,6 +99,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( path.as_ref(), target_cpu, ); + if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split { + link_dwarf_object(sess, &out_filename); + } } } if sess.opts.json_artifact_notifications { @@ -107,22 +113,30 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( // Remove the temporary object file and metadata if we aren't saving temps sess.time("link_binary_remove_temps", || { if !sess.opts.cg.save_temps { + let remove_temps_from_module = |module: &CompiledModule| { + if let Some(ref obj) = module.object { + remove(sess, obj); + } + + if let Some(ref obj) = module.dwarf_object { + remove(sess, obj); + } + }; + if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) { - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - remove(sess, obj); + for module in &codegen_results.modules { + remove_temps_from_module(module); } } + if let Some(ref metadata_module) = codegen_results.metadata_module { - if let Some(ref obj) = metadata_module.object { - remove(sess, obj); - } + remove_temps_from_module(metadata_module); } + if let Some(ref allocator_module) = codegen_results.allocator_module { - if let Some(ref obj) = allocator_module.object { - remove(sess, obj); - } + remove_temps_from_module(allocator_module); } } }); @@ -279,12 +293,12 @@ pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeT out_filename } -// Create an 'rlib' -// -// An rlib in its current incarnation is essentially a renamed .a file. The -// rlib primarily contains the object file of the crate, but it also contains -// all of the object files from native libraries. This is done by unzipping -// native libraries and inserting all of the contents into this archive. +/// Create an 'rlib'. +/// +/// An rlib in its current incarnation is essentially a renamed .a file. The rlib primarily contains +/// the object file of the crate, but it also contains all of the object files from native +/// libraries. This is done by unzipping native libraries and inserting all of the contents into +/// this archive. fn link_rlib<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, @@ -379,18 +393,17 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( ab } -// Create a static archive -// -// This is essentially the same thing as an rlib, but it also involves adding -// all of the upstream crates' objects into the archive. This will slurp in -// all of the native libraries of upstream dependencies as well. -// -// Additionally, there's no way for us to link dynamic libraries, so we warn -// about all dynamic library dependencies that they're not linked in. -// -// There's no need to include metadata in a static archive, so ensure to not -// link in the metadata object file (and also don't prepare the archive with a -// metadata file). +/// Create a static archive. +/// +/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream +/// crates' objects into the archive. This will slurp in all of the native libraries of upstream +/// dependencies as well. +/// +/// Additionally, there's no way for us to link dynamic libraries, so we warn about all dynamic +/// library dependencies that they're not linked in. +/// +/// There's no need to include metadata in a static archive, so ensure to not link in the metadata +/// object file (and also don't prepare the archive with a metadata file). fn link_staticlib<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, codegen_results: &CodegenResults, @@ -447,10 +460,73 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( } } -// Create a dynamic library or executable -// -// This will invoke the system linker/cc to create the resulting file. This -// links to all upstream files as well. +fn escape_stdout_stderr_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); + x + }) +} + +const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp"; + +/// Invoke `llvm-dwp` (shipped alongside rustc) to link `dwo` files from Split DWARF into a `dwp` +/// file. +fn link_dwarf_object<'a>(sess: &'a Session, executable_out_filename: &Path) { + info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap()); + + let dwp_out_filename = executable_out_filename.with_extension("dwp"); + let mut cmd = Command::new(LLVM_DWP_EXECUTABLE); + cmd.arg("-e"); + cmd.arg(executable_out_filename); + cmd.arg("-o"); + cmd.arg(&dwp_out_filename); + + let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + if let Some(path) = env::var_os("PATH") { + new_path.extend(env::split_paths(&path)); + } + let new_path = env::join_paths(new_path).unwrap(); + cmd.env("PATH", new_path); + + info!("{:?}", &cmd); + match sess.time("run_dwp", || cmd.output()) { + Ok(prog) if !prog.status.success() => { + sess.struct_err(&format!( + "linking dwarf objects with `{}` failed: {}", + LLVM_DWP_EXECUTABLE, prog.status + )) + .note(&format!("{:?}", &cmd)) + .note(&escape_stdout_stderr_string(&prog.stdout)) + .note(&escape_stdout_stderr_string(&prog.stderr)) + .emit(); + info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); + } + Ok(_) => {} + Err(e) => { + let dwp_not_found = e.kind() == io::ErrorKind::NotFound; + let mut err = if dwp_not_found { + sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE)) + } else { + sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE)) + }; + + err.note(&e.to_string()); + + if !dwp_not_found { + err.note(&format!("{:?}", &cmd)); + } + + err.emit(); + } + } +} + +/// Create a dynamic library or executable. +/// +/// This will invoke the system linker/cc to create the resulting file. This links to all upstream +/// files as well. fn link_natively<'a, B: ArchiveBuilder<'a>>( sess: &'a Session, crate_type: CrateType, @@ -643,15 +719,16 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( } } + fn escape_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); + x + }) + } + match prog { Ok(prog) => { - fn escape_string(s: &[u8]) -> String { - str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { - let mut x = "Non-UTF-8 output: ".to_string(); - x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); - x - }) - } if !prog.status.success() { let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); @@ -661,7 +738,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( prog.status )) .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output)) + .note(&escape_stdout_stderr_string(&output)) .emit(); // If MSVC's `link.exe` was expected but the return code @@ -714,8 +791,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( sess.abort_if_errors(); } - info!("linker stderr:\n{}", escape_string(&prog.stderr)); - info!("linker stdout:\n{}", escape_string(&prog.stdout)); + info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); } Err(e) => { let linker_not_found = e.kind() == io::ErrorKind::NotFound; @@ -760,8 +837,21 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( && sess.opts.debuginfo != DebugInfo::None && !preserve_objects_for_their_debuginfo(sess) { - if let Err(e) = Command::new("dsymutil").arg(out_filename).output() { - sess.fatal(&format!("failed to run dsymutil: {}", e)) + let prog = Command::new("dsymutil").arg(out_filename).output(); + match prog { + Ok(prog) => { + if !prog.status.success() { + let mut output = prog.stderr.clone(); + output.extend_from_slice(&prog.stdout); + sess.struct_warn(&format!( + "processing debug info with `dsymutil` failed: {}", + prog.status + )) + .note(&escape_string(&output)) + .emit(); + } + } + Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)), } } } @@ -948,6 +1038,13 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { return false; } + // Single mode keeps debuginfo in the same object file, but in such a way that it it skipped + // by the linker - so it's expected that when codegen units are linked together that this + // debuginfo would be lost without keeping around the temps. + if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Single { + return true; + } + // If we're on OSX then the equivalent of split dwarf is turned on by // default. The final executable won't actually have any debug information // except it'll have pointers to elsewhere. Historically we've always run @@ -1663,17 +1760,15 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.take_cmd() } -// # Native library linking -// -// User-supplied library search paths (-L on the command line). These are -// the same paths used to find Rust crates, so some of them may have been -// added already by the previous crate linking code. This only allows them -// to be found at compile time so it is still entirely up to outside -// forces to make sure that library can be found at runtime. -// -// Also note that the native libraries linked here are only the ones located -// in the current crate. Upstream crates with native library dependencies -// may have their native library pulled in above. +/// # Native library linking +/// +/// User-supplied library search paths (-L on the command line). These are the same paths used to +/// find Rust crates, so some of them may have been added already by the previous crate linking +/// code. This only allows them to be found at compile time so it is still entirely up to outside +/// forces to make sure that library can be found at runtime. +/// +/// Also note that the native libraries linked here are only the ones located in the current crate. +/// Upstream crates with native library dependencies may have their native library pulled in above. fn add_local_native_libraries( cmd: &mut dyn Linker, sess: &Session, @@ -1713,11 +1808,10 @@ fn add_local_native_libraries( } } -// # Rust Crate linking -// -// Rust crates are not considered at all when creating an rlib output. All -// dependencies will be linked when producing the final output (instead of -// the intermediate rlib version) +/// # Rust Crate linking +/// +/// Rust crates are not considered at all when creating an rlib output. All dependencies will be +/// linked when producing the final output (instead of the intermediate rlib version). fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( cmd: &mut dyn Linker, sess: &'a Session, @@ -1982,24 +2076,21 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } } -// Link in all of our upstream crates' native dependencies. Remember that -// all of these upstream native dependencies are all non-static -// dependencies. We've got two cases then: -// -// 1. The upstream crate is an rlib. In this case we *must* link in the -// native dependency because the rlib is just an archive. -// -// 2. The upstream crate is a dylib. In order to use the dylib, we have to -// have the dependency present on the system somewhere. Thus, we don't -// gain a whole lot from not linking in the dynamic dependency to this -// crate as well. -// -// The use case for this is a little subtle. In theory the native -// dependencies of a crate are purely an implementation detail of the crate -// itself, but the problem arises with generic and inlined functions. If a -// generic function calls a native function, then the generic function must -// be instantiated in the target crate, meaning that the native symbol must -// also be resolved in the target crate. +/// Link in all of our upstream crates' native dependencies. Remember that all of these upstream +/// native dependencies are all non-static dependencies. We've got two cases then: +/// +/// 1. The upstream crate is an rlib. In this case we *must* link in the native dependency because +/// the rlib is just an archive. +/// +/// 2. The upstream crate is a dylib. In order to use the dylib, we have to have the dependency +/// present on the system somewhere. Thus, we don't gain a whole lot from not linking in the +/// dynamic dependency to this crate as well. +/// +/// The use case for this is a little subtle. In theory the native dependencies of a crate are +/// purely an implementation detail of the crate itself, but the problem arises with generic and +/// inlined functions. If a generic function calls a native function, then the generic function +/// must be instantiated in the target crate, meaning that the native symbol must also be resolved +/// in the target crate. fn add_upstream_native_libraries( cmd: &mut dyn Linker, sess: &Session, @@ -2090,9 +2181,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { ("aarch64", "tvos") => "appletvos", ("x86_64", "tvos") => "appletvsimulator", ("arm", "ios") => "iphoneos", + ("aarch64", "ios") if llvm_target.contains("macabi") => "macosx", ("aarch64", "ios") => "iphoneos", ("x86", "ios") => "iphonesimulator", - ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx10.15", + ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx", ("x86_64", "ios") => "iphonesimulator", _ => { sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os)); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index b34bee3358..c84b87964b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -274,17 +274,20 @@ impl ModuleConfig { } } -// HACK(eddyb) work around `#[derive]` producing wrong bounds for `Clone`. -pub struct TargetMachineFactory( - pub Arc Result + Send + Sync>, -); - -impl Clone for TargetMachineFactory { - fn clone(&self) -> Self { - TargetMachineFactory(self.0.clone()) - } +/// Configuration passed to the function returned by the `target_machine_factory`. +pub struct TargetMachineFactoryConfig { + /// Split DWARF is enabled in LLVM by checking that `TM.MCOptions.SplitDwarfFile` isn't empty, + /// so the path to the dwarf object has to be provided when we create the target machine. + /// This can be ignored by backends which do not need it for their Split DWARF support. + pub split_dwarf_file: Option, } +pub type TargetMachineFactoryFn = Arc< + dyn Fn(TargetMachineFactoryConfig) -> Result<::TargetMachine, String> + + Send + + Sync, +>; + pub type ExportedSymbols = FxHashMap>>; /// Additional resources used by optimize_and_codegen (not module specific) @@ -305,11 +308,13 @@ pub struct CodegenContext { pub regular_module_config: Arc, pub metadata_module_config: Arc, pub allocator_module_config: Arc, - pub tm_factory: TargetMachineFactory, + pub tm_factory: TargetMachineFactoryFn, pub msvc_imps_needed: bool, + pub is_pe_coff: bool, pub target_pointer_width: u32, pub target_arch: String, pub debuginfo: config::DebugInfo, + pub split_dwarf_kind: config::SplitDwarfKind, // Number of cgus excluding the allocator/metadata modules pub total_cgus: usize, @@ -626,6 +631,12 @@ fn produce_final_output_artifacts( } } + if let Some(ref path) = module.dwarf_object { + if !keep_numbered_objects { + remove(sess, path); + } + } + if let Some(ref path) = module.bytecode { if !keep_numbered_bitcode { remove(sess, path); @@ -848,6 +859,7 @@ fn execute_copy_from_cache_work_item( name: module.name, kind: ModuleKind::Regular, object, + dwarf_object: None, bytecode: None, })) } @@ -1019,12 +1031,14 @@ fn start_executing_work( regular_module_config: regular_config, metadata_module_config: metadata_config, allocator_module_config: allocator_config, - tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)), + tm_factory: backend.target_machine_factory(tcx.sess, ol), total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), + is_pe_coff: tcx.sess.target.is_like_windows, target_pointer_width: tcx.sess.target.pointer_width, target_arch: tcx.sess.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, + split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf, }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 5fe26dbf91..18132a2c7a 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -399,7 +399,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = cx.tcx().erase_regions(main_ret_ty.no_bound_vars().unwrap()); let llfn = match cx.declare_c_main(llfty) { Some(llfn) => llfn, @@ -766,7 +766,7 @@ impl CrateInfo { profiler_runtime: None, is_no_builtins: Default::default(), native_libraries: Default::default(), - used_libraries: tcx.native_libraries(LOCAL_CRATE), + used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), link_args: tcx.link_args(LOCAL_CRATE), crate_name: Default::default(), used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), @@ -787,7 +787,8 @@ impl CrateInfo { info.missing_lang_items.reserve(n_crates); for &cnum in crates.iter() { - info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); + info.native_libraries + .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect()); info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); if tcx.is_panic_runtime(cnum) { diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs index bcac2c90fd..af6c476292 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex}; -/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L91) +/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum CounterKind { @@ -17,7 +17,7 @@ pub enum CounterKind { /// `instrprof.increment()`) /// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of /// counter expressions. -/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L98-L99) +/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L99-L100) /// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart. #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -41,7 +41,7 @@ impl Counter { } } -/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146) +/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147) #[derive(Copy, Clone, Debug)] #[repr(C)] pub enum ExprKind { @@ -49,7 +49,7 @@ pub enum ExprKind { Add = 1, } -/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-05-05/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147-L148) +/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L148-L149) /// Important: The Rust struct layout (order and types of fields) must match its C++ /// counterpart. #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 0b49a37907..d1bbf74307 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -94,7 +94,14 @@ pub fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, true, output, visited); if cpp_like_names { - output.push('*'); + // Slices and `&str` are treated like C++ pointers when computing debug + // info for MSVC debugger. However, adding '*' at the end of these types' names + // causes the .natvis engine for WinDbg to fail to display their data, so we opt these + // types out to aid debugging in MSVC. + match *inner_type.kind() { + ty::Slice(_) | ty::Str => {} + _ => output.push('*'), + } } } ty::Array(inner_type, len) => { @@ -120,8 +127,8 @@ pub fn push_debuginfo_type_name<'tcx>( } ty::Dynamic(ref trait_data, ..) => { if let Some(principal) = trait_data.principal() { - let principal = tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &principal); + let principal = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); push_item_name(tcx, principal.def_id, false, output); push_type_params(tcx, principal.substs, output, visited); } else { @@ -159,7 +166,7 @@ pub fn push_debuginfo_type_name<'tcx>( output.push_str("fn("); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { push_debuginfo_type_name(tcx, parameter_type, true, output, visited); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 70b92b234e..bc93bd8b7b 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,6 +2,7 @@ #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] +#![feature(drain_filter)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] #![feature(nll)] @@ -20,15 +21,17 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib}; +use rustc_middle::middle::cstore::{self, CrateSource, LibSource}; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::ty::query::Providers; use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT}; +use rustc_session::utils::NativeLibKind; use rustc_span::symbol::Symbol; use std::path::{Path, PathBuf}; @@ -63,13 +66,15 @@ impl ModuleCodegen { pub fn into_compiled_module( self, emit_obj: bool, + emit_dwarf_obj: bool, emit_bc: bool, outputs: &OutputFilenames, ) -> CompiledModule { let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); + let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name))); let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); - CompiledModule { name: self.name.clone(), kind: self.kind, object, bytecode } + CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode } } } @@ -78,6 +83,7 @@ pub struct CompiledModule { pub name: String, pub kind: ModuleKind, pub object: Option, + pub dwarf_object: Option, pub bytecode: Option, } @@ -101,6 +107,19 @@ bitflags::bitflags! { } } +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +pub struct NativeLib { + pub kind: NativeLibKind, + pub name: Option, + pub cfg: Option, +} + +impl From<&cstore::NativeLib> for NativeLib { + fn from(lib: &cstore::NativeLib) -> Self { + NativeLib { kind: lib.kind.clone(), name: lib.name.clone(), cfg: lib.cfg.clone() } + } +} + /// Misc info we load from metadata to persist beyond the tcx. /// /// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` @@ -115,9 +134,9 @@ pub struct CrateInfo { pub compiler_builtins: Option, pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, - pub native_libraries: FxHashMap>>, + pub native_libraries: FxHashMap>, pub crate_name: FxHashMap, - pub used_libraries: Lrc>, + pub used_libraries: Vec, pub link_args: Lrc>, pub used_crate_source: FxHashMap>, pub used_crates_static: Vec<(CrateNum, LibSource)>, diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index bdde07d3fa..44bb0deeae 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -24,7 +24,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( analyzer.visit_body(&mir); for (local, decl) in mir.local_decls.iter_enumerated() { - let ty = fx.monomorphize(&decl.ty); + let ty = fx.monomorphize(decl.ty); debug!("local {:?} has type `{}`", local, ty); let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); if fx.cx.is_backend_immediate(layout) { @@ -121,10 +121,10 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { if is_consume { let base_ty = mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx()); - let base_ty = self.fx.monomorphize(&base_ty); + let base_ty = self.fx.monomorphize(base_ty); // ZSTs don't require any actual memory access. - let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(&elem)).ty; + let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty; let span = self.fx.mir.local_decls[place_ref.local].source_info.span; if cx.spanned_layout_of(elem_ty, span).is_zst() { return; @@ -313,7 +313,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> PlaceContext::MutatingUse(MutatingUseContext::Drop) => { let ty = self.fx.mir.local_decls[local].ty; - let ty = self.fx.monomorphize(&ty); + let ty = self.fx.monomorphize(ty); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index da4637b1af..ce56f16354 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -37,12 +37,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { /// `funclet_bb` member if it is not `None`. fn funclet<'b, Bx: BuilderMethods<'a, 'tcx>>( &self, - fx: &'b mut FunctionCx<'a, 'tcx, Bx>, + fx: &'b FunctionCx<'a, 'tcx, Bx>, ) -> Option<&'b Bx::Funclet> { - match self.funclet_bb { - Some(funcl) => fx.funclets[funcl].as_ref(), - None => None, - } + self.funclet_bb.and_then(|funcl| fx.funclets[funcl].as_ref()) } fn lltarget>( @@ -255,7 +252,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } let llval = match self.fn_abi.ret.mode { - PassMode::Ignore | PassMode::Indirect(..) => { + PassMode::Ignore | PassMode::Indirect { .. } => { bx.ret_void(); return; } @@ -306,7 +303,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind: Option, ) { let ty = location.ty(self.mir, bx.tcx()).ty; - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { @@ -454,7 +451,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Inhabited, ZeroValid, UninitValid, - }; + } let panic_intrinsic = intrinsic.and_then(|i| match i { sym::assert_inhabited => Some(AssertIntrinsic::Inhabited), sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid), @@ -576,7 +573,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .iter() .map(|op_arg| { let op_ty = op_arg.ty(self.mir, bx.tcx()); - self.monomorphize(&op_ty) + self.monomorphize(op_ty) }) .collect::>(); @@ -900,7 +897,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::InlineAsmOperand::SymFn { ref value } => { - let literal = self.monomorphize(&value.literal); + let literal = self.monomorphize(value.literal); if let ty::FnDef(def_id, substs) = *literal.ty.kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), @@ -1101,7 +1098,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Force by-ref if we have to load through a cast pointer. let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => match arg.mode { - PassMode::Indirect(..) | PassMode::Cast(_) => { + PassMode::Indirect { .. } | PassMode::Cast(_) => { let scratch = PlaceRef::alloca(bx, arg.layout); op.val.store(bx, scratch); (scratch.llval, scratch.align, true) @@ -1398,6 +1395,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dst: PlaceRef<'tcx, Bx::Value>, ) { let src = self.codegen_operand(bx, src); + + // Special-case transmutes between scalars as simple bitcasts. + match (&src.layout.abi, &dst.layout.abi) { + (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { + // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. + if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) { + assert_eq!(src.layout.size, dst.layout.size); + + // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar` + // conversions allow handling `bool`s the same as `u8`s. + let src = bx.from_immediate(src.immediate()); + let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout)); + Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst); + return; + } + } + _ => {} + } + let llty = bx.backend_type(src.layout); let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); let align = src.layout.align.abi.min(dst.align); diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 4943e279c7..3a85c268e0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -11,20 +11,20 @@ use super::FunctionCx; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant_to_operand( - &mut self, + &self, bx: &mut Bx, constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { let val = self.eval_mir_constant(constant)?; - let ty = self.monomorphize(&constant.literal.ty); + let ty = self.monomorphize(constant.literal.ty); Ok(OperandRef::from_const(bx, val, ty)) } pub fn eval_mir_constant( - &mut self, + &self, constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { - match self.monomorphize(&constant.literal).val { + match self.monomorphize(constant.literal).val { ty::ConstKind::Unevaluated(def, substs, promoted) => self .cx .tcx() @@ -83,7 +83,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .unwrap_or_else(|_| { bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time"); // We've errored, so we don't have to produce working code. - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); let llty = bx.backend_type(bx.layout_of(ty)); (bx.const_undef(llty), ty) }) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 4e0396a15a..d5b2cbaa55 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; use rustc_target::abi::{LayoutOf, Size}; -use super::operand::OperandValue; +use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; use super::{FunctionCx, LocalRef}; @@ -116,6 +116,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { span } + fn spill_operand_to_stack( + operand: &OperandRef<'tcx, Bx::Value>, + name: Option, + bx: &mut Bx, + ) -> PlaceRef<'tcx, Bx::Value> { + // "Spill" the value onto the stack, for debuginfo, + // without forcing non-debuginfo uses of the local + // to also load from the stack every single time. + // FIXME(#68817) use `llvm.dbg.value` instead, + // at least for the cases which LLVM handles correctly. + let spill_slot = PlaceRef::alloca(bx, operand.layout); + if let Some(name) = name { + bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); + } + operand.val.store(bx, spill_slot); + spill_slot + } + /// Apply debuginfo and/or name, after creating the `alloca` for a local, /// or initializing the local with an operand (whichever applies). pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { @@ -160,7 +178,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(eddyb) is this `+ 1` needed at all? let kind = VariableKind::ArgumentVariable(arg_index + 1); - let arg_ty = self.monomorphize(&decl.ty); + let arg_ty = self.monomorphize(decl.ty); self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span) }, @@ -226,17 +244,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // "Spill" the value onto the stack, for debuginfo, - // without forcing non-debuginfo uses of the local - // to also load from the stack every single time. - // FIXME(#68817) use `llvm.dbg.value` instead, - // at least for the cases which LLVM handles correctly. - let spill_slot = PlaceRef::alloca(bx, operand.layout); - if let Some(name) = name { - bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); - } - operand.val.store(bx, spill_slot); - spill_slot + Self::spill_operand_to_stack(operand, name, bx) } LocalRef::Place(place) => *place, @@ -308,6 +316,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`. pub fn compute_per_local_var_debug_info( &self, + bx: &mut Bx, ) -> Option>>> { let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; @@ -322,31 +331,63 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { None }; + let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let place = var.place; - let var_ty = self.monomorphized_place_ty(place.as_ref()); - let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg - && place.projection.is_empty() - && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE - { - let arg_index = place.local.index() - 1; - - // FIXME(eddyb) shouldn't `ArgumentVariable` indices be - // offset in closures to account for the hidden environment? - // Also, is this `+ 1` needed at all? - VariableKind::ArgumentVariable(arg_index + 1) - } else { - VariableKind::LocalVariable + let (var_ty, var_kind) = match var.value { + mir::VarDebugInfoContents::Place(place) => { + let var_ty = self.monomorphized_place_ty(place.as_ref()); + let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg + && place.projection.is_empty() + && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE + { + let arg_index = place.local.index() - 1; + + // FIXME(eddyb) shouldn't `ArgumentVariable` indices be + // offset in closures to account for the hidden environment? + // Also, is this `+ 1` needed at all? + VariableKind::ArgumentVariable(arg_index + 1) + } else { + VariableKind::LocalVariable + }; + (var_ty, var_kind) + } + mir::VarDebugInfoContents::Const(c) => { + let ty = self.monomorphize(c.literal.ty); + (ty, VariableKind::LocalVariable) + } }; + self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); - per_local[var.place.local].push(PerLocalVarDebugInfo { - name: var.name, - source_info: var.source_info, - dbg_var, - projection: var.place.projection, - }); + match var.value { + mir::VarDebugInfoContents::Place(place) => { + per_local[place.local].push(PerLocalVarDebugInfo { + name: var.name, + source_info: var.source_info, + dbg_var, + projection: place.projection, + }); + } + mir::VarDebugInfoContents::Const(c) => { + if let Some(dbg_var) = dbg_var { + let dbg_loc = match self.dbg_loc(var.source_info) { + Some(dbg_loc) => dbg_loc, + None => continue, + }; + + if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) { + let base = Self::spill_operand_to_stack( + &operand, + Some(var.name.to_string()), + bx, + ); + + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]); + } + } + } + } } Some(per_local) } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 2bf1ee43c7..80e3ed75b8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -64,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let sig = callee_ty.fn_sig(bx.tcx()); - let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = bx.tcx().item_name(def_id); @@ -83,9 +83,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - sym::unreachable => { - return; - } sym::va_start => bx.va_start(args[0].immediate()), sym::va_end => bx.va_end(args[0].immediate()), sym::size_of_val => { @@ -106,8 +103,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) } } - sym::size_of - | sym::pref_align_of + sym::pref_align_of | sym::min_align_of | sym::needs_drop | sym::type_id @@ -119,10 +115,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .unwrap(); OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) } - // Effectively no-op - sym::forget => { - return; - } sym::offset => { let ptr = args[0].immediate(); let offset = args[1].immediate(); @@ -218,9 +210,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul | sym::unchecked_div | sym::unchecked_rem | sym::unchecked_shl @@ -254,9 +243,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()), - sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()), - sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()), sym::exact_div => { if signed { bx.exactsdiv(args[0].immediate(), args[1].immediate()) @@ -437,16 +423,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match split[1] { "cxchg" | "cxchgweak" => { let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let weak = split[1] == "cxchgweak"; - let pair = bx.atomic_cmpxchg( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - order, - failorder, - weak, - ); + let mut dst = args[0].immediate(); + let mut cmp = args[1].immediate(); + let mut src = args[2].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first. + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + dst = bx.pointercast(dst, ptr_llty); + cmp = bx.ptrtoint(cmp, bx.type_isize()); + src = bx.ptrtoint(src, bx.type_isize()); + } + let pair = bx.atomic_cmpxchg(dst, cmp, src, order, failorder, weak); let val = bx.extract_value(pair, 0); let success = bx.extract_value(pair, 1); let val = bx.from_immediate(val); @@ -464,9 +454,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "load" => { let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { - let size = bx.layout_of(ty).size; - bx.atomic_load(args[0].immediate(), order, size) + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { + let layout = bx.layout_of(ty); + let size = layout.size; + let mut source = args[0].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first... + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + source = bx.pointercast(source, ptr_llty); + } + let result = bx.atomic_load(source, order, size); + if ty.is_unsafe_ptr() { + // ... and then cast the result back to a pointer + bx.inttoptr(result, bx.backend_type(layout)) + } else { + result + } } else { return invalid_monomorphization(ty); } @@ -474,9 +478,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "store" => { let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let size = bx.layout_of(ty).size; - bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size); + let mut val = args[1].immediate(); + let mut ptr = args[0].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first. + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + ptr = bx.pointercast(ptr, ptr_llty); + val = bx.ptrtoint(val, bx.type_isize()); + } + bx.atomic_store(val, ptr, order, size); return; } else { return invalid_monomorphization(ty); @@ -511,8 +524,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { - bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) + if int_type_width_signed(ty, bx.tcx()).is_some() + || (ty.is_unsafe_ptr() && op == "xchg") + { + let mut ptr = args[0].immediate(); + let mut val = args[1].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first. + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + ptr = bx.pointercast(ptr, ptr_llty); + val = bx.ptrtoint(val, bx.type_isize()); + } + bx.atomic_rmw(atom_op, ptr, val, order) } else { return invalid_monomorphization(ty); } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 01fd168159..285140060b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -87,7 +87,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn monomorphize(&self, value: &T) -> T + pub fn monomorphize(&self, value: T) -> T where T: Copy + TypeFoldable<'tcx>, { @@ -186,7 +186,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( caller_location: None, }; - fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(); + fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx); for const_ in &mir.required_consts { if let Err(err) = fx.eval_mir_constant(const_) { @@ -208,7 +208,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut allocate_local = |local| { let decl = &mir.local_decls[local]; - let layout = bx.layout_of(fx.monomorphize(&decl.ty)); + let layout = bx.layout_of(fx.monomorphize(decl.ty)); assert!(!layout.ty.has_erasable_regions()); if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { @@ -364,7 +364,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // to reconstruct it into a tuple local variable, from multiple // individual LLVM function arguments. - let arg_ty = fx.monomorphize(&arg_decl.ty); + let arg_ty = fx.monomorphize(arg_decl.ty); let tupled_arg_tys = match arg_ty.kind() { ty::Tuple(tys) => tys, _ => bug!("spread argument isn't a tuple?!"), @@ -385,7 +385,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() { - let arg_ty = fx.monomorphize(&arg_decl.ty); + let arg_ty = fx.monomorphize(arg_decl.ty); let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); bx.va_start(va_list.llval); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index bbd004be87..08a4ae3962 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -452,7 +452,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.abort(); // We still have to return an operand but it doesn't matter, // this code is unreachable. - let ty = self.monomorphize(&constant.literal.ty); + let ty = self.monomorphize(constant.literal.ty); let layout = bx.cx().layout_of(ty); bx.load_operand(PlaceRef::new_sized( bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index e1cc026872..e4f4c88447 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cg_base.project_index(bx, bx.cx().const_usize(from as u64)); let projected_ty = PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty; - subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); + subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty)); if subslice.layout.is_unsized() { assert!(from_end, "slice subslices should be `from_end`"); @@ -515,6 +515,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, self.mir, tcx); - self.monomorphize(&place_ty.ty) + self.monomorphize(place_ty.ty) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 40ae0a13c7..e3a6cabd60 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let count = - self.monomorphize(&count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); + self.monomorphize(count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); bx.write_operand_repeatedly(cg_elem, count, dest) } @@ -181,7 +181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { let operand = self.codegen_operand(&mut bx, source); debug!("cast operand is {:?}", operand); - let cast = bx.cx().layout_of(self.monomorphize(&mir_cast_ty)); + let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty)); let val = match *kind { mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { @@ -489,6 +489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Discriminant(ref place) => { let discr_ty = rvalue.ty(self.mir, bx.tcx()); + let discr_ty = self.monomorphize(discr_ty); let discr = self .codegen_place(&mut bx, place.as_ref()) .codegen_get_discr(&mut bx, discr_ty); @@ -502,7 +503,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); assert!(bx.cx().type_is_sized(ty)); let val = bx.cx().const_usize(bx.cx().layout_of(ty).size.bytes()); let tcx = self.cx.tcx(); @@ -516,7 +517,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { - let content_ty = self.monomorphize(&content_ty); + let content_ty = self.monomorphize(content_ty); let content_layout = bx.cx().layout_of(content_ty); let llsize = bx.cx().const_usize(content_layout.size.bytes()); let llalign = bx.cx().const_usize(content_layout.align.abi.bytes()); @@ -554,7 +555,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // aggregate rvalues are allowed to be operands. let ty = rvalue.ty(self.mir, self.cx.tcx()); let operand = - OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(&ty))); + OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty))); (bx, operand) } } @@ -774,7 +775,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { let ty = rvalue.ty(self.mir, self.cx.tcx()); - let ty = self.monomorphize(&ty); + let ty = self.monomorphize(ty); self.cx.spanned_layout_of(ty, span).is_zst() } } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 000ddf4260..fd18f42f2d 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -4,6 +4,11 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::symbol::Symbol; +// When adding features to the below lists +// check whether they're named already elsewhere in rust +// e.g. in stdarch and whether the given name matches LLVM's +// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted + const ARM_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("aclass", Some(sym::arm_target_feature)), ("mclass", Some(sym::arm_target_feature)), @@ -50,15 +55,23 @@ const X86_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("aes", None), ("avx", None), ("avx2", None), + ("avx512bf16", Some(sym::avx512_target_feature)), + ("avx512bitalg", Some(sym::avx512_target_feature)), ("avx512bw", Some(sym::avx512_target_feature)), ("avx512cd", Some(sym::avx512_target_feature)), ("avx512dq", Some(sym::avx512_target_feature)), ("avx512er", Some(sym::avx512_target_feature)), ("avx512f", Some(sym::avx512_target_feature)), + ("avx512gfni", Some(sym::avx512_target_feature)), ("avx512ifma", Some(sym::avx512_target_feature)), ("avx512pf", Some(sym::avx512_target_feature)), + ("avx512vaes", Some(sym::avx512_target_feature)), ("avx512vbmi", Some(sym::avx512_target_feature)), + ("avx512vbmi2", Some(sym::avx512_target_feature)), ("avx512vl", Some(sym::avx512_target_feature)), + ("avx512vnni", Some(sym::avx512_target_feature)), + ("avx512vp2intersect", Some(sym::avx512_target_feature)), + ("avx512vpclmulqdq", Some(sym::avx512_target_feature)), ("avx512vpopcntdq", Some(sym::avx512_target_feature)), ("bmi1", None), ("bmi2", None), diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index b9c555c2eb..f28db2fe84 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,5 +1,6 @@ use super::write::WriteBackendMethods; use super::CodegenObject; +use crate::back::write::TargetMachineFactoryFn; use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; @@ -21,7 +22,6 @@ use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; use std::any::Any; -use std::sync::Arc; pub trait BackendTypes { type Value: CodegenObject; @@ -123,7 +123,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se &self, sess: &Session, opt_level: config::OptLevel, - ) -> Arc Result + Send + Sync>; + ) -> TargetMachineFactoryFn; fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str; fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>; } diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index ec2f9597b1..01efcaf6f4 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -151,8 +151,67 @@ impl FingerprintDecoder for D { panic!("Cannot decode `Fingerprint` with `{}`", std::any::type_name::()); } } + impl FingerprintDecoder for opaque::Decoder<'_> { fn decode_fingerprint(&mut self) -> Result { Fingerprint::decode_opaque(self) } } + +// `PackedFingerprint` wraps a `Fingerprint`. Its purpose is to, on certain +// architectures, behave like a `Fingerprint` without alignment requirements. +// This behavior is only enabled on x86 and x86_64, where the impact of +// unaligned accesses is tolerable in small doses. +// +// This may be preferable to use in large collections of structs containing +// fingerprints, as it can reduce memory consumption by preventing the padding +// that the more strictly-aligned `Fingerprint` can introduce. An application of +// this is in the query dependency graph, which contains a large collection of +// `DepNode`s. As of this writing, the size of a `DepNode` decreases by ~30% +// (from 24 bytes to 17) by using the packed representation here, which +// noticeably decreases total memory usage when compiling large crates. +// +// The wrapped `Fingerprint` is private to reduce the chance of a client +// invoking undefined behavior by taking a reference to the packed field. +#[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed))] +#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)] +pub struct PackedFingerprint(Fingerprint); + +impl std::fmt::Display for PackedFingerprint { + #[inline] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Copy to avoid taking reference to packed field. + let copy = self.0; + copy.fmt(formatter) + } +} + +impl Encodable for PackedFingerprint { + #[inline] + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + // Copy to avoid taking reference to packed field. + let copy = self.0; + copy.encode(s) + } +} + +impl Decodable for PackedFingerprint { + #[inline] + fn decode(d: &mut D) -> Result { + Fingerprint::decode(d).map(|f| PackedFingerprint(f)) + } +} + +impl From for PackedFingerprint { + #[inline] + fn from(f: Fingerprint) -> PackedFingerprint { + PackedFingerprint(f) + } +} + +impl From for Fingerprint { + #[inline] + fn from(f: PackedFingerprint) -> Fingerprint { + f.0 + } +} diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs new file mode 100644 index 0000000000..fe7a256d21 --- /dev/null +++ b/compiler/rustc_data_structures/src/functor.rs @@ -0,0 +1,82 @@ +use rustc_index::vec::{Idx, IndexVec}; +use std::mem; +use std::ptr; + +pub trait IdFunctor { + type Inner; + + fn map_id(self, f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner; +} + +impl IdFunctor for Box { + type Inner = T; + + #[inline] + fn map_id(self, mut f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + let raw = Box::into_raw(self); + unsafe { + // SAFETY: The raw pointer points to a valid value of type `T`. + let value = ptr::read(raw); + // SAFETY: Converts `Box` to `Box>` which is the + // inverse of `Box::assume_init()` and should be safe. + let mut raw: Box> = Box::from_raw(raw.cast()); + // SAFETY: Write the mapped value back into the `Box`. + ptr::write(raw.as_mut_ptr(), f(value)); + // SAFETY: We just initialized `raw`. + raw.assume_init() + } + } +} + +impl IdFunctor for Vec { + type Inner = T; + + #[inline] + fn map_id(mut self, mut f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + // FIXME: We don't really care about panics here and leak + // far more than we should, but that should be fine for now. + let len = self.len(); + unsafe { + self.set_len(0); + let start = self.as_mut_ptr(); + for i in 0..len { + let p = start.add(i); + ptr::write(p, f(ptr::read(p))); + } + self.set_len(len); + } + self + } +} + +impl IdFunctor for Box<[T]> { + type Inner = T; + + #[inline] + fn map_id(self, f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + Vec::from(self).map_id(f).into() + } +} + +impl IdFunctor for IndexVec { + type Inner = T; + + #[inline] + fn map_id(self, f: F) -> Self + where + F: FnMut(Self::Inner) -> Self::Inner, + { + IndexVec::from_raw(self.raw.map_id(f)) + } +} diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 1634c58631..09b91083a6 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -149,8 +149,6 @@ struct Event { /// those successors), we will pop off that node's `Settled` event. /// /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms -/// [`NodeStatus`]: ./enum.NodeStatus.html -/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined pub struct TriColorDepthFirstSearch<'graph, G> where G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 486a9ba77b..5b3d8233f3 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -231,20 +231,30 @@ where let scc_indices = (0..num_nodes) .map(G::Node::new) - .map(|node| match this.walk_node(0, node) { + .map(|node| match this.start_walk_from(node) { WalkReturn::Complete { scc_index } => scc_index, - WalkReturn::Cycle { min_depth } => { - panic!("`walk_node(0, {:?})` returned cycle with depth {:?}", node, min_depth) - } + WalkReturn::Cycle { min_depth } => panic!( + "`start_walk_node({:?})` returned cycle with depth {:?}", + node, min_depth + ), }) .collect(); Sccs { scc_indices, scc_data: this.scc_data } } - /// Visits a node during the DFS. We first examine its current - /// state -- if it is not yet visited (`NotVisited`), we can push - /// it onto the stack and start walking its successors. + fn start_walk_from(&mut self, node: G::Node) -> WalkReturn { + if let Some(result) = self.inspect_node(node) { + result + } else { + self.walk_unvisited_node(node) + } + } + + /// Inspect a node during the DFS. We first examine its current + /// state -- if it is not yet visited (`NotVisited`), return `None` so + /// that the caller might push it onto the stack and start walking its + /// successors. /// /// If it is already on the DFS stack it will be in the state /// `BeingVisited`. In that case, we have found a cycle and we @@ -253,20 +263,19 @@ where /// Otherwise, we are looking at a node that has already been /// completely visited. We therefore return `WalkReturn::Complete` /// with its associated SCC index. - fn walk_node(&mut self, depth: usize, node: G::Node) -> WalkReturn { - debug!("walk_node(depth = {:?}, node = {:?})", depth, node); - match self.find_state(node) { + fn inspect_node(&mut self, node: G::Node) -> Option> { + Some(match self.find_state(node) { NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index }, NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth }, - NodeState::NotVisited => self.walk_unvisited_node(depth, node), + NodeState::NotVisited => return None, NodeState::InCycleWith { parent } => panic!( "`find_state` returned `InCycleWith({:?})`, which ought to be impossible", parent ), - } + }) } /// Fetches the state of the node `r`. If `r` is recorded as being @@ -274,104 +283,292 @@ where /// of `r2` (and updates `r` to reflect current result). This is /// basically the "find" part of a standard union-find algorithm /// (with path compression). - fn find_state(&mut self, r: G::Node) -> NodeState { - debug!("find_state(r = {:?} in state {:?})", r, self.node_states[r]); - match self.node_states[r] { - NodeState::InCycle { scc_index } => NodeState::InCycle { scc_index }, - NodeState::BeingVisited { depth } => NodeState::BeingVisited { depth }, - NodeState::NotVisited => NodeState::NotVisited, - NodeState::InCycleWith { parent } => { - let parent_state = self.find_state(parent); - debug!("find_state: parent_state = {:?}", parent_state); - match parent_state { - NodeState::InCycle { .. } => { - self.node_states[r] = parent_state; - parent_state - } + fn find_state(&mut self, mut node: G::Node) -> NodeState { + // To avoid recursion we temporarily reuse the `parent` of each + // InCycleWith link to encode a downwards link while compressing + // the path. After we have found the root or deepest node being + // visited, we traverse the reverse links and correct the node + // states on the way. + // + // **Note**: This mutation requires that this is a leaf function + // or at least that none of the called functions inspects the + // current node states. Luckily, we are a leaf. + + // Remember one previous link. The termination condition when + // following links downwards is then simply as soon as we have + // found the initial self-loop. + let mut previous_node = node; + + // Ultimately assigned by the parent when following + // `InCycleWith` upwards. + let node_state = loop { + debug!("find_state(r = {:?} in state {:?})", node, self.node_states[node]); + match self.node_states[node] { + NodeState::InCycle { scc_index } => break NodeState::InCycle { scc_index }, + NodeState::BeingVisited { depth } => break NodeState::BeingVisited { depth }, + NodeState::NotVisited => break NodeState::NotVisited, + NodeState::InCycleWith { parent } => { + // We test this, to be extremely sure that we never + // ever break our termination condition for the + // reverse iteration loop. + assert!(node != parent, "Node can not be in cycle with itself"); + // Store the previous node as an inverted list link + self.node_states[node] = NodeState::InCycleWith { parent: previous_node }; + // Update to parent node. + previous_node = node; + node = parent; + } + } + }; - NodeState::BeingVisited { depth } => { - self.node_states[r] = - NodeState::InCycleWith { parent: self.node_stack[depth] }; - parent_state - } + // The states form a graph where up to one outgoing link is stored at + // each node. Initially in general, + // + // E + // ^ + // | + // InCycleWith/BeingVisited/NotVisited + // | + // A-InCycleWith->B-InCycleWith…>C-InCycleWith->D-+ + // | + // = node, previous_node + // + // After the first loop, this will look like + // E + // ^ + // | + // InCycleWith/BeingVisited/NotVisited + // | + // +>A<-InCycleWith-B<…InCycleWith-C<-InCycleWith-D-+ + // | | | | + // | InCycleWith | = node + // +-+ =previous_node + // + // Note in particular that A will be linked to itself in a self-cycle + // and no other self-cycles occur due to how InCycleWith is assigned in + // the find phase implemented by `walk_unvisited_node`. + // + // We now want to compress the path, that is assign the state of the + // link D-E to all other links. + // + // We can then walk backwards, starting from `previous_node`, and assign + // each node in the list with the updated state. The loop terminates + // when we reach the self-cycle. + + // Move backwards until we found the node where we started. We + // will know when we hit the state where previous_node == node. + loop { + // Back at the beginning, we can return. + if previous_node == node { + return node_state; + } + // Update to previous node in the link. + match self.node_states[previous_node] { + NodeState::InCycleWith { parent: previous } => { + node = previous_node; + previous_node = previous; + } + // Only InCycleWith nodes were added to the reverse linked list. + other => panic!("Invalid previous link while compressing cycle: {:?}", other), + } - NodeState::NotVisited | NodeState::InCycleWith { .. } => { - panic!("invalid parent state: {:?}", parent_state) - } + debug!("find_state: parent_state = {:?}", node_state); + + // Update the node state from the parent state. The assigned + // state is actually a loop invariant but it will only be + // evaluated if there is at least one backlink to follow. + // Fully trusting llvm here to find this loop optimization. + match node_state { + // Path compression, make current node point to the same root. + NodeState::InCycle { .. } => { + self.node_states[node] = node_state; + } + // Still visiting nodes, compress to cycle to the node + // at that depth. + NodeState::BeingVisited { depth } => { + self.node_states[node] = + NodeState::InCycleWith { parent: self.node_stack[depth] }; + } + // These are never allowed as parent nodes. InCycleWith + // should have been followed to a real parent and + // NotVisited can not be part of a cycle since it should + // have instead gotten explored. + NodeState::NotVisited | NodeState::InCycleWith { .. } => { + panic!("invalid parent state: {:?}", node_state) } } } } /// Walks a node that has never been visited before. - fn walk_unvisited_node(&mut self, depth: usize, node: G::Node) -> WalkReturn { - debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node); - - debug_assert!(matches!(self.node_states[node], NodeState::NotVisited)); - - // Push `node` onto the stack. - self.node_states[node] = NodeState::BeingVisited { depth }; - self.node_stack.push(node); - - // Walk each successor of the node, looking to see if any of - // them can reach a node that is presently on the stack. If - // so, that means they can also reach us. - let mut min_depth = depth; - let mut min_cycle_root = node; - let successors_len = self.successors_stack.len(); - for successor_node in self.graph.successors(node) { - debug!("walk_unvisited_node: node = {:?} successor_ode = {:?}", node, successor_node); - match self.walk_node(depth + 1, successor_node) { - WalkReturn::Cycle { min_depth: successor_min_depth } => { - // Track the minimum depth we can reach. - assert!(successor_min_depth <= depth); - if successor_min_depth < min_depth { + /// + /// Call this method when `inspect_node` has returned `None`. Having the + /// caller decide avoids mutual recursion between the two methods and allows + /// us to maintain an allocated stack for nodes on the path between calls. + fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { + struct VisitingNodeFrame { + node: G::Node, + iter: Option, + depth: usize, + min_depth: usize, + successors_len: usize, + min_cycle_root: G::Node, + successor_node: G::Node, + } + + // Move the stack to a local variable. We want to utilize the existing allocation and + // mutably borrow it without borrowing self at the same time. + let mut successors_stack = core::mem::take(&mut self.successors_stack); + debug_assert_eq!(successors_stack.len(), 0); + + let mut stack: Vec> = vec![VisitingNodeFrame { + node: initial, + depth: 0, + min_depth: 0, + iter: None, + successors_len: 0, + min_cycle_root: initial, + successor_node: initial, + }]; + + let mut return_value = None; + + 'recurse: while let Some(frame) = stack.last_mut() { + let VisitingNodeFrame { + node, + depth, + iter, + successors_len, + min_depth, + min_cycle_root, + successor_node, + } = frame; + + let node = *node; + let depth = *depth; + + let successors = match iter { + Some(iter) => iter, + None => { + // This None marks that we still have the initialize this node's frame. + debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node); + + debug_assert!(matches!(self.node_states[node], NodeState::NotVisited)); + + // Push `node` onto the stack. + self.node_states[node] = NodeState::BeingVisited { depth }; + self.node_stack.push(node); + + // Walk each successor of the node, looking to see if any of + // them can reach a node that is presently on the stack. If + // so, that means they can also reach us. + *successors_len = successors_stack.len(); + // Set and return a reference, this is currently empty. + iter.get_or_insert(self.graph.successors(node)) + } + }; + + // Now that iter is initialized, this is a constant for this frame. + let successors_len = *successors_len; + + // Construct iterators for the nodes and walk results. There are two cases: + // * The walk of a successor node returned. + // * The remaining successor nodes. + let returned_walk = + return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); + + let successor_walk = successors.by_ref().map(|successor_node| { + debug!( + "walk_unvisited_node: node = {:?} successor_ode = {:?}", + node, successor_node + ); + (successor_node, self.inspect_node(successor_node)) + }); + + for (successor_node, walk) in returned_walk.chain(successor_walk) { + match walk { + Some(WalkReturn::Cycle { min_depth: successor_min_depth }) => { + // Track the minimum depth we can reach. + assert!(successor_min_depth <= depth); + if successor_min_depth < *min_depth { + debug!( + "walk_unvisited_node: node = {:?} successor_min_depth = {:?}", + node, successor_min_depth + ); + *min_depth = successor_min_depth; + *min_cycle_root = successor_node; + } + } + + Some(WalkReturn::Complete { scc_index: successor_scc_index }) => { + // Push the completed SCC indices onto + // the `successors_stack` for later. debug!( - "walk_unvisited_node: node = {:?} successor_min_depth = {:?}", - node, successor_min_depth + "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", + node, successor_scc_index ); - min_depth = successor_min_depth; - min_cycle_root = successor_node; + successors_stack.push(successor_scc_index); } - } - WalkReturn::Complete { scc_index: successor_scc_index } => { - // Push the completed SCC indices onto - // the `successors_stack` for later. - debug!( - "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", - node, successor_scc_index - ); - self.successors_stack.push(successor_scc_index); + None => { + let depth = depth + 1; + debug!("walk_node(depth = {:?}, node = {:?})", depth, successor_node); + // Remember which node the return value will come from. + frame.successor_node = successor_node; + // Start a new stack frame the step into it. + stack.push(VisitingNodeFrame { + node: successor_node, + depth, + iter: None, + successors_len: 0, + min_depth: depth, + min_cycle_root: successor_node, + successor_node: successor_node, + }); + continue 'recurse; + } } } - } - // Completed walk, remove `node` from the stack. - let r = self.node_stack.pop(); - debug_assert_eq!(r, Some(node)); - - // If `min_depth == depth`, then we are the root of the - // cycle: we can't reach anyone further down the stack. - if min_depth == depth { - // Note that successor stack may have duplicates, so we - // want to remove those: - let deduplicated_successors = { - let duplicate_set = &mut self.duplicate_set; - duplicate_set.clear(); - self.successors_stack - .drain(successors_len..) - .filter(move |&i| duplicate_set.insert(i)) - }; - let scc_index = self.scc_data.create_scc(deduplicated_successors); - self.node_states[node] = NodeState::InCycle { scc_index }; - WalkReturn::Complete { scc_index } - } else { - // We are not the head of the cycle. Return back to our - // caller. They will take ownership of the - // `self.successors` data that we pushed. - self.node_states[node] = NodeState::InCycleWith { parent: min_cycle_root }; - WalkReturn::Cycle { min_depth } + // Completed walk, remove `node` from the stack. + let r = self.node_stack.pop(); + debug_assert_eq!(r, Some(node)); + + // Remove the frame, it's done. + let frame = stack.pop().unwrap(); + + // If `min_depth == depth`, then we are the root of the + // cycle: we can't reach anyone further down the stack. + + // Pass the 'return value' down the stack. + // We return one frame at a time so there can't be another return value. + debug_assert!(return_value.is_none()); + return_value = Some(if frame.min_depth == depth { + // Note that successor stack may have duplicates, so we + // want to remove those: + let deduplicated_successors = { + let duplicate_set = &mut self.duplicate_set; + duplicate_set.clear(); + successors_stack + .drain(successors_len..) + .filter(move |&i| duplicate_set.insert(i)) + }; + let scc_index = self.scc_data.create_scc(deduplicated_successors); + self.node_states[node] = NodeState::InCycle { scc_index }; + WalkReturn::Complete { scc_index } + } else { + // We are not the head of the cycle. Return back to our + // caller. They will take ownership of the + // `self.successors` data that we pushed. + self.node_states[node] = NodeState::InCycleWith { parent: frame.min_cycle_root }; + WalkReturn::Cycle { min_depth: frame.min_depth } + }); } + + // Keep the allocation we used for successors_stack. + self.successors_stack = successors_stack; + debug_assert_eq!(self.successors_stack.len(), 0); + + return_value.unwrap() } } diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 1d5f46ebab..364005e67e 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -1,3 +1,5 @@ +extern crate test; + use super::*; use crate::graph::tests::TestGraph; @@ -139,3 +141,73 @@ fn test_find_state_3() { assert_eq!(sccs.successors(0), &[]); assert_eq!(sccs.successors(1), &[0]); } + +#[test] +fn test_deep_linear() { + /* + 0 + | + v + 1 + | + v + 2 + | + v + … + */ + const NR_NODES: usize = 1 << 14; + let mut nodes = vec![]; + for i in 1..NR_NODES { + nodes.push((i - 1, i)); + } + let graph = TestGraph::new(0, nodes.as_slice()); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), NR_NODES); + assert_eq!(sccs.scc(0), NR_NODES - 1); + assert_eq!(sccs.scc(NR_NODES - 1), 0); +} + +#[bench] +fn bench_sccc(b: &mut test::Bencher) { + // Like `test_three_sccs` but each state is replaced by a group of + // three or four to have some amount of test data. + /* + 0-3 + | + v + +->4-6 11-14 + | | | + | v | + +--7-10<-+ + */ + fn make_3_clique(slice: &mut [(usize, usize)], base: usize) { + slice[0] = (base + 0, base + 1); + slice[1] = (base + 1, base + 2); + slice[2] = (base + 2, base + 0); + } + // Not actually a clique but strongly connected. + fn make_4_clique(slice: &mut [(usize, usize)], base: usize) { + slice[0] = (base + 0, base + 1); + slice[1] = (base + 1, base + 2); + slice[2] = (base + 2, base + 3); + slice[3] = (base + 3, base + 0); + slice[4] = (base + 1, base + 3); + slice[5] = (base + 2, base + 1); + } + + let mut graph = [(0, 0); 6 + 3 + 6 + 3 + 4]; + make_4_clique(&mut graph[0..6], 0); + make_3_clique(&mut graph[6..9], 4); + make_4_clique(&mut graph[9..15], 7); + make_3_clique(&mut graph[15..18], 11); + graph[18] = (0, 4); + graph[19] = (5, 7); + graph[20] = (11, 10); + graph[21] = (7, 4); + let graph = TestGraph::new(0, &graph[..]); + b.iter(|| { + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 3); + }); +} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 7669b78834..d903a557c7 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -15,7 +15,8 @@ #![feature(fn_traits)] #![feature(int_bits_const)] #![feature(min_specialization)] -#![feature(optin_builtin_traits)] +#![cfg_attr(bootstrap, feature(optin_builtin_traits))] +#![cfg_attr(not(bootstrap), feature(auto_traits))] #![feature(nll)] #![feature(allow_internal_unstable)] #![feature(hash_raw_entry)] @@ -27,9 +28,11 @@ #![feature(extend_one)] #![feature(const_panic)] #![feature(min_const_generics)] +#![feature(new_uninit)] #![feature(once_cell)] #![feature(maybe_uninit_uninit_array)] #![allow(rustc::default_hash_types)] +#![deny(unaligned_references)] #[macro_use] extern crate tracing; @@ -47,9 +50,9 @@ pub fn cold_path R, R>(f: F) -> R { #[macro_export] macro_rules! likely { ($e:expr) => { - #[allow(unused_unsafe)] - { - unsafe { std::intrinsics::likely($e) } + match $e { + #[allow(unused_unsafe)] + e => unsafe { std::intrinsics::likely(e) }, } }; } @@ -57,9 +60,9 @@ macro_rules! likely { #[macro_export] macro_rules! unlikely { ($e:expr) => { - #[allow(unused_unsafe)] - { - unsafe { std::intrinsics::unlikely($e) } + match $e { + #[allow(unused_unsafe)] + e => unsafe { std::intrinsics::unlikely(e) }, } }; } @@ -70,6 +73,7 @@ pub mod box_region; pub mod captures; pub mod const_cstr; pub mod flock; +pub mod functor; pub mod fx; pub mod graph; pub mod jobserver; @@ -102,6 +106,7 @@ pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; pub mod sso; +pub mod steal; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index e598d7a683..5d13b7f27c 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -272,6 +272,28 @@ impl SelfProfilerRef { }) } + #[inline(always)] + pub fn generic_activity_with_args( + &self, + event_label: &'static str, + event_args: &[String], + ) -> TimingGuard<'_> { + self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { + let builder = EventIdBuilder::new(&profiler.profiler); + let event_label = profiler.get_or_alloc_cached_string(event_label); + let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) { + let event_args: Vec<_> = event_args + .iter() + .map(|s| profiler.get_or_alloc_cached_string(&s[..])) + .collect(); + builder.from_label_and_args(event_label, &event_args) + } else { + builder.from_label(event_label) + }; + TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) + }) + } + /// Start profiling a query provider. Profiling continues until the /// TimingGuard returned from this call is dropped. #[inline(always)] diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index 2bb421a47e..01cd1cec92 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -24,8 +24,7 @@ use rustc_index::vec::{Idx, IndexVec}; /// to insert into the middle of the sorted array. Users should avoid mutating this data structure /// in-place. /// -/// [`IndexVec`]: ../../rustc_index/vec/struct.IndexVec.html -/// [`SortedMap`]: ../sorted_map/struct.SortedMap.html +/// [`SortedMap`]: super::SortedMap #[derive(Clone, Debug)] pub struct SortedIndexMultiMap { /// The elements of the map in insertion order. diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index fe8ae7abf9..06e8442d47 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -40,7 +40,7 @@ const SSO_ARRAY_SIZE: usize = 8; // into_keys/into_values (unstable) // all raw_entry-related // PartialEq/Eq (requires sorting the array) -// Entry::or_insert_with_key (unstable) +// Entry::or_insert_with_key // Vacant/Occupied entries and related // // FIXME: In HashMap most methods accepting key reference diff --git a/compiler/rustc_middle/src/ty/steal.rs b/compiler/rustc_data_structures/src/steal.rs similarity index 82% rename from compiler/rustc_middle/src/ty/steal.rs rename to compiler/rustc_data_structures/src/steal.rs index 224e76845d..e532a84cea 100644 --- a/compiler/rustc_middle/src/ty/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -1,4 +1,5 @@ -use rustc_data_structures::sync::{MappedReadGuard, ReadGuard, RwLock}; +use crate::stable_hasher::{HashStable, StableHasher}; +use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; /// The `Steal` struct is intended to used as the value for a query. /// Specifically, we sometimes have queries (*cough* MIR *cough*) @@ -31,7 +32,7 @@ impl Steal { pub fn borrow(&self) -> MappedReadGuard<'_, T> { ReadGuard::map(self.value.borrow(), |opt| match *opt { - None => bug!("attempted to read from stolen value"), + None => panic!("attempted to read from stolen value"), Some(ref v) => v, }) } @@ -42,3 +43,9 @@ impl Steal { value.expect("attempt to read from stolen value") } } + +impl> HashStable for Steal { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.borrow().hash_stable(hcx, hasher); + } +} diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index a192c2eb94..b3466f49b9 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -20,7 +20,7 @@ use rustc_data_structures::profiling::print_time_passes_entry; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ErrorReported, PResult}; -use rustc_feature::{find_gated_cfg, UnstableFeatures}; +use rustc_feature::find_gated_cfg; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend}; use rustc_interface::{interface, Queries}; @@ -223,7 +223,6 @@ fn run_compiler( file_loader: None, diagnostic_output, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, @@ -248,11 +247,18 @@ fn run_compiler( interface::run_compiler(config, |compiler| { let sopts = &compiler.session().opts; if sopts.describe_lints { - let lint_store = rustc_lint::new_lint_store( + let mut lint_store = rustc_lint::new_lint_store( sopts.debugging_opts.no_interleave_lints, compiler.session().unstable_options(), ); - describe_lints(compiler.session(), &lint_store, false); + let registered_lints = + if let Some(register_lints) = compiler.register_lints() { + register_lints(compiler.session(), &mut lint_store); + true + } else { + false + }; + describe_lints(compiler.session(), &lint_store, registered_lints); return; } let should_stop = RustcDefaultCalls::print_crate_info( @@ -300,7 +306,6 @@ fn run_compiler( file_loader, diagnostic_output, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, @@ -746,9 +751,6 @@ impl RustcDefaultCalls { } } Cfg => { - let allow_unstable_cfg = - UnstableFeatures::from_environment().is_nightly_build(); - let mut cfgs = sess .parse_sess .config @@ -763,7 +765,7 @@ impl RustcDefaultCalls { // it, this is intended to get into Cargo and then go // through to build scripts. if (name != sym::target_feature || value != Some(sym::crt_dash_static)) - && !allow_unstable_cfg + && !sess.is_nightly_build() && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() { return None; @@ -814,14 +816,14 @@ pub fn version(binary: &str, matches: &getopts::Matches) { } } -fn usage(verbose: bool, include_unstable_options: bool) { +fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() }; let mut options = getopts::Options::new(); for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) { (option.apply)(&mut options); } let message = "Usage: rustc [OPTIONS] INPUT"; - let nightly_help = if nightly_options::is_nightly_build() { + let nightly_help = if nightly_build { "\n -Z help Print unstable compiler options" } else { "" @@ -831,7 +833,7 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - let at_path = if verbose && nightly_options::is_nightly_build() { + let at_path = if verbose && nightly_build { " @path Read newline separated options from `path`\n" } else { "" @@ -957,10 +959,7 @@ Available lint options: match (loaded_plugins, plugin.len(), plugin_groups.len()) { (false, 0, _) | (false, _, 0) => { - println!( - "Compiler plugins can provide additional lints and lint groups. To see a \ - listing of these, re-run `rustc -W help` with a crate filename." - ); + println!("Lint tools like Clippy can provide additional lints and lint groups."); } (false, ..) => panic!("didn't load lint plugins but got them anyway!"), (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), @@ -1034,7 +1033,9 @@ pub fn handle_options(args: &[String]) -> Option { if args.is_empty() { // user did not write `-v` nor `-Z unstable-options`, so do not // include that extra information. - usage(false, false); + let nightly_build = + rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build(); + usage(false, false, nightly_build); return None; } @@ -1063,7 +1064,9 @@ pub fn handle_options(args: &[String]) -> Option { if matches.opt_present("h") || matches.opt_present("help") { // Only show unstable options in --help if we accept unstable options. - usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); + let unstable_enabled = nightly_options::is_unstable_enabled(&matches); + let nightly_build = nightly_options::match_is_nightly_build(&matches); + usage(matches.opt_present("verbose"), unstable_enabled, nightly_build); return None; } @@ -1283,10 +1286,30 @@ pub fn init_env_logger(env: &str) { Ok(s) if s.is_empty() => return, Ok(_) => {} } + let color_logs = match std::env::var(String::from(env) + "_COLOR") { + Ok(value) => match value.as_ref() { + "always" => true, + "never" => false, + "auto" => stdout_isatty(), + _ => early_error( + ErrorOutputType::default(), + &format!( + "invalid log color value '{}': expected one of always, never, or auto", + value + ), + ), + }, + Err(std::env::VarError::NotPresent) => stdout_isatty(), + Err(std::env::VarError::NotUnicode(_value)) => early_error( + ErrorOutputType::default(), + "non-Unicode log color value: expected one of always, never, or auto", + ), + }; let filter = tracing_subscriber::EnvFilter::from_env(env); let layer = tracing_tree::HierarchicalLayer::default() + .with_writer(io::stderr) .with_indent_lines(true) - .with_ansi(true) + .with_ansi(color_logs) .with_targets(true) .with_wraparound(10) .with_verbose_exit(true) @@ -1312,7 +1335,7 @@ pub fn main() -> ! { arg.into_string().unwrap_or_else(|arg| { early_error( ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg), + &format!("argument {} is not valid Unicode: {:?}", i, arg), ) }) }) diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index b0fbf1e03f..305fa838af 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -32,9 +32,6 @@ use crate::abort_on_err; // Note that since the `&PrinterSupport` is freshly constructed on each // call, it would not make sense to try to attach the lifetime of `self` // to the lifetime of the `&PrinterObject`. -// -// (The `use_once_payload` is working around the current lack of once -// functions in the compiler.) /// Constructs a `PrinterSupport` object and passes it to `f`. fn call_with_pp_support<'tcx, A, F>( @@ -407,7 +404,6 @@ pub fn print_after_parsing( annotation.pp_ann(), false, parse.edition, - parse.injected_crate_name.get().is_some(), ) }) } else { @@ -449,7 +445,6 @@ pub fn print_after_hir_lowering<'tcx>( annotation.pp_ann(), true, parse.edition, - parse.injected_crate_name.get().is_some(), ) }) } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 0a88759f84..fef6602b9c 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -111,6 +111,7 @@ E0206: include_str!("./error_codes/E0206.md"), E0207: include_str!("./error_codes/E0207.md"), E0210: include_str!("./error_codes/E0210.md"), E0211: include_str!("./error_codes/E0211.md"), +E0212: include_str!("./error_codes/E0212.md"), E0214: include_str!("./error_codes/E0214.md"), E0220: include_str!("./error_codes/E0220.md"), E0221: include_str!("./error_codes/E0221.md"), @@ -283,6 +284,7 @@ E0537: include_str!("./error_codes/E0537.md"), E0538: include_str!("./error_codes/E0538.md"), E0539: include_str!("./error_codes/E0539.md"), E0541: include_str!("./error_codes/E0541.md"), +E0546: include_str!("./error_codes/E0546.md"), E0550: include_str!("./error_codes/E0550.md"), E0551: include_str!("./error_codes/E0551.md"), E0552: include_str!("./error_codes/E0552.md"), @@ -502,7 +504,6 @@ E0779: include_str!("./error_codes/E0779.md"), // E0196, // cannot determine a type for this closure E0208, // E0209, // builtin traits can only be implemented on structs or enums - E0212, // cannot extract an associated type from a higher-ranked trait bound // E0213, // associated types are not accepted in this context // E0215, // angle-bracket notation is not stable with `Fn` // E0216, // parenthetical notation is only stable with `Fn` @@ -603,7 +604,6 @@ E0779: include_str!("./error_codes/E0779.md"), E0543, // missing 'reason' E0544, // multiple stability levels E0545, // incorrect 'issue' - E0546, // missing 'feature' E0547, // missing 'issue' // E0548, // replaced with a generic attribute input check // rustc_deprecated attribute must be paired with either stable or unstable diff --git a/compiler/rustc_error_codes/src/error_codes/E0198.md b/compiler/rustc_error_codes/src/error_codes/E0198.md index 90f1e54287..1238165cb8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0198.md +++ b/compiler/rustc_error_codes/src/error_codes/E0198.md @@ -16,7 +16,7 @@ unsafe. This will compile: ```ignore (ignore auto_trait future compatibility warning) -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] struct Foo; diff --git a/compiler/rustc_error_codes/src/error_codes/E0212.md b/compiler/rustc_error_codes/src/error_codes/E0212.md new file mode 100644 index 0000000000..1746541465 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0212.md @@ -0,0 +1,35 @@ +Cannot use the associated type of +a trait with uninferred generic parameters. + +Erroneous code example: + +```compile_fail,E0212 +pub trait Foo { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo2 Foo<&'x isize>>( + field: I::A) {} // error! +``` + +In this example, we have to instantiate `'x`, and +we don't know what lifetime to instantiate it with. +To fix this, spell out the precise lifetimes involved. +Example: + +``` +pub trait Foo { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo3 Foo<&'x isize>>( + x: >::A) {} // ok! + + +fn foo4<'a, I : for<'x> Foo<&'x isize>>( + x: >::A) {} // ok! +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0321.md b/compiler/rustc_error_codes/src/error_codes/E0321.md index bfcdabfe9d..bcfc12897c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0321.md +++ b/compiler/rustc_error_codes/src/error_codes/E0321.md @@ -4,7 +4,7 @@ or enum type. Erroneous code example: ```compile_fail,E0321 -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] struct Foo; diff --git a/compiler/rustc_error_codes/src/error_codes/E0390.md b/compiler/rustc_error_codes/src/error_codes/E0390.md index ecc5b5568a..7a13160d09 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0390.md +++ b/compiler/rustc_error_codes/src/error_codes/E0390.md @@ -1,4 +1,4 @@ -A method was implemented on a primitive type. +A method or constant was implemented on a primitive type. Erroneous code example: @@ -12,7 +12,8 @@ impl *mut Foo {} // `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive ``` -This isn't allowed, but using a trait to implement a method is a good solution. +This isn't allowed, but using a trait to implement a method or constant +is a good solution. Example: ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0546.md b/compiler/rustc_error_codes/src/error_codes/E0546.md new file mode 100644 index 0000000000..b2df22c0f8 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0546.md @@ -0,0 +1,27 @@ +A feature name is missing. + +Erroneous code example: + +```compile_fail,E0546 +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[unstable(issue = "none")] // invalid +fn unstable_fn() {} + +#[stable(since = "1.0.0")] // invalid +fn stable_fn() {} +``` + +To fix the issue you need to provide a feature name. + +``` +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[unstable(feature = "unstable_fn", issue = "none")] // ok! +fn unstable_fn() {} + +#[stable(feature = "stable_fn", since = "1.0.0")] // ok! +fn stable_fn() {} +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0567.md b/compiler/rustc_error_codes/src/error_codes/E0567.md index 05cf8fed03..bc13ee4c04 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0567.md +++ b/compiler/rustc_error_codes/src/error_codes/E0567.md @@ -3,7 +3,7 @@ Generics have been used on an auto trait. Erroneous code example: ```compile_fail,E0567 -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] auto trait Generic {} // error! # fn main() {} @@ -16,7 +16,7 @@ parameters. To fix this issue, just remove the generics: ``` -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] auto trait Generic {} // ok! # fn main() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0568.md b/compiler/rustc_error_codes/src/error_codes/E0568.md index a37381f1cb..17b3f5e31b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0568.md +++ b/compiler/rustc_error_codes/src/error_codes/E0568.md @@ -3,7 +3,7 @@ A super trait has been added to an auto trait. Erroneous code example: ```compile_fail,E0568 -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] auto trait Bound : Copy {} // error! @@ -18,7 +18,7 @@ all the existing types could implement `Bound` because very few of them have the To fix this issue, just remove the super trait: ``` -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] auto trait Bound {} // ok! diff --git a/compiler/rustc_error_codes/src/error_codes/E0591.md b/compiler/rustc_error_codes/src/error_codes/E0591.md index 7f68815b1c..f49805d9b4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0591.md +++ b/compiler/rustc_error_codes/src/error_codes/E0591.md @@ -1,14 +1,20 @@ Per [RFC 401][rfc401], if you have a function declaration `foo`: ``` +struct S; + // For the purposes of this explanation, all of these // different kinds of `fn` declarations are equivalent: -struct S; + fn foo(x: S) { /* ... */ } # #[cfg(for_demonstration_only)] -extern "C" { fn foo(x: S); } +extern "C" { + fn foo(x: S); +} # #[cfg(for_demonstration_only)] -impl S { fn foo(self) { /* ... */ } } +impl S { + fn foo(self) { /* ... */ } +} ``` the type of `foo` is **not** `fn(S)`, as one might expect. @@ -40,10 +46,10 @@ extern "C" fn foo(userdata: Box) { # fn callback(_: extern "C" fn(*mut i32)) {} # use std::mem::transmute; -# unsafe { -let f: extern "C" fn(*mut i32) = transmute(foo); -callback(f); -# } +unsafe { + let f: extern "C" fn(*mut i32) = transmute(foo); + callback(f); +} ``` Here, transmute is being used to convert the types of the fn arguments. diff --git a/compiler/rustc_error_codes/src/error_codes/E0744.md b/compiler/rustc_error_codes/src/error_codes/E0744.md index 14cff3613e..45804ab266 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0744.md +++ b/compiler/rustc_error_codes/src/error_codes/E0744.md @@ -1,4 +1,4 @@ -A control-flow expression was used inside a const context. +An unsupported expression was used inside a const context. Erroneous code example: @@ -12,12 +12,15 @@ const _: i32 = { }; ``` -At the moment, `if` and `match`, as well as the looping constructs `for`, -`while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`. +At the moment, `for` loops, `.await`, and the `Try` operator (`?`) are forbidden +inside a `const`, `static`, or `const fn`. -This will be allowed at some point in the future, but the implementation is not -yet complete. See the tracking issue for [conditionals] or [loops] in a const -context for the current status. +This may be allowed at some point in the future, but the implementation is not +yet complete. See the tracking issues for [`async`] and [`?`] in `const fn`, and +(to support `for` loops in `const fn`) the tracking issues for [`impl const +Trait for Ty`] and [`&mut T`] in `const fn`. -[conditionals]: https://github.com/rust-lang/rust/issues/49146 -[loops]: https://github.com/rust-lang/rust/issues/52000 +[`async`]: https://github.com/rust-lang/rust/issues/69431 +[`?`]: https://github.com/rust-lang/rust/issues/74935 +[`impl const Trait for Ty`]: https://github.com/rust-lang/rust/issues/67792 +[`&mut T`]: https://github.com/rust-lang/rust/issues/57349 diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index decbf03b9d..e61476bf23 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -30,7 +30,8 @@ pub enum DiagnosticId { Lint { name: String, has_future_breakage: bool }, } -/// For example a note attached to an error. +/// A "sub"-diagnostic attached to a parent diagnostic. +/// For example, a note attached to an error. #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] pub struct SubDiagnostic { pub level: Level, @@ -124,6 +125,7 @@ impl Diagnostic { self.level = Level::Cancelled; } + /// Check if this diagnostic [was cancelled][Self::cancel()]. pub fn cancelled(&self) -> bool { self.level == Level::Cancelled } @@ -136,8 +138,6 @@ impl Diagnostic { /// /// This span is *not* considered a ["primary span"][`MultiSpan`]; only /// the `Span` supplied when creating the diagnostic is primary. - /// - /// [`MultiSpan`]: ../rustc_span/struct.MultiSpan.html pub fn span_label>(&mut self, span: Span, label: T) -> &mut Self { self.span.push_span_label(span, label.into()); self @@ -164,7 +164,7 @@ impl Diagnostic { self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") } - pub fn note_unsuccessfull_coercion( + pub fn note_unsuccessful_coercion( &mut self, expected: DiagnosticStyledString, found: DiagnosticStyledString, @@ -241,6 +241,7 @@ impl Diagnostic { self } + /// Add a note attached to this diagnostic. pub fn note(&mut self, msg: &str) -> &mut Self { self.sub(Level::Note, msg, MultiSpan::new(), None); self @@ -252,33 +253,40 @@ impl Diagnostic { } /// Prints the span with a note above it. + /// This is like [`Diagnostic::note()`], but it gets its own span. pub fn span_note>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Note, msg, sp.into(), None); self } + /// Add a warning attached to this diagnostic. pub fn warn(&mut self, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, MultiSpan::new(), None); self } - /// Prints the span with a warn above it. + /// Prints the span with a warning above it. + /// This is like [`Diagnostic::warn()`], but it gets its own span. pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, sp.into(), None); self } + /// Add a help message attached to this diagnostic. pub fn help(&mut self, msg: &str) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), None); self } /// Prints the span with some help above it. + /// This is like [`Diagnostic::help()`], but it gets its own span. pub fn span_help>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Help, msg, sp.into(), None); self } + /// Show a suggestion that has multiple parts to it. + /// In other words, multiple changes need to be applied as part of this suggestion. pub fn multipart_suggestion( &mut self, msg: &str, @@ -299,6 +307,8 @@ impl Diagnostic { self } + /// Show multiple suggestions that have multiple parts. + /// See also [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestions( &mut self, msg: &str, @@ -382,6 +392,7 @@ impl Diagnostic { self } + /// [`Diagnostic::span_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn span_suggestion_with_style( &mut self, sp: Span, @@ -401,6 +412,7 @@ impl Diagnostic { self } + /// Always show the suggested change. pub fn span_suggestion_verbose( &mut self, sp: Span, @@ -419,6 +431,7 @@ impl Diagnostic { } /// Prints out a message with multiple suggested edits of the code. + /// See also [`Diagnostic::span_suggestion()`]. pub fn span_suggestions( &mut self, sp: Span, @@ -458,7 +471,7 @@ impl Diagnostic { self } - /// Prints out a message with for a suggestion without showing the suggested code. + /// Prints out a message for a suggestion without showing the suggested code. /// /// This is intended to be used for suggestions that are obvious in what the changes need to /// be from the message, showing the span label inline would be visually unpleasant @@ -481,7 +494,7 @@ impl Diagnostic { self } - /// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli. + /// Adds a suggestion to the JSON output that will not be shown in the CLI. /// /// This is intended to be used for suggestions that are *very* obvious in what the changes /// need to be from the message, but we still want other tools to be able to apply them. diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 56acdf699e..f165a60336 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -30,6 +30,15 @@ struct DiagnosticBuilderInner<'a> { allow_suggestions: bool, } +/// This is a helper macro for [`forward!`] that allows automatically adding documentation +/// that uses tokens from [`forward!`]'s input. +macro_rules! forward_inner_docs { + ($e:expr => $i:item) => { + #[doc = $e] + $i + } +} + /// In general, the `DiagnosticBuilder` uses deref to allow access to /// the fields and methods of the embedded `diagnostic` in a /// transparent way. *However,* many of the methods are intended to @@ -45,10 +54,11 @@ macro_rules! forward { pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self ) => { $(#[$attrs])* + forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") => pub fn $n(&self, $($name: $ty),*) -> &Self { self.diagnostic.$n($($name),*); self - } + }); }; // Forward pattern for &mut self -> &mut Self @@ -57,10 +67,11 @@ macro_rules! forward { pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self ) => { $(#[$attrs])* + forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") => pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { self.0.diagnostic.$n($($name),*); self - } + }); }; // Forward pattern for &mut self -> &mut Self, with S: Into @@ -74,10 +85,11 @@ macro_rules! forward { ) -> &mut Self ) => { $(#[$attrs])* + forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") => pub fn $n>(&mut self, $($name: $ty),*) -> &mut Self { self.0.diagnostic.$n($($name),*); self - } + }); }; } @@ -116,7 +128,7 @@ impl<'a> DiagnosticBuilder<'a> { /// Stashes diagnostic for possible later improvement in a different, /// later stage of the compiler. The diagnostic can be accessed with - /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`. + /// the provided `span` and `key` through [`Handler::steal_diagnostic()`]. /// /// As with `buffer`, this is unless the handler has disabled such buffering. pub fn stash(self, span: Span, key: StashKey) { @@ -184,23 +196,25 @@ impl<'a> DiagnosticBuilder<'a> { self.cancel(); } - /// Adds a span/label to be included in the resulting snippet. - /// - /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic - /// was first built. That means it will be shown together with the original - /// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods. + /// Appends a labeled span to the diagnostic. /// - /// This span is *not* considered a ["primary span"][`MultiSpan`]; only - /// the `Span` supplied when creating the diagnostic is primary. + /// Labels are used to convey additional context for the diagnostic's primary span. They will + /// be shown together with the original diagnostic's span, *not* with spans added by + /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because + /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed + /// either. /// - /// [`MultiSpan`]: ../rustc_span/struct.MultiSpan.html + /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when + /// the diagnostic was constructed. However, the label span is *not* considered a + /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is + /// primary. pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self { self.0.diagnostic.span_label(span, label); self } /// Labels all the given spans with the provided label. - /// See `span_label` for more information. + /// See [`Diagnostic::span_label()`] for more information. pub fn span_labels( &mut self, spans: impl IntoIterator, @@ -231,7 +245,7 @@ impl<'a> DiagnosticBuilder<'a> { found_extra: &dyn fmt::Display, ) -> &mut Self); - forward!(pub fn note_unsuccessfull_coercion( + forward!(pub fn note_unsuccessful_coercion( &mut self, expected: DiagnosticStyledString, found: DiagnosticStyledString, @@ -252,6 +266,7 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, ) -> &mut Self); + /// See [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestion( &mut self, msg: &str, @@ -265,6 +280,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::multipart_suggestions()`]. pub fn multipart_suggestions( &mut self, msg: &str, @@ -278,6 +294,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::tool_only_multipart_suggestion()`]. pub fn tool_only_multipart_suggestion( &mut self, msg: &str, @@ -291,6 +308,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion()`]. pub fn span_suggestion( &mut self, sp: Span, @@ -305,6 +323,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestions()`]. pub fn span_suggestions( &mut self, sp: Span, @@ -319,6 +338,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion_short()`]. pub fn span_suggestion_short( &mut self, sp: Span, @@ -333,6 +353,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion_verbose()`]. pub fn span_suggestion_verbose( &mut self, sp: Span, @@ -347,6 +368,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::span_suggestion_hidden()`]. pub fn span_suggestion_hidden( &mut self, sp: Span, @@ -361,6 +383,7 @@ impl<'a> DiagnosticBuilder<'a> { self } + /// See [`Diagnostic::tool_only_span_suggestion()`] for more information. pub fn tool_only_span_suggestion( &mut self, sp: Span, @@ -378,19 +401,22 @@ impl<'a> DiagnosticBuilder<'a> { forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); + /// Allow attaching suggestions this diagnostic. + /// If this is set to `false`, then any suggestions attached with the `span_suggestion_*` + /// methods after this is set to `false` will be ignored. pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self { self.0.allow_suggestions = allow; self } /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. + /// `struct_*` methods on [`Handler`]. crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder::new_with_code(handler, level, None, message) } /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. + /// `struct_*` methods on [`Handler`]. crate fn new_with_code( handler: &'a Handler, level: Level, diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 302713a21d..32104e6f00 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -200,6 +200,11 @@ pub trait Emitter { true } + /// Checks if we can use colors in the current output stream. + fn supports_color(&self) -> bool { + false + } + fn source_map(&self) -> Option<&Lrc>; /// Formats the substitutions of the primary_span @@ -504,6 +509,10 @@ impl Emitter for EmitterWriter { fn should_show_explain(&self) -> bool { !self.short_message } + + fn supports_color(&self) -> bool { + self.dst.supports_color() + } } /// An emitter that does nothing when emitting a diagnostic. @@ -2057,6 +2066,14 @@ impl Destination { Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)), } } + + fn supports_color(&self) -> bool { + match *self { + Self::Terminal(ref stream) => stream.supports_color(), + Self::Buffered(ref buffer) => buffer.buffer().supports_color(), + Self::Raw(_, supports_color) => supports_color, + } + } } impl<'a> WritableDst<'a> { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b435def87a..335f3b7a9a 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -234,6 +234,13 @@ impl Annotatable { pub fn derive_allowed(&self) -> bool { match *self { + Annotatable::Stmt(ref stmt) => match stmt.kind { + ast::StmtKind::Item(ref item) => matches!( + item.kind, + ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) + ), + _ => false, + }, Annotatable::Item(ref item) => match item.kind { ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => { true @@ -251,8 +258,7 @@ pub enum ExpandResult { /// Expansion produced a result (possibly dummy). Ready(T), /// Expansion could not produce a result and needs to be retried. - /// The string is an explanation that will be printed if we are stuck in an infinite retry loop. - Retry(U, String), + Retry(U), } // `meta_item` is the attribute, and `item` is the item being modified. @@ -366,7 +372,6 @@ macro_rules! make_stmts_default { id: ast::DUMMY_NODE_ID, span: e.span, kind: ast::StmtKind::Expr(e), - tokens: None }] }) }; @@ -609,7 +614,6 @@ impl MacResult for DummyResult { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), span: self.span, - tokens: None }]) } @@ -889,8 +893,10 @@ pub trait ResolverExpand { /// Some parent node that is close enough to the given macro call. fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId; + // Resolver interfaces for specific built-in macros. + /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it? fn has_derive_copy(&self, expn_id: ExpnId) -> bool; - fn add_derive_copy(&mut self, expn_id: ExpnId); + /// Path resolution logic for `#[cfg_accessible(path)]`. fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result; } @@ -919,6 +925,9 @@ pub struct ExtCtxt<'a> { pub root_path: PathBuf, pub resolver: &'a mut dyn ResolverExpand, pub current_expansion: ExpansionData, + /// Error recovery mode entered when expansion is stuck + /// (or during eager expansion, but that's a hack). + pub force_mode: bool, pub expansions: FxHashMap>, /// Called directly after having parsed an external `mod foo;` in expansion. pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>, @@ -945,6 +954,7 @@ impl<'a> ExtCtxt<'a> { directory_ownership: DirectoryOwnership::Owned { relative: None }, prior_type_ascription: None, }, + force_mode: false, expansions: FxHashMap::default(), } } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 30f0fc6cdd..fe67b401fc 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -140,12 +140,7 @@ impl<'a> ExtCtxt<'a> { } pub fn stmt_expr(&self, expr: P) -> ast::Stmt { - ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: expr.span, - kind: ast::StmtKind::Expr(expr), - tokens: None, - } + ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) } } pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P) -> ast::Stmt { @@ -162,13 +157,9 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: sp, attrs: AttrVec::new(), - }); - ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Local(local), - span: sp, tokens: None, - } + }); + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } } // Generates `let _: Type;`, which is usually used for type assertions. @@ -180,17 +171,13 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span, attrs: AttrVec::new(), + tokens: None, }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span, tokens: None } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span } } pub fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { - ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Item(item), - span: sp, - tokens: None, - } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp } } pub fn block_expr(&self, expr: P) -> P { @@ -200,7 +187,6 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr), - tokens: None, }], ) } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index cccbdf778e..563783c5b7 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -1,5 +1,7 @@ //! Conditional compilation stripping. +use crate::base::Annotatable; + use rustc_ast::attr::HasAttrs; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; @@ -496,6 +498,49 @@ impl<'a> StripUnconfigured<'a> { pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); } + + pub fn fully_configure(&mut self, item: Annotatable) -> Annotatable { + // Since the item itself has already been configured by the InvocationCollector, + // we know that fold result vector will contain exactly one element + match item { + Annotatable::Item(item) => Annotatable::Item(self.flat_map_item(item).pop().unwrap()), + Annotatable::TraitItem(item) => { + Annotatable::TraitItem(self.flat_map_trait_item(item).pop().unwrap()) + } + Annotatable::ImplItem(item) => { + Annotatable::ImplItem(self.flat_map_impl_item(item).pop().unwrap()) + } + Annotatable::ForeignItem(item) => { + Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap()) + } + Annotatable::Stmt(stmt) => { + Annotatable::Stmt(stmt.map(|stmt| self.flat_map_stmt(stmt).pop().unwrap())) + } + Annotatable::Expr(mut expr) => Annotatable::Expr({ + self.visit_expr(&mut expr); + expr + }), + Annotatable::Arm(arm) => Annotatable::Arm(self.flat_map_arm(arm).pop().unwrap()), + Annotatable::Field(field) => { + Annotatable::Field(self.flat_map_field(field).pop().unwrap()) + } + Annotatable::FieldPat(fp) => { + Annotatable::FieldPat(self.flat_map_field_pattern(fp).pop().unwrap()) + } + Annotatable::GenericParam(param) => { + Annotatable::GenericParam(self.flat_map_generic_param(param).pop().unwrap()) + } + Annotatable::Param(param) => { + Annotatable::Param(self.flat_map_param(param).pop().unwrap()) + } + Annotatable::StructField(sf) => { + Annotatable::StructField(self.flat_map_struct_field(sf).pop().unwrap()) + } + Annotatable::Variant(v) => { + Annotatable::Variant(self.flat_map_variant(v).pop().unwrap()) + } + } + } } impl<'a> MutVisitor for StripUnconfigured<'a> { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1b31bd6a30..2da5bde028 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -209,6 +209,28 @@ impl AstFragmentKind { self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment") } + /// Fragment supports macro expansion and not just inert attributes, `cfg` and `cfg_attr`. + pub fn supports_macro_expansion(self) -> bool { + match self { + AstFragmentKind::OptExpr + | AstFragmentKind::Expr + | AstFragmentKind::Pat + | AstFragmentKind::Ty + | AstFragmentKind::Stmts + | AstFragmentKind::Items + | AstFragmentKind::TraitItems + | AstFragmentKind::ImplItems + | AstFragmentKind::ForeignItems => true, + AstFragmentKind::Arms + | AstFragmentKind::Fields + | AstFragmentKind::FieldPats + | AstFragmentKind::GenericParams + | AstFragmentKind::Params + | AstFragmentKind::StructFields + | AstFragmentKind::Variants => false, + } + } + fn expect_from_annotatables>( self, items: I, @@ -404,6 +426,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Recursively expand all macro invocations in this AST fragment. pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { let orig_expansion_data = self.cx.current_expansion.clone(); + let orig_force_mode = self.cx.force_mode; self.cx.current_expansion.depth = 0; // Collect all macro invocations and replace them with placeholders. @@ -432,6 +455,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } invocations = mem::take(&mut undetermined_invocations); force = !mem::replace(&mut progress, false); + if force && self.monotonic { + self.cx.sess.delay_span_bug( + invocations.last().unwrap().0.span(), + "expansion entered force mode without producing any errors", + ); + } continue; }; @@ -460,18 +489,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); + self.cx.force_mode = force; // FIXME(jseyfried): Refactor out the following logic + let fragment_kind = invoc.fragment_kind; let (expanded_fragment, new_invocations) = match res { InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) { ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]), - ExpandResult::Retry(invoc, explanation) => { + ExpandResult::Retry(invoc) => { if force { - // We are stuck, stop retrying and produce a dummy fragment. - let span = invoc.span(); - self.cx.span_err(span, &explanation); - let fragment = invoc.fragment_kind.dummy(span); - self.collect_invocations(fragment, &[]) + self.cx.span_bug( + invoc.span(), + "expansion entered force mode but is still stuck", + ); } else { // Cannot expand, will retry this invocation later. undetermined_invocations @@ -483,36 +513,45 @@ impl<'a, 'b> MacroExpander<'a, 'b> { InvocationRes::DeriveContainer(_exts) => { // FIXME: Consider using the derive resolutions (`_exts`) immediately, // instead of enqueuing the derives to be resolved again later. - let (derives, item) = match invoc.kind { + let (derives, mut item) = match invoc.kind { InvocationKind::DeriveContainer { derives, item } => (derives, item), _ => unreachable!(), }; - if !item.derive_allowed() { + let (item, derive_placeholders) = if !item.derive_allowed() { self.error_derive_forbidden_on_non_adt(&derives, &item); - } + item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive))); + (item, Vec::new()) + } else { + let mut item = StripUnconfigured { + sess: self.cx.sess, + features: self.cx.ecfg.features, + } + .fully_configure(item); + item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive))); + + invocations.reserve(derives.len()); + let derive_placeholders = derives + .into_iter() + .map(|path| { + let expn_id = ExpnId::fresh(None); + invocations.push(( + Invocation { + kind: InvocationKind::Derive { path, item: item.clone() }, + fragment_kind, + expansion_data: ExpansionData { + id: expn_id, + ..self.cx.current_expansion.clone() + }, + }, + None, + )); + NodeId::placeholder_from_expn_id(expn_id) + }) + .collect::>(); + (item, derive_placeholders) + }; - let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive))); - - let mut derive_placeholders = Vec::with_capacity(derives.len()); - invocations.reserve(derives.len()); - for path in derives { - let expn_id = ExpnId::fresh(None); - derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id)); - invocations.push(( - Invocation { - kind: InvocationKind::Derive { path, item: item.clone() }, - fragment_kind: invoc.fragment_kind, - expansion_data: ExpansionData { - id: expn_id, - ..invoc.expansion_data.clone() - }, - }, - None, - )); - } - let fragment = - invoc.fragment_kind.expect_from_annotatables(::std::iter::once(item)); + let fragment = fragment_kind.expect_from_annotatables(::std::iter::once(item)); self.collect_invocations(fragment, &derive_placeholders) } }; @@ -526,6 +565,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } self.cx.current_expansion = orig_expansion_data; + self.cx.force_mode = orig_force_mode; // Finally incorporate all the expanded macros into the input AST fragment. let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); @@ -601,48 +641,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { (fragment, invocations) } - fn fully_configure(&mut self, item: Annotatable) -> Annotatable { - let mut cfg = StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features }; - // Since the item itself has already been configured by the InvocationCollector, - // we know that fold result vector will contain exactly one element - match item { - Annotatable::Item(item) => Annotatable::Item(cfg.flat_map_item(item).pop().unwrap()), - Annotatable::TraitItem(item) => { - Annotatable::TraitItem(cfg.flat_map_trait_item(item).pop().unwrap()) - } - Annotatable::ImplItem(item) => { - Annotatable::ImplItem(cfg.flat_map_impl_item(item).pop().unwrap()) - } - Annotatable::ForeignItem(item) => { - Annotatable::ForeignItem(cfg.flat_map_foreign_item(item).pop().unwrap()) - } - Annotatable::Stmt(stmt) => { - Annotatable::Stmt(stmt.map(|stmt| cfg.flat_map_stmt(stmt).pop().unwrap())) - } - Annotatable::Expr(mut expr) => Annotatable::Expr({ - cfg.visit_expr(&mut expr); - expr - }), - Annotatable::Arm(arm) => Annotatable::Arm(cfg.flat_map_arm(arm).pop().unwrap()), - Annotatable::Field(field) => { - Annotatable::Field(cfg.flat_map_field(field).pop().unwrap()) - } - Annotatable::FieldPat(fp) => { - Annotatable::FieldPat(cfg.flat_map_field_pattern(fp).pop().unwrap()) - } - Annotatable::GenericParam(param) => { - Annotatable::GenericParam(cfg.flat_map_generic_param(param).pop().unwrap()) - } - Annotatable::Param(param) => { - Annotatable::Param(cfg.flat_map_param(param).pop().unwrap()) - } - Annotatable::StructField(sf) => { - Annotatable::StructField(cfg.flat_map_struct_field(sf).pop().unwrap()) - } - Annotatable::Variant(v) => Annotatable::Variant(cfg.flat_map_variant(v).pop().unwrap()), - } - } - fn error_recursion_limit_reached(&mut self) { let expn_data = self.cx.current_expansion.id.expn_data(); let suggested_limit = self.cx.ecfg.recursion_limit * 2; @@ -735,20 +733,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Ok(meta) => { let items = match expander.expand(self.cx, span, &meta, item) { ExpandResult::Ready(items) => items, - ExpandResult::Retry(item, explanation) => { + ExpandResult::Retry(item) => { // Reassemble the original invocation for retrying. - return ExpandResult::Retry( - Invocation { - kind: InvocationKind::Attr { - attr, - item, - derives, - after_derive, - }, - ..invoc + return ExpandResult::Retry(Invocation { + kind: InvocationKind::Attr { + attr, + item, + derives, + after_derive, }, - explanation, - ); + ..invoc + }); } }; fragment_kind.expect_from_annotatables(items) @@ -772,24 +767,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> { InvocationKind::Derive { path, item } => match ext { SyntaxExtensionKind::Derive(expander) | SyntaxExtensionKind::LegacyDerive(expander) => { - if !item.derive_allowed() { - return ExpandResult::Ready(fragment_kind.dummy(span)); - } if let SyntaxExtensionKind::Derive(..) = ext { self.gate_proc_macro_input(&item); } let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path }; let items = match expander.expand(self.cx, span, &meta, item) { ExpandResult::Ready(items) => items, - ExpandResult::Retry(item, explanation) => { + ExpandResult::Retry(item) => { // Reassemble the original invocation for retrying. - return ExpandResult::Retry( - Invocation { - kind: InvocationKind::Derive { path: meta.path, item }, - ..invoc - }, - explanation, - ); + return ExpandResult::Retry(Invocation { + kind: InvocationKind::Derive { path: meta.path, item }, + ..invoc + }); } }; fragment_kind.expect_from_annotatables(items) @@ -806,7 +795,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::TraitItem(_) | Annotatable::ImplItem(_) | Annotatable::ForeignItem(_) => return, - Annotatable::Stmt(_) => "statements", + Annotatable::Stmt(stmt) => { + // Attributes are stable on item statements, + // but unstable on all other kinds of statements + if stmt.is_item() { + return; + } + "statements" + } Annotatable::Expr(_) => "expressions", Annotatable::Arm(..) | Annotatable::Field(..) @@ -1034,11 +1030,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr( &mut self, - attr: Option, - derives: Vec, + (attr, derives, after_derive): (Option, Vec, bool), item: Annotatable, kind: AstFragmentKind, - after_derive: bool, ) -> AstFragment { self.collect( kind, @@ -1054,7 +1048,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attrs: &mut Vec, after_derive: &mut bool, ) -> Option { - let attr = attrs + attrs .iter() .position(|a| { if a.has_name(sym::derive) { @@ -1062,29 +1056,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a) }) - .map(|i| attrs.remove(i)); - if let Some(attr) = &attr { - if !self.cx.ecfg.custom_inner_attributes() - && attr.style == ast::AttrStyle::Inner - && !attr.has_name(sym::test) - { - feature_err( - &self.cx.sess.parse_sess, - sym::custom_inner_attributes, - attr.span, - "non-builtin inner attributes are unstable", - ) - .emit(); - } - } - attr + .map(|i| attrs.remove(i)) } /// If `item` is an attr invocation, remove and return the macro attribute and derive traits. - fn classify_item( + fn take_first_attr( &mut self, item: &mut impl HasAttrs, - ) -> (Option, Vec, /* after_derive */ bool) { + ) -> Option<(Option, Vec, /* after_derive */ bool)> { let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false); item.visit_attrs(|mut attrs| { @@ -1092,23 +1071,23 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { traits = collect_derives(&mut self.cx, &mut attrs); }); - (attr, traits, after_derive) + if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None } } - /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough + /// Alternative to `take_first_attr()` that ignores `#[derive]` so invocations fallthrough /// to the unused-attributes lint (making it an error on statements and expressions /// is a breaking change) - fn classify_nonitem( + fn take_first_attr_no_derive( &mut self, nonitem: &mut impl HasAttrs, - ) -> (Option, /* after_derive */ bool) { + ) -> Option<(Option, Vec, /* after_derive */ bool)> { let (mut attr, mut after_derive) = (None, false); nonitem.visit_attrs(|mut attrs| { attr = self.find_attr_invoc(&mut attrs, &mut after_derive); }); - (attr, after_derive) + attr.map(|attr| (Some(attr), Vec::new(), after_derive)) } fn configure(&mut self, node: T) -> Option { @@ -1152,23 +1131,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { visit_clobber(expr.deref_mut(), |mut expr| { self.cfg.configure_expr_kind(&mut expr.kind); - // ignore derives so they remain unused - let (attr, after_derive) = self.classify_nonitem(&mut expr); - - if let Some(ref attr_value) = attr { + if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { // Collect the invoc regardless of whether or not attributes are permitted here // expansion will eat the attribute so it won't error later. - self.cfg.maybe_emit_expr_attr_err(attr_value); + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } // AstFragmentKind::Expr requires the macro to emit an expression. return self - .collect_attr( - attr, - vec![], - Annotatable::Expr(P(expr)), - AstFragmentKind::Expr, - after_derive, - ) + .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr) .make_expr() .into_inner(); } @@ -1186,16 +1158,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { let mut arm = configure!(self, arm); - let (attr, traits, after_derive) = self.classify_item(&mut arm); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut arm) { return self - .collect_attr( - attr, - traits, - Annotatable::Arm(arm), - AstFragmentKind::Arms, - after_derive, - ) + .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms) .make_arms(); } @@ -1205,16 +1170,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> { let mut field = configure!(self, field); - let (attr, traits, after_derive) = self.classify_item(&mut field); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut field) { return self - .collect_attr( - attr, - traits, - Annotatable::Field(field), - AstFragmentKind::Fields, - after_derive, - ) + .collect_attr(attr, Annotatable::Field(field), AstFragmentKind::Fields) .make_fields(); } @@ -1224,16 +1182,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> { let mut fp = configure!(self, fp); - let (attr, traits, after_derive) = self.classify_item(&mut fp); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut fp) { return self - .collect_attr( - attr, - traits, - Annotatable::FieldPat(fp), - AstFragmentKind::FieldPats, - after_derive, - ) + .collect_attr(attr, Annotatable::FieldPat(fp), AstFragmentKind::FieldPats) .make_field_patterns(); } @@ -1243,16 +1194,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { let mut p = configure!(self, p); - let (attr, traits, after_derive) = self.classify_item(&mut p); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut p) { return self - .collect_attr( - attr, - traits, - Annotatable::Param(p), - AstFragmentKind::Params, - after_derive, - ) + .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params) .make_params(); } @@ -1262,16 +1206,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> { let mut sf = configure!(self, sf); - let (attr, traits, after_derive) = self.classify_item(&mut sf); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut sf) { return self - .collect_attr( - attr, - traits, - Annotatable::StructField(sf), - AstFragmentKind::StructFields, - after_derive, - ) + .collect_attr(attr, Annotatable::StructField(sf), AstFragmentKind::StructFields) .make_struct_fields(); } @@ -1281,16 +1218,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { let mut variant = configure!(self, variant); - let (attr, traits, after_derive) = self.classify_item(&mut variant); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut variant) { return self - .collect_attr( - attr, - traits, - Annotatable::Variant(variant), - AstFragmentKind::Variants, - after_derive, - ) + .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants) .make_variants(); } @@ -1302,20 +1232,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { expr.filter_map(|mut expr| { self.cfg.configure_expr_kind(&mut expr.kind); - // Ignore derives so they remain unused. - let (attr, after_derive) = self.classify_nonitem(&mut expr); - - if let Some(ref attr_value) = attr { - self.cfg.maybe_emit_expr_attr_err(attr_value); + if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } return self - .collect_attr( - attr, - vec![], - Annotatable::Expr(P(expr)), - AstFragmentKind::OptExpr, - after_derive, - ) + .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr) .make_opt_expr() .map(|expr| expr.into_inner()); } @@ -1354,31 +1277,23 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // we'll expand attributes on expressions separately if !stmt.is_expr() { - let (attr, derives, after_derive) = if stmt.is_item() { - // FIXME: Handle custom attributes on statements (#15701) - (None, vec![], false) + let attr = if stmt.is_item() { + self.take_first_attr(&mut stmt) } else { - // ignore derives on non-item statements so it falls through - // to the unused-attributes lint - let (attr, after_derive) = self.classify_nonitem(&mut stmt); - (attr, vec![], after_derive) + // Ignore derives on non-item statements for backwards compatibility. + // This will result in a unused attribute warning + self.take_first_attr_no_derive(&mut stmt) }; - if attr.is_some() || !derives.is_empty() { + if let Some(attr) = attr { return self - .collect_attr( - attr, - derives, - Annotatable::Stmt(P(stmt)), - AstFragmentKind::Stmts, - after_derive, - ) + .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts) .make_stmts(); } } if let StmtKind::MacCall(mac) = stmt.kind { - let MacCallStmt { mac, style, attrs } = mac.into_inner(); + let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner(); self.check_attributes(&attrs); let mut placeholder = self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts(); @@ -1395,10 +1310,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } // The placeholder expander gives ids to statements, so we avoid folding the id here. - let ast::Stmt { id, kind, span, tokens } = stmt; + let ast::Stmt { id, kind, span } = stmt; noop_flat_map_stmt_kind(kind, self) .into_iter() - .map(|kind| ast::Stmt { id, kind, span, tokens: tokens.clone() }) + .map(|kind| ast::Stmt { id, kind, span }) .collect() } @@ -1412,16 +1327,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { let mut item = configure!(self, item); - let (attr, traits, after_derive) = self.classify_item(&mut item); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut item) { return self - .collect_attr( - attr, - traits, - Annotatable::Item(item), - AstFragmentKind::Items, - after_derive, - ) + .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items) .make_items(); } @@ -1515,16 +1423,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { let mut item = configure!(self, item); - let (attr, traits, after_derive) = self.classify_item(&mut item); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut item) { return self - .collect_attr( - attr, - traits, - Annotatable::TraitItem(item), - AstFragmentKind::TraitItems, - after_derive, - ) + .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems) .make_trait_items(); } @@ -1545,16 +1446,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { let mut item = configure!(self, item); - let (attr, traits, after_derive) = self.classify_item(&mut item); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut item) { return self - .collect_attr( - attr, - traits, - Annotatable::ImplItem(item), - AstFragmentKind::ImplItems, - after_derive, - ) + .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems) .make_impl_items(); } @@ -1595,16 +1489,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { &mut self, mut foreign_item: P, ) -> SmallVec<[P; 1]> { - let (attr, traits, after_derive) = self.classify_item(&mut foreign_item); - - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut foreign_item) { return self .collect_attr( attr, - traits, Annotatable::ForeignItem(foreign_item), AstFragmentKind::ForeignItems, - after_derive, ) .make_foreign_items(); } @@ -1639,15 +1529,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { ) -> SmallVec<[ast::GenericParam; 1]> { let mut param = configure!(self, param); - let (attr, traits, after_derive) = self.classify_item(&mut param); - if attr.is_some() || !traits.is_empty() { + if let Some(attr) = self.take_first_attr(&mut param) { return self .collect_attr( attr, - traits, Annotatable::GenericParam(param), AstFragmentKind::GenericParams, - after_derive, ) .make_generic_params(); } @@ -1720,23 +1607,22 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { items.push(ast::NestedMetaItem::MetaItem(item)); } Err(e) => { - let lit = - it.meta_item().and_then(|item| item.name_value_literal()).unwrap(); + let lit_span = it.name_value_literal_span().unwrap(); if e.kind() == ErrorKind::InvalidData { self.cx .struct_span_err( - lit.span, + lit_span, &format!("{} wasn't a utf-8 file", filename.display()), ) - .span_label(lit.span, "contains invalid utf-8") + .span_label(lit_span, "contains invalid utf-8") .emit(); } else { let mut err = self.cx.struct_span_err( - lit.span, + lit_span, &format!("couldn't read {}: {}", filename.display(), e), ); - err.span_label(lit.span, "couldn't read file"); + err.span_label(lit_span, "couldn't read file"); err.emit(); } @@ -1830,7 +1716,4 @@ impl<'feat> ExpansionConfig<'feat> { fn proc_macro_hygiene(&self) -> bool { self.features.map_or(false, |features| features.proc_macro_hygiene) } - fn custom_inner_attributes(&self) -> bool { - self.features.map_or(false, |features| features.custom_inner_attributes) - } } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 47247294f5..3b722c04cb 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -36,16 +36,13 @@ crate mod mbe; mod tests; #[cfg(test)] mod parse { - #[cfg(test)] mod tests; } #[cfg(test)] mod tokenstream { - #[cfg(test)] mod tests; } #[cfg(test)] mod mut_visit { - #[cfg(test)] mod tests; } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index d2fe7fe10a..0c44f5fe9e 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -1,4 +1,4 @@ -//! This is an NFA-based parser, which calls out to the main rust parser for named non-terminals +//! This is an NFA-based parser, which calls out to the main Rust parser for named non-terminals //! (which it commits to fully when it hits one in a grammar). There's a set of current NFA threads //! and a set of next ones. Instead of NTs, we have a special case for Kleene star. The big-O, in //! pathological cases, is worse than traditional use of NFA or Earley parsing, but it's an easier @@ -77,9 +77,9 @@ use TokenTreeOrTokenTreeSlice::*; use crate::mbe::{self, TokenTree}; use rustc_ast::token::{self, DocComment, Nonterminal, Token}; -use rustc_parse::parser::Parser; +use rustc_parse::parser::{OrPatNonterminalMode, Parser}; use rustc_session::parse::ParseSess; -use rustc_span::symbol::MacroRulesNormalizedIdent; +use rustc_span::{edition::Edition, symbol::MacroRulesNormalizedIdent}; use smallvec::{smallvec, SmallVec}; @@ -419,6 +419,18 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { } } +/// In edition 2015/18, `:pat` can only match `pat` because otherwise, we have +/// breakage. As of edition 2021, `:pat` matches `top_pat`. +/// +/// See for more info. +fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode { + match edition { + Edition::Edition2015 | Edition::Edition2018 => OrPatNonterminalMode::NoTopAlt, + // FIXME(mark-i-m): uncomment this when edition 2021 machinery is added. + // Edition::Edition2021 => OrPatNonterminalMode::TopPat, + } +} + /// Process the matcher positions of `cur_items` until it is empty. In the process, this will /// produce more items in `next_items`, `eof_items`, and `bb_items`. /// @@ -427,7 +439,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// /// # Parameters /// -/// - `sess`: the parsing session into which errors are emitted. /// - `cur_items`: the set of current items to be processed. This should be empty by the end of a /// successful execution of this function. /// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in @@ -435,8 +446,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// - `eof_items`: the set of items that would be valid if this was the EOF. /// - `bb_items`: the set of items that are waiting for the black-box parser. /// - `token`: the current token of the parser. -/// - `span`: the `Span` in the source code corresponding to the token trees we are trying to match -/// against the matcher positions in `cur_items`. /// /// # Returns /// @@ -569,10 +578,14 @@ fn inner_parse_loop<'root, 'tt>( // We need to match a metavar with a valid ident... call out to the black-box // parser by adding an item to `bb_items`. - TokenTree::MetaVarDecl(_, _, Some(kind)) => { - // Built-in nonterminals never start with these tokens, - // so we can eliminate them from consideration. - if Parser::nonterminal_may_begin_with(kind, token) { + TokenTree::MetaVarDecl(span, _, Some(kind)) => { + // Built-in nonterminals never start with these tokens, so we can eliminate + // them from consideration. + // + // We use the span of the metavariable declaration to determine any + // edition-specific matching behavior for non-terminals. + if Parser::nonterminal_may_begin_with(kind, token, or_pat_mode(span.edition())) + { bb_items.push(item); } } @@ -734,7 +747,10 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na let mut item = bb_items.pop().unwrap(); if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) { let match_cur = item.match_cur; - let nt = match parser.to_mut().parse_nonterminal(kind) { + // We use the span of the metavariable declaration to determine any + // edition-specific matching behavior for non-terminals. + let nt = match parser.to_mut().parse_nonterminal(kind, or_pat_mode(span.edition())) + { Err(mut err) => { err.span_label( span, diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index d928fb692d..89d375b257 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -1174,7 +1174,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind), mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name), _ => panic!( - "unexpected mbe::TokenTree::{{Sequence or Delimited}} \ + "{}", + "unexpected mbe::TokenTree::{Sequence or Delimited} \ in follow set checker" ), } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index f0e5826f40..ce19e813bb 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -104,8 +104,9 @@ pub fn placeholder( mac: mac_placeholder(), style: ast::MacStmtStyle::Braces, attrs: ast::AttrVec::new(), + tokens: None, }); - ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac), tokens: None } + ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) } }]), AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm { attrs: Default::default(), @@ -331,12 +332,8 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { // FIXME: We will need to preserve the original semicolon token and // span as part of #15701 - let empty_stmt = ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Empty, - span: DUMMY_SP, - tokens: None, - }; + let empty_stmt = + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Empty, span: DUMMY_SP }; if let Some(stmt) = stmts.pop() { if stmt.has_trailing_semicolon() { diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 4c95f19b96..36707a1ae2 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -1,6 +1,7 @@ use crate::base::{self, *}; use crate::proc_macro_server; +use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::{self as ast, *}; @@ -74,39 +75,22 @@ impl MultiItemModifier for ProcMacroDerive { _meta_item: &ast::MetaItem, item: Annotatable, ) -> ExpandResult, Annotatable> { + // We need special handling for statement items + // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) + let mut is_stmt = false; let item = match item { - Annotatable::Arm(..) - | Annotatable::Field(..) - | Annotatable::FieldPat(..) - | Annotatable::GenericParam(..) - | Annotatable::Param(..) - | Annotatable::StructField(..) - | Annotatable::Variant(..) => panic!("unexpected annotatable"), - Annotatable::Item(item) => item, - Annotatable::ImplItem(_) - | Annotatable::TraitItem(_) - | Annotatable::ForeignItem(_) - | Annotatable::Stmt(_) - | Annotatable::Expr(_) => { - ecx.span_err( - span, - "proc-macro derives may only be applied to a struct, enum, or union", - ); - return ExpandResult::Ready(Vec::new()); + Annotatable::Item(item) => token::NtItem(item), + Annotatable::Stmt(stmt) => { + is_stmt = true; + assert!(stmt.is_item()); + + // A proc macro can't observe the fact that we're passing + // them an `NtStmt` - it can only see the underlying tokens + // of the wrapped item + token::NtStmt(stmt.into_inner()) } + _ => unreachable!(), }; - match item.kind { - ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..) => {} - _ => { - ecx.span_err( - span, - "proc-macro derives may only be applied to a struct, enum, or union", - ); - return ExpandResult::Ready(Vec::new()); - } - } - - let item = token::NtItem(item); let input = if item.pretty_printing_compatibility_hack() { TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into() } else { @@ -135,7 +119,13 @@ impl MultiItemModifier for ProcMacroDerive { loop { match parser.parse_item() { Ok(None) => break, - Ok(Some(item)) => items.push(Annotatable::Item(item)), + Ok(Some(item)) => { + if is_stmt { + items.push(Annotatable::Stmt(P(ecx.stmt_item(span, item)))); + } else { + items.push(Annotatable::Item(item)); + } + } Err(mut err) => { err.emit(); break; diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 0df67b63eb..845e03150d 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -149,9 +149,6 @@ declare_features! ( /// Allows using the `#[linkage = ".."]` attribute. (active, linkage, "1.0.0", Some(29603), None), - /// Allows features specific to OIBIT (auto traits). - (active, optin_builtin_traits, "1.0.0", Some(13231), None), - /// Allows using `box` in patterns (RFC 469). (active, box_patterns, "1.0.0", Some(29641), None), @@ -215,6 +212,10 @@ declare_features! ( /// purpose as `#[allow_internal_unstable]`. (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), + /// Allows features specific to auto traits. + /// Renamed from `optin_builtin_traits`. + (active, auto_traits, "1.50.0", Some(13231), None), + // no-tracking-issue-end // ------------------------------------------------------------------------- @@ -616,6 +617,12 @@ declare_features! ( /// Enables `#[cfg(panic = "...")]` config key. (active, cfg_panic, "1.49.0", Some(77443), None), + /// Allows capturing disjoint fields in a closure/generator (RFC 2229). + (active, capture_disjoint_fields, "1.49.0", Some(53488), None), + + /// Allows arbitrary expressions in key-value attributes at parse time. + (active, extended_key_value_attributes, "1.50.0", Some(78835), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -639,6 +646,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::inline_const, sym::repr128, sym::unsized_locals, + sym::capture_disjoint_fields, ]; /// Some features are not allowed to be used together at the same time, if diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5c5cf609ac..fa8edba629 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -547,6 +547,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), + rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)), rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 68ac2841fe..2a7c2a02fb 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -18,6 +18,9 @@ mod active; mod builtin_attrs; mod removed; +#[cfg(test)] +mod tests; + use rustc_span::{edition::Edition, symbol::Symbol, Span}; use std::fmt; use std::num::NonZeroU32; @@ -59,7 +62,7 @@ pub enum Stability { Deprecated(&'static str, Option<&'static str>), } -#[derive(Clone, Copy, Hash)] +#[derive(Clone, Copy, Debug, Hash)] pub enum UnstableFeatures { /// Hard errors for unstable features are active, as on beta/stable channels. Disallow, @@ -73,11 +76,20 @@ pub enum UnstableFeatures { } impl UnstableFeatures { - pub fn from_environment() -> UnstableFeatures { + /// This takes into account `RUSTC_BOOTSTRAP`. + /// + /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly features. + /// Otherwise, only `RUSTC_BOOTSTRAP=1` will work. + pub fn from_environment(krate: Option<&str>) -> Self { // `true` if this is a feature-staged build, i.e., on the beta or stable channel. let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // Returns whether `krate` should be counted as unstable + let is_unstable_crate = |var: &str| { + krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name)) + }; // `true` if we should enable unstable features for bootstrapping. - let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok(); + let bootstrap = std::env::var("RUSTC_BOOTSTRAP") + .map_or(false, |var| var == "1" || is_unstable_crate(&var)); match (disable_unstable_features, bootstrap) { (_, true) => UnstableFeatures::Cheat, (true, _) => UnstableFeatures::Disallow, diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index a480ddc7f3..07bd1602cd 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -71,6 +71,10 @@ declare_features! ( /// Allows using custom attributes (RFC 572). (removed, custom_attribute, "1.0.0", Some(29642), None, Some("removed in favor of `#![register_tool]` and `#![register_attr]`")), + /// Allows features specific to OIBIT (now called auto traits). + /// Renamed to `auto_traits`. + (removed, optin_builtin_traits, "1.0.0", Some(13231), None, + Some("renamed to `auto_traits`")), (removed, pushpop_unsafe, "1.2.0", None, None, None), (removed, needs_allocator, "1.4.0", Some(27389), None, Some("subsumed by `#![feature(allocator_internals)]`")), @@ -113,7 +117,6 @@ declare_features! ( Some("removed in favor of `#![feature(marker_trait_attr)]`")), /// Allows `#[no_debug]`. (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")), - /// Allows comparing raw pointers during const eval. (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None, Some("cannot be allowed in const eval in any meaningful way")), diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs new file mode 100644 index 0000000000..50433e44b1 --- /dev/null +++ b/compiler/rustc_feature/src/tests.rs @@ -0,0 +1,23 @@ +use super::UnstableFeatures; + +#[test] +fn rustc_bootstrap_parsing() { + let is_bootstrap = |env, krate| { + std::env::set_var("RUSTC_BOOTSTRAP", env); + matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat) + }; + assert!(is_bootstrap("1", None)); + assert!(is_bootstrap("1", Some("x"))); + // RUSTC_BOOTSTRAP allows specifying a specific crate + assert!(is_bootstrap("x", Some("x"))); + // RUSTC_BOOTSTRAP allows multiple comma-delimited crates + assert!(is_bootstrap("x,y,z", Some("x"))); + assert!(is_bootstrap("x,y,z", Some("y"))); + // Crate that aren't specified do not get unstable features + assert!(!is_bootstrap("x", Some("a"))); + assert!(!is_bootstrap("x,y,z", Some("a"))); + assert!(!is_bootstrap("x,y,z", None)); + + // this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP + assert!(!is_bootstrap("0", None)); +} diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index 85ab7906d2..c7dc66b70f 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -14,7 +14,7 @@ macro_rules! arena_types { // HIR types [few] hir_krate: rustc_hir::Crate<$tcx>, [] arm: rustc_hir::Arm<$tcx>, - [] asm_operand: rustc_hir::InlineAsmOperand<$tcx>, + [] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span), [] asm_template: rustc_ast::InlineAsmTemplatePiece, [] attribute: rustc_ast::Attribute, [] block: rustc_hir::Block<$tcx>, @@ -29,6 +29,7 @@ macro_rules! arena_types { [] field_pat: rustc_hir::FieldPat<$tcx>, [] fn_decl: rustc_hir::FnDecl<$tcx>, [] foreign_item: rustc_hir::ForeignItem<$tcx>, + [few] foreign_item_ref: rustc_hir::ForeignItemRef<$tcx>, [] impl_item_ref: rustc_hir::ImplItemRef<$tcx>, [few] inline_asm: rustc_hir::InlineAsm<$tcx>, [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 298cfcc254..4ede9d67b7 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -39,6 +39,9 @@ pub enum NonMacroAttrKind { Tool, /// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`). DeriveHelper, + /// Single-segment custom attribute registered by a derive macro + /// but used before that derive macro was expanded (deprecated). + DeriveHelperCompat, /// Single-segment custom attribute registered with `#[register_attr]`. Registered, } @@ -370,7 +373,9 @@ impl NonMacroAttrKind { match self { NonMacroAttrKind::Builtin => "built-in attribute", NonMacroAttrKind::Tool => "tool attribute", - NonMacroAttrKind::DeriveHelper => "derive helper attribute", + NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => { + "derive helper attribute" + } NonMacroAttrKind::Registered => "explicitly registered attribute", } } @@ -385,7 +390,9 @@ impl NonMacroAttrKind { /// Users of some attributes cannot mark them as used, so they are considered always used. pub fn is_used(self) -> bool { match self { - NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper => true, + NonMacroAttrKind::Tool + | NonMacroAttrKind::DeriveHelper + | NonMacroAttrKind::DeriveHelperCompat => true, NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false, } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3c28b48795..2abebbd030 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -282,6 +282,14 @@ impl GenericArg<'_> { GenericArg::Const(_) => "constant", } } + + pub fn short_descr(&self) -> &'static str { + match self { + GenericArg::Lifetime(_) => "lifetime", + GenericArg::Type(_) => "type", + GenericArg::Const(_) => "const", + } + } } #[derive(Debug, HashStable_Generic)] @@ -571,6 +579,7 @@ pub struct ModuleItems { pub items: BTreeSet, pub trait_items: BTreeSet, pub impl_items: BTreeSet, + pub foreign_items: BTreeSet, } /// A type representing only the top-level module. @@ -604,6 +613,7 @@ pub struct Crate<'hir> { pub trait_items: BTreeMap>, pub impl_items: BTreeMap>, + pub foreign_items: BTreeMap>, pub bodies: BTreeMap>, pub trait_impls: BTreeMap>, @@ -636,6 +646,10 @@ impl Crate<'hir> { &self.impl_items[&id] } + pub fn foreign_item(&self, id: ForeignItemId) -> &ForeignItem<'hir> { + &self.foreign_items[&id] + } + pub fn body(&self, id: BodyId) -> &Body<'hir> { &self.bodies[&id] } @@ -665,6 +679,10 @@ impl Crate<'_> { for impl_item in self.impl_items.values() { visitor.visit_impl_item(impl_item); } + + for foreign_item in self.foreign_items.values() { + visitor.visit_foreign_item(foreign_item); + } } /// A parallel version of `visit_all_item_likes`. @@ -687,6 +705,11 @@ impl Crate<'_> { par_for_each_in(&self.impl_items, |(_, impl_item)| { visitor.visit_impl_item(impl_item); }); + }, + { + par_for_each_in(&self.foreign_items, |(_, foreign_item)| { + visitor.visit_foreign_item(foreign_item); + }); } ); } @@ -1137,6 +1160,7 @@ pub struct Arm<'hir> { #[derive(Debug, HashStable_Generic)] pub enum Guard<'hir> { If(&'hir Expr<'hir>), + IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>), } #[derive(Debug, HashStable_Generic)] @@ -1698,6 +1722,8 @@ pub enum MatchSource { IfDesugar { contains_else_clause: bool }, /// An `if let _ = _ { .. }` (optionally with `else { .. }`). IfLetDesugar { contains_else_clause: bool }, + /// An `if let _ = _ => { .. }` match guard. + IfLetGuardDesugar, /// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`). WhileDesugar, /// A `while let _ = _ { .. }` (which was desugared to a @@ -1716,7 +1742,7 @@ impl MatchSource { use MatchSource::*; match self { Normal => "match", - IfDesugar { .. } | IfLetDesugar { .. } => "if", + IfDesugar { .. } | IfLetDesugar { .. } | IfLetGuardDesugar => "if", WhileDesugar | WhileLetDesugar => "while", ForLoopDesugar => "for", TryDesugar => "?", @@ -1832,7 +1858,7 @@ pub struct FnSig<'hir> { } // The bodies for items are stored "out of line", in a separate -// hashmap in the `Crate`. Here we just record the node-id of the item +// hashmap in the `Crate`. Here we just record the hir-id of the item // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)] pub struct TraitItemId { @@ -1876,7 +1902,7 @@ pub enum TraitItemKind<'hir> { } // The bodies for items are stored "out of line", in a separate -// hashmap in the `Crate`. Here we just record the node-id of the item +// hashmap in the `Crate`. Here we just record the hir-id of the item // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)] pub struct ImplItemId { @@ -2120,7 +2146,7 @@ impl<'hir> InlineAsmOperand<'hir> { #[derive(Debug, HashStable_Generic)] pub struct InlineAsm<'hir> { pub template: &'hir [InlineAsmTemplatePiece], - pub operands: &'hir [InlineAsmOperand<'hir>], + pub operands: &'hir [(InlineAsmOperand<'hir>, Span)], pub options: InlineAsmOptions, pub line_spans: &'hir [Span], } @@ -2261,12 +2287,6 @@ pub struct Mod<'hir> { pub item_ids: &'hir [ItemId], } -#[derive(Debug, HashStable_Generic)] -pub struct ForeignMod<'hir> { - pub abi: Abi, - pub items: &'hir [ForeignItem<'hir>], -} - #[derive(Encodable, Debug, HashStable_Generic)] pub struct GlobalAsm { pub asm: Symbol, @@ -2384,7 +2404,7 @@ impl StructField<'_> { // Still necessary in couple of places pub fn is_positional(&self) -> bool { let first = self.ident.as_str().as_bytes()[0]; - first >= b'0' && first <= b'9' + (b'0'..=b'9').contains(&first) } } @@ -2424,7 +2444,7 @@ impl VariantData<'hir> { } // The bodies for items are stored "out of line", in a separate -// hashmap in the `Crate`. Here we just record the node-id of the item +// hashmap in the `Crate`. Here we just record the hir-id of the item // so it can fetched later. #[derive(Copy, Clone, Encodable, Debug)] pub struct ItemId { @@ -2513,7 +2533,7 @@ pub enum ItemKind<'hir> { /// A module. Mod(Mod<'hir>), /// An external module, e.g. `extern { .. }`. - ForeignMod(ForeignMod<'hir>), + ForeignMod { abi: Abi, items: &'hir [ForeignItemRef<'hir>] }, /// Module-level inline assembly (from `global_asm!`). GlobalAsm(&'hir GlobalAsm), /// A type alias, e.g., `type Foo = Bar`. @@ -2606,6 +2626,29 @@ pub enum AssocItemKind { Type, } +// The bodies for items are stored "out of line", in a separate +// hashmap in the `Crate`. Here we just record the hir-id of the item +// so it can fetched later. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)] +pub struct ForeignItemId { + pub hir_id: HirId, +} + +/// A reference from a foreign block to one of its items. This +/// contains the item's ID, naturally, but also the item's name and +/// some other high-level details (like whether it is an associated +/// type or method, and whether it is public). This allows other +/// passes to find the impl they want without loading the ID (which +/// means fewer edges in the incremental compilation graph). +#[derive(Debug, HashStable_Generic)] +pub struct ForeignItemRef<'hir> { + pub id: ForeignItemId, + #[stable_hasher(project(name))] + pub ident: Ident, + pub span: Span, + pub vis: Visibility<'hir>, +} + #[derive(Debug, HashStable_Generic)] pub struct ForeignItem<'hir> { #[stable_hasher(project(name))] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 35615af0fc..03c8b17388 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -64,6 +64,10 @@ where fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) { self.visitor.visit_impl_item(impl_item); } + + fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) { + self.visitor.visit_foreign_item(foreign_item); + } } pub trait IntoVisitor<'hir> { @@ -88,6 +92,10 @@ where fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>) { self.0.into_visitor().visit_impl_item(impl_item); } + + fn visit_foreign_item(&self, foreign_item: &'hir ForeignItem<'hir>) { + self.0.into_visitor().visit_foreign_item(foreign_item); + } } #[derive(Copy, Clone)] @@ -128,6 +136,7 @@ pub trait Map<'hir> { fn item(&self, id: HirId) -> &'hir Item<'hir>; fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>; fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>; + fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>; } /// An erased version of `Map<'hir>`, using dynamic dispatch. @@ -150,6 +159,9 @@ impl<'hir> Map<'hir> for ErasedMap<'hir> { fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { self.0.impl_item(id) } + fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { + self.0.foreign_item(id) + } } /// Specifies what nested things a visitor wants to visit. The most @@ -277,6 +289,14 @@ pub trait Visitor<'v>: Sized { walk_list!(self, visit_impl_item, opt_item); } + /// Like `visit_nested_item()`, but for foreign items. See + /// `visit_nested_item()` for advice on when to override this + /// method. + fn visit_nested_foreign_item(&mut self, id: ForeignItemId) { + let opt_item = self.nested_visit_map().inter().map(|map| map.foreign_item(id)); + walk_list!(self, visit_foreign_item, opt_item); + } + /// Invoked to visit the body of a function, method or closure. Like /// visit_nested_item, does nothing by default unless you override /// `nested_visit_map` to return other than `None`, in which case it will walk @@ -378,6 +398,9 @@ pub trait Visitor<'v>: Sized { fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) { walk_impl_item(self, ii) } + fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef<'v>) { + walk_foreign_item_ref(self, ii) + } fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef<'v>) { walk_impl_item_ref(self, ii) } @@ -566,9 +589,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { // `visit_mod()` takes care of visiting the `Item`'s `HirId`. visitor.visit_mod(module, item.span, item.hir_id) } - ItemKind::ForeignMod(ref foreign_module) => { + ItemKind::ForeignMod { abi: _, items } => { visitor.visit_id(item.hir_id); - walk_list!(visitor, visit_foreign_item, foreign_module.items); + walk_list!(visitor, visit_foreign_item_ref, items); } ItemKind::GlobalAsm(_) => { visitor.visit_id(item.hir_id); @@ -1012,6 +1035,17 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } } +pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>( + visitor: &mut V, + foreign_item_ref: &'v ForeignItemRef<'v>, +) { + // N.B., deliberately force a compilation error if/when new fields are added. + let ForeignItemRef { id, ident, span: _, ref vis } = *foreign_item_ref; + visitor.visit_nested_foreign_item(id); + visitor.visit_ident(ident); + visitor.visit_vis(vis); +} + pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef<'v>) { // N.B., deliberately force a compilation error if/when new fields are added. let ImplItemRef { id, ident, ref kind, span: _, ref vis, ref defaultness } = *impl_item_ref; @@ -1157,7 +1191,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_expr, optional_expression); } ExprKind::InlineAsm(ref asm) => { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } @@ -1194,6 +1228,10 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { if let Some(ref g) = arm.guard { match g { Guard::If(ref e) => visitor.visit_expr(e), + Guard::IfLet(ref pat, ref e) => { + visitor.visit_pat(pat); + visitor.visit_expr(e); + } } } visitor.visit_expr(&arm.body); diff --git a/compiler/rustc_hir/src/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs index 369cd49621..0db562f91a 100644 --- a/compiler/rustc_hir/src/itemlikevisit.rs +++ b/compiler/rustc_hir/src/itemlikevisit.rs @@ -1,4 +1,4 @@ -use super::{ImplItem, Item, TraitItem}; +use super::{ForeignItem, ImplItem, Item, TraitItem}; /// The "item-like visitor" defines only the top-level methods /// that can be invoked by `Crate::visit_all_item_likes()`. Whether @@ -47,6 +47,7 @@ pub trait ItemLikeVisitor<'hir> { fn visit_item(&mut self, item: &'hir Item<'hir>); fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>); fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>); + fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>); } /// A parallel variant of `ItemLikeVisitor`. @@ -54,4 +55,5 @@ pub trait ParItemLikeVisitor<'hir> { fn visit_item(&self, item: &'hir Item<'hir>); fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>); fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>); + fn visit_foreign_item(&self, foreign_item: &'hir ForeignItem<'hir>); } diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 1d3f44a089..439fb88039 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,8 +1,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use crate::hir::{ - BodyId, Expr, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId, Ty, - VisibilityKind, + BodyId, Expr, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId, + Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::{DefPathHash, LocalDefId}; @@ -52,6 +52,15 @@ impl ToStableHashKey for ImplItemId { } } +impl ToStableHashKey for ForeignItemId { + type KeyType = (DefPathHash, ItemLocalId); + + #[inline] + fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) { + self.hir_id.to_stable_hash_key(hcx) + } +} + impl HashStable for HirId { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { hcx.hash_hir_id(*self, hasher) @@ -77,6 +86,12 @@ impl HashStable for ItemId { } } +impl HashStable for ForeignItemId { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + hcx.hash_reference_to_item(self.hir_id, hasher) + } +} + impl HashStable for ImplItemId { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { hcx.hash_reference_to_item(self.hir_id, hasher) diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index fd6a312ef3..2774cc9c08 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -9,6 +9,13 @@ use crate::{Item, ItemKind, TraitItem, TraitItemKind}; use std::fmt::{self, Display}; +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum GenericParamKind { + Type, + Lifetime, + Const, +} + #[derive(Copy, Clone, PartialEq, Debug)] pub enum MethodKind { Trait { body: bool }, @@ -43,6 +50,7 @@ pub enum Target { ForeignFn, ForeignStatic, ForeignTy, + GenericParam(GenericParamKind), } impl Display for Target { @@ -77,6 +85,11 @@ impl Display for Target { Target::ForeignFn => "foreign function", Target::ForeignStatic => "foreign static item", Target::ForeignTy => "foreign type", + Target::GenericParam(kind) => match kind { + GenericParamKind::Type => "type parameter", + GenericParamKind::Lifetime => "lifetime parameter", + GenericParamKind::Const => "const parameter", + }, } ) } @@ -91,7 +104,7 @@ impl Target { ItemKind::Const(..) => Target::Const, ItemKind::Fn(..) => Target::Fn, ItemKind::Mod(..) => Target::Mod, - ItemKind::ForeignMod(..) => Target::ForeignMod, + ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm(..) => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, ItemKind::OpaqueTy(..) => Target::OpaqueTy, @@ -124,4 +137,14 @@ impl Target { hir::ForeignItemKind::Type => Target::ForeignTy, } } + + pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target { + match generic_param.kind { + hir::GenericParamKind::Type { .. } => Target::GenericParam(GenericParamKind::Type), + hir::GenericParamKind::Lifetime { .. } => { + Target::GenericParam(GenericParamKind::Lifetime) + } + hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const), + } + } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f7018ae62a..0b5eb1d826 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -36,6 +36,7 @@ pub enum Nested { Item(hir::ItemId), TraitItem(hir::TraitItemId), ImplItem(hir::ImplItemId), + ForeignItem(hir::ForeignItemId), Body(hir::BodyId), BodyParamPat(hir::BodyId, usize), } @@ -56,6 +57,7 @@ impl PpAnn for hir::Crate<'_> { Nested::Item(id) => state.print_item(self.item(id.id)), Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), + Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), } @@ -70,6 +72,7 @@ impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { Nested::Item(id) => state.print_item(self.item(id.id)), Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), + Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), } @@ -349,13 +352,6 @@ impl<'a> State<'a> { } } - pub fn print_foreign_mod(&mut self, nmod: &hir::ForeignMod<'_>, attrs: &[ast::Attribute]) { - self.print_inner_attributes(attrs); - for item in nmod.items { - self.print_foreign_item(item); - } - } - pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) { if !lifetime.is_elided() { self.print_lifetime(lifetime); @@ -644,11 +640,14 @@ impl<'a> State<'a> { self.print_mod(_mod, &item.attrs); self.bclose(item.span); } - hir::ItemKind::ForeignMod(ref nmod) => { + hir::ItemKind::ForeignMod { abi, items } => { self.head("extern"); - self.word_nbsp(nmod.abi.to_string()); + self.word_nbsp(abi.to_string()); self.bopen(); - self.print_foreign_mod(nmod, &item.attrs); + self.print_inner_attributes(item.attrs); + for item in items { + self.ann.nested(self, Nested::ForeignItem(item.id)); + } self.bclose(item.span); } hir::ItemKind::GlobalAsm(ref ga) => { @@ -1463,7 +1462,7 @@ impl<'a> State<'a> { let mut args = vec![]; args.push(AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&a.template))); - args.extend(a.operands.iter().map(|o| AsmArg::Operand(o))); + args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o))); if !a.options.is_empty() { args.push(AsmArg::Options(a.options)); } @@ -2003,6 +2002,15 @@ impl<'a> State<'a> { self.print_expr(&e); self.s.space(); } + hir::Guard::IfLet(pat, e) => { + self.word_nbsp("if"); + self.word_nbsp("let"); + self.print_pat(&pat); + self.s.space(); + self.word_space("="); + self.print_expr(&e); + self.s.space(); + } } } self.word_space("=>"); diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index d55813f4cc..e1c60050d9 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -280,7 +280,7 @@ impl DirtyCleanVisitor<'tcx> { HirItem::Mod(..) => ("ItemMod", LABELS_HIR_ONLY), // // An external module - HirItem::ForeignMod(..) => ("ItemForeignMod", LABELS_HIR_ONLY), + HirItem::ForeignMod { .. } => ("ItemForeignMod", LABELS_HIR_ONLY), // Module-level inline assembly (from global_asm!) HirItem::GlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY), @@ -460,6 +460,10 @@ impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> { fn visit_impl_item(&mut self, item: &hir::ImplItem<'_>) { self.check_item(item.hir_id, item.span); } + + fn visit_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { + self.check_item(item.hir_id, item.span); + } } /// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 048a81b81b..e185ee24d1 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -15,7 +15,6 @@ use std::io::{self, Read}; use std::path::Path; use rustc_serialize::opaque::Encoder; -use rustc_session::config::nightly_options; /// The first few bytes of files generated by incremental compilation. const FILE_MAGIC: &[u8] = b"RSIC"; @@ -28,12 +27,12 @@ const HEADER_FORMAT_VERSION: u16 = 0; /// the Git commit hash. const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); -pub fn write_file_header(stream: &mut Encoder) { +pub fn write_file_header(stream: &mut Encoder, nightly_build: bool) { stream.emit_raw_bytes(FILE_MAGIC); stream .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); - let rustc_version = rustc_version(); + let rustc_version = rustc_version(nightly_build); assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); stream.emit_raw_bytes(&[rustc_version.len() as u8]); stream.emit_raw_bytes(rustc_version.as_bytes()); @@ -51,6 +50,7 @@ pub fn write_file_header(stream: &mut Encoder) { pub fn read_file( report_incremental_info: bool, path: &Path, + nightly_build: bool, ) -> io::Result, usize)>> { if !path.exists() { return Ok(None); @@ -93,7 +93,7 @@ pub fn read_file( let mut buffer = vec![0; rustc_version_str_len]; file.read_exact(&mut buffer)?; - if buffer != rustc_version().as_bytes() { + if buffer != rustc_version(nightly_build).as_bytes() { report_format_mismatch(report_incremental_info, path, "Different compiler version"); return Ok(None); } @@ -115,8 +115,8 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: & } } -fn rustc_version() -> String { - if nightly_options::is_nightly_build() { +fn rustc_version(nightly_build: bool) -> String { + if nightly_build { if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") { return val.to_string_lossy().into_owned(); } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 966faa9639..35428dc8d8 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,6 +1,7 @@ //! Code to save/load the dep-graph from files. use rustc_data_structures::fx::FxHashMap; +use rustc_hir::definitions::Definitions; use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::query::OnDiskCache; use rustc_middle::ty::TyCtxt; @@ -53,8 +54,12 @@ impl LoadResult<(PreviousDepGraph, WorkProductMap)> { } } -fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec, usize)> { - match file_format::read_file(report_incremental_info, path) { +fn load_data( + report_incremental_info: bool, + path: &Path, + nightly_build: bool, +) -> LoadResult<(Vec, usize)> { + match file_format::read_file(report_incremental_info, path, nightly_build) { Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, Ok(None) => { // The file either didn't exist or was produced by an incompatible @@ -111,13 +116,14 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { let expected_hash = sess.opts.dep_tracking_hash(); let mut prev_work_products = FxHashMap::default(); + let nightly_build = sess.is_nightly_build(); // If we are only building with -Zquery-dep-graph but without an actual // incr. comp. session directory, we skip this. Otherwise we'd fail // when trying to load work products. if sess.incr_comp_session_dir_opt().is_some() { let work_products_path = work_products_path(sess); - let load_result = load_data(report_incremental_info, &work_products_path); + let load_result = load_data(report_incremental_info, &work_products_path, nightly_build); if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { // Decode the list of work_products @@ -163,7 +169,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { MaybeAsync::Async(std::thread::spawn(move || { let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); - match load_data(report_incremental_info, &path) { + match load_data(report_incremental_info, &path, nightly_build) { LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, LoadResult::Error { message } => LoadResult::Error { message }, LoadResult::Ok { data: (bytes, start_pos) } => { @@ -194,15 +200,29 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { })) } -pub fn load_query_result_cache(sess: &Session) -> OnDiskCache<'_> { +/// Attempts to load the query result cache from disk +/// +/// If we are not in incremental compilation mode, returns `None`. +/// Otherwise, tries to load the query result cache from disk, +/// creating an empty cache if it could not be loaded. +pub fn load_query_result_cache<'a>( + sess: &'a Session, + definitions: &Definitions, +) -> Option> { if sess.opts.incremental.is_none() { - return OnDiskCache::new_empty(sess.source_map()); + return None; } let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); - match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) { - LoadResult::Ok { data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos), - _ => OnDiskCache::new_empty(sess.source_map()), + match load_data( + sess.opts.debugging_opts.incremental_info, + &query_cache_path(sess), + sess.is_nightly_build(), + ) { + LoadResult::Ok { data: (bytes, start_pos) } => { + Some(OnDiskCache::new(sess, bytes, start_pos, definitions)) + } + _ => Some(OnDiskCache::new_empty(sess.source_map())), } } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 45cef479a4..102a77e8e7 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -119,7 +119,7 @@ where // generate the data in a memory buffer let mut encoder = Encoder::new(Vec::new()); - file_format::write_file_header(&mut encoder); + file_format::write_file_header(&mut encoder, sess.is_nightly_build()); encode(&mut encoder); // write the data out diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 8e00e54650..0b501da7cd 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -27,7 +27,6 @@ pub const WORD_BITS: usize = WORD_BYTES * 8; /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. /// -/// [`GrowableBitSet`]: struct.GrowableBitSet.html #[derive(Eq, PartialEq, Decodable, Encodable)] pub struct BitSet { domain_size: usize, diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 7ee881b063..eaef4c7b54 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,5 +1,4 @@ #![feature(allow_internal_unstable)] -#![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] #![feature(extend_one)] diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 871fc4fafe..9002d251f1 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -38,7 +38,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query pub fn canonicalize_query( &self, - value: &V, + value: V, query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'tcx, V> where @@ -80,7 +80,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// out the [chapter in the rustc dev guide][c]. /// /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result - pub fn canonicalize_response(&self, value: &V) -> Canonicalized<'tcx, V> + pub fn canonicalize_response(&self, value: V) -> Canonicalized<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -94,7 +94,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) } - pub fn canonicalize_user_type_annotation(&self, value: &V) -> Canonicalized<'tcx, V> + pub fn canonicalize_user_type_annotation(&self, value: V) -> Canonicalized<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -123,7 +123,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // and just use `canonicalize_query`. pub fn canonicalize_hr_query_hack( &self, - value: &V, + value: V, query_state: &mut OriginalQueryValues<'tcx>, ) -> Canonicalized<'tcx, V> where @@ -277,7 +277,7 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic { struct Canonicalizer<'cx, 'tcx> { infcx: Option<&'cx InferCtxt<'cx, 'tcx>>, tcx: TyCtxt<'tcx>, - variables: SmallVec<[CanonicalVarInfo; 8]>, + variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>, query_state: &'cx mut OriginalQueryValues<'tcx>, // Note that indices is only used once `var_values` is big enough to be // heap-allocated. @@ -293,7 +293,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { self.tcx } - fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder where T: TypeFoldable<'tcx>, { @@ -479,7 +479,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// The main `canonicalize` method, shared impl of /// `canonicalize_query` and `canonicalize_response`. fn canonicalize( - value: &V, + value: V, infcx: Option<&InferCtxt<'_, 'tcx>>, tcx: TyCtxt<'tcx>, canonicalize_region_mode: &dyn CanonicalizeRegionMode, @@ -505,7 +505,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { let canon_value = Canonical { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), - value: value.clone(), + value, }; return canon_value; } @@ -542,7 +542,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// or returns an existing variable if `kind` has already been /// seen. `kind` is expected to be an unbound variable (or /// potentially a free region). - fn canonical_var(&mut self, info: CanonicalVarInfo, kind: GenericArg<'tcx>) -> BoundVar { + fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>) -> BoundVar { let Canonicalizer { variables, query_state, indices, .. } = self; let var_values = &mut query_state.var_values; @@ -621,11 +621,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// representing the region `r`; return a region referencing it. fn canonical_var_for_region( &mut self, - info: CanonicalVarInfo, + info: CanonicalVarInfo<'tcx>, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); - let region = ty::ReLateBound(self.binder_index, ty::BoundRegion::BrAnon(var.as_u32())); + let br = ty::BoundRegion { kind: ty::BrAnon(var.as_u32()) }; + let region = ty::ReLateBound(self.binder_index, br); self.tcx().mk_region(region) } @@ -633,7 +634,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// if `ty_var` is bound to anything; if so, canonicalize /// *that*. Otherwise, create a new canonical variable for /// `ty_var`. - fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> { + fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.infcx.expect("encountered ty-var without infcx"); let bound_to = infcx.shallow_resolve(ty_var); if bound_to != ty_var { @@ -650,7 +651,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// `const_var`. fn canonicalize_const_var( &mut self, - info: CanonicalVarInfo, + info: CanonicalVarInfo<'tcx>, const_var: &'tcx ty::Const<'tcx>, ) -> &'tcx ty::Const<'tcx> { let infcx = self.infcx.expect("encountered const-var without infcx"); diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 2b8c46f1de..0c26639e9b 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -82,7 +82,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { fn instantiate_canonical_vars( &self, span: Span, - variables: &List, + variables: &List>, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> CanonicalVarValues<'tcx> { let var_values: IndexVec> = variables @@ -100,7 +100,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { fn instantiate_canonical_var( &self, span: Span, - cv_info: CanonicalVarInfo, + cv_info: CanonicalVarInfo<'tcx>, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> GenericArg<'tcx> { match cv_info.kind { @@ -154,7 +154,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { self.tcx .mk_const(ty::Const { val: ty::ConstKind::Placeholder(placeholder_mapped), - ty: self.tcx.ty_error(), // FIXME(const_generics) + ty: name.ty, }) .into() } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 93e1952189..71ce50f745 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -59,7 +59,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, { let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; - let canonical_result = self.canonicalize_response(&query_response); + let canonical_result = self.canonicalize_response(query_response); debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result); @@ -83,7 +83,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { where T: Debug + TypeFoldable<'tcx>, { - self.canonicalize_response(&QueryResponse { + self.canonicalize_response(QueryResponse { var_values: inference_vars, region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Proven, // Ambiguities are OK! @@ -176,7 +176,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { )); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } @@ -238,7 +238,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { - &v.var_values[BoundVar::new(index)] + v.var_values[BoundVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { ( @@ -296,7 +296,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // ...also include the other query region constraints from the query. output_query_region_constraints.outlives.extend( - query_response.value.region_constraints.outlives.iter().filter_map(|r_c| { + query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| { let r_c = substitute_value(self.tcx, &result_subst, r_c); // Screen out `'a: 'a` cases -- we skip the binder here but @@ -314,11 +314,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { .region_constraints .member_constraints .iter() - .map(|p_c| substitute_value(self.tcx, &result_subst, p_c)), + .map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())), ); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } @@ -502,7 +502,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // `query_response.var_values` after applying the substitution // `result_subst`. let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> { - query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) + query_response.substitute_projected(self.tcx, &result_subst, |v| v.var_values[index]) }; // Unify the original value for each variable with the value @@ -524,11 +524,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], result_subst: &'a CanonicalVarValues<'tcx>, ) -> impl Iterator> + 'a + Captures<'tcx> { - unsubstituted_region_constraints.iter().map(move |constraint| { - let ty::OutlivesPredicate(k1, r2) = - substitute_value(self.tcx, result_subst, constraint).skip_binder(); + unsubstituted_region_constraints.iter().map(move |&constraint| { + let predicate = substitute_value(self.tcx, result_subst, constraint); + let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder(); - let predicate = match k1.unpack() { + let atom = match k1.unpack() { GenericArgKind::Lifetime(r1) => { ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2)) } @@ -540,8 +540,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // encounter this branch. span_bug!(cause.span, "unexpected const outlives {:?}", constraint); } - } - .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); + }; + let predicate = + predicate.rebind(atom).potentially_quantified(self.tcx, ty::PredicateKind::ForAll); Obligation::new(cause.clone(), param_env, predicate) }) diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index 65791f6fc6..387f480814 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -28,7 +28,7 @@ pub(super) trait CanonicalExt<'tcx, V> { &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> &T, + projection_fn: impl FnOnce(&V) -> T, ) -> T where T: TypeFoldable<'tcx>; @@ -39,14 +39,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { where V: TypeFoldable<'tcx>, { - self.substitute_projected(tcx, var_values, |value| value) + self.substitute_projected(tcx, var_values, |value| value.clone()) } fn substitute_projected( &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> &T, + projection_fn: impl FnOnce(&V) -> T, ) -> T where T: TypeFoldable<'tcx>, @@ -60,16 +60,16 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { /// Substitute the values from `var_values` into `value`. `var_values` /// must be values for the set of canonical variables that appear in /// `value`. -pub(super) fn substitute_value<'a, 'tcx, T>( +pub(super) fn substitute_value<'tcx, T>( tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, - value: &'a T, + value: T, ) -> T where T: TypeFoldable<'tcx>, { if var_values.var_values.is_empty() { - value.clone() + value } else { let fld_r = |br: ty::BoundRegion| match var_values.var_values[br.assert_bound_var()].unpack() { @@ -87,6 +87,6 @@ where c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }; - tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c).0 + tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c) } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 6a1715ef81..e38eebe23b 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -543,6 +543,10 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { true } + fn visit_ct_substs(&self) -> bool { + true + } + fn binders( &mut self, a: ty::Binder, @@ -551,7 +555,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } fn relate_item_substs( @@ -716,7 +720,10 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); match var_value.val { - ConstVariableValue::Known { value: u } => self.relate(u, u), + ConstVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } ConstVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { Ok(c) @@ -815,6 +822,10 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { true } + fn visit_ct_substs(&self) -> bool { + true + } + fn relate_with_variance>( &mut self, _variance: ty::Variance, @@ -833,7 +844,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { @@ -870,6 +881,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), _ => relate::super_relate_tys(self, t, t), } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 524efd04cf..6b7edde9a6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -165,7 +165,9 @@ fn msg_span_from_early_bound_and_free_regions( } (format!("the lifetime `{}` as defined on", br.name), sp) } - ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => { + ty::ReFree(ty::FreeRegion { + bound_region: ty::BoundRegionKind::BrNamed(_, name), .. + }) => { let mut sp = sm.guess_head_span(tcx.hir().span(node)); if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) @@ -389,7 +391,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { member_region, span, } => { - let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); + let hidden_ty = self.resolve_vars_if_possible(hidden_ty); unexpected_hidden_region_diagnostic( self.tcx, span, @@ -496,7 +498,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List>, + _predicates: &'tcx ty::List>>, ) -> Result { Err(NonTrivialPath) } @@ -590,7 +592,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { match cause.code { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { - let ty = self.resolve_vars_if_possible(&root_ty); + let ty = self.resolve_vars_if_possible(root_ty); if ty.is_suggestable() { // don't show type `_` err.span_label(span, format!("this expression has type `{}`", ty)); @@ -661,7 +663,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } _ => { // `last_ty` can be `!`, `expected` will have better info when present. - let t = self.resolve_vars_if_possible(&match exp_found { + let t = self.resolve_vars_if_possible(match exp_found { Some(ty::error::ExpectedFound { expected, .. }) => expected, _ => last_ty, }); @@ -1498,7 +1500,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let Some((kind, def_id)) = TyCategory::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: @@ -1547,7 +1549,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")), _ => (false, Mismatch::Fixed("type")), }; - let vals = match self.values_str(&values) { + let vals = match self.values_str(values) { Some((expected, found)) => Some((expected, found)), None => { // Derived error. Cancel the emitter. @@ -1622,7 +1624,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } (TypeError::ObjectUnsafeCoercion(_), _) => { - diag.note_unsuccessfull_coercion(found, expected); + diag.note_unsuccessful_coercion(found, expected); } (_, _) => { debug!( @@ -1893,32 +1895,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn values_str( &self, - values: &ValuePairs<'tcx>, + values: ValuePairs<'tcx>, ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { - match *values { - infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), - infer::Regions(ref exp_found) => self.expected_found_str(exp_found), - infer::Consts(ref exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(ref exp_found) => { + match values { + infer::Types(exp_found) => self.expected_found_str_ty(exp_found), + infer::Regions(exp_found) => self.expected_found_str(exp_found), + infer::Consts(exp_found) => self.expected_found_str(exp_found), + infer::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(&pretty_exp_found) + self.expected_found_str(pretty_exp_found) } - infer::PolyTraitRefs(ref exp_found) => { + infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), found: exp_found.found.print_only_trait_path(), }; - self.expected_found_str(&pretty_exp_found) + self.expected_found_str(pretty_exp_found) } } } fn expected_found_str_ty( &self, - exp_found: &ty::error::ExpectedFound>, + exp_found: ty::error::ExpectedFound>, ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { @@ -1931,7 +1933,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Returns a string of the form "expected `{}`, found `{}`". fn expected_found_str>( &self, - exp_found: &ty::error::ExpectedFound, + exp_found: ty::error::ExpectedFound, ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { @@ -2180,7 +2182,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...", ); if let Some(infer::RelateParamBound(_, t)) = origin { - let t = self.resolve_vars_if_possible(&t); + let t = self.resolve_vars_if_possible(t); match t.kind() { // We've got: // fn get_later(g: G, dest: &mut T) -> impl FnOnce() + '_ @@ -2237,7 +2239,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values); if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = - (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values)) + (self.values_str(sup_trace.values), self.values_str(sub_trace.values)) { if sub_expected == sup_expected && sub_found == sup_found { note_and_explain_region( @@ -2279,7 +2281,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, var_origin: RegionVariableOrigin, ) -> DiagnosticBuilder<'tcx> { - let br_string = |br: ty::BoundRegion| { + let br_string = |br: ty::BoundRegionKind| { let mut s = match br { ty::BrNamed(_, name) => name.to_string(), _ => String::new(), diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 868989539d..373f0a602c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id)); match ty_opt { Some(ty) => { - let ty = self.infcx.resolve_vars_if_possible(&ty); + let ty = self.infcx.resolve_vars_if_possible(ty); if ty.walk().any(|inner| { inner == self.target || match (inner.unpack(), self.target.unpack()) { @@ -124,6 +124,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { return; } } + + // FIXME(const_generics): Currently, any uninferred `const` generics arguments + // are handled specially, but instead they should be handled in `annotate_method_call`, + // which currently doesn't work because this evaluates to `false` for const arguments. + // See https://github.com/rust-lang/rust/pull/77758 for more details. if self.node_ty_contains_target(expr.hir_id).is_some() { match expr.kind { ExprKind::Closure(..) => self.found_closure = Some(&expr), @@ -343,13 +348,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { - let arg = self.resolve_vars_if_possible(&arg); + let arg = self.resolve_vars_if_possible(arg); let arg_data = self.extract_inference_diagnostics_data(arg, None); - let kind_str = match arg.unpack() { - GenericArgKind::Type(_) => "type", - GenericArgKind::Const(_) => "the value", - GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), - }; let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span); let ty_to_string = |ty: Ty<'tcx>| -> String { @@ -618,6 +618,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .any(|span_label| span_label.label.is_some() && span_label.span == span) && local_visitor.found_arg_pattern.is_none() { + let (kind_str, const_value) = match arg.unpack() { + GenericArgKind::Type(_) => ("type", None), + GenericArgKind::Const(_) => ("the value", Some(())), + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + }; + + // FIXME(const_generics): we would like to handle const arguments + // as part of the normal diagnostics flow below, but there appear to + // be subtleties in doing so, so for now we special-case const args + // here. + if let Some(suggestion) = const_value + .and_then(|_| arg_data.parent_name.as_ref()) + .map(|parent| format!("{}::<{}>", parent, arg_data.name)) + { + err.span_suggestion_verbose( + span, + "consider specifying the const argument", + suggestion, + Applicability::MaybeIncorrect, + ); + } + // Avoid multiple labels pointing at `span`. err.span_label( span, @@ -686,7 +708,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: Span, ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); let data = self.extract_inference_diagnostics_data(ty.into(), None); let mut err = struct_span_err!( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 59786059fa..cdd68d83f2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -121,7 +121,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { (Some(ret_span), _) => { let sup_future = self.future_return_type(scope_def_id_sup); - let (return_type, action) = if let Some(_) = sup_future { + let (return_type, action) = if sup_future.is_some() { ("returned future", "held across an await point") } else { ("return type", "returned") @@ -140,7 +140,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } (_, Some(ret_span)) => { let sub_future = self.future_return_type(scope_def_id_sub); - let (return_type, action) = if let Some(_) = sub_future { + let (return_type, action) = if sub_future.is_some() { ("returned future", "held across an await point") } else { ("return type", "returned") diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index eb1521f056..b014b9832e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub(super) fn find_anon_type( &self, region: Region<'tcx>, - br: &ty::BoundRegion, + br: &ty::BoundRegionKind, ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> { if let Some(anon_reg) = self.tcx().is_suitable_region(region) { let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id); @@ -56,7 +56,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn find_component_for_bound_region( &self, arg: &'tcx hir::Ty<'tcx>, - br: &ty::BoundRegion, + br: &ty::BoundRegionKind, ) -> Option<&'tcx hir::Ty<'tcx>> { let mut nested_visitor = FindNestedTypeVisitor { tcx: self.tcx(), @@ -80,7 +80,7 @@ struct FindNestedTypeVisitor<'tcx> { tcx: TyCtxt<'tcx>, // The bound_region corresponding to the Refree(freeregion) // associated with the anonymous region we are looking for. - bound_region: ty::BoundRegion, + bound_region: ty::BoundRegionKind, // The type where the anonymous lifetime appears // for e.g., Vec<`&u8`> and <`&u8`> found_type: Option<&'tcx hir::Ty<'tcx>>, @@ -207,7 +207,7 @@ impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { struct TyPathVisitor<'tcx> { tcx: TyCtxt<'tcx>, found_it: bool, - bound_region: ty::BoundRegion, + bound_region: ty::BoundRegionKind, current_index: ty::DebruijnIndex, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 2187064ec5..e8e0326d97 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -234,14 +234,13 @@ impl NiceRegionError<'me, 'tcx> { false }; - let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { + let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: expected_substs, }); - let actual_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { - def_id: trait_def_id, - substs: actual_substs, - }); + let actual_trait_ref = self + .infcx + .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs }); // Search the expected and actual trait references to see (a) // whether the sub/sup placeholders appear in them (sometimes diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index df3dbfca01..5264854d8e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -414,7 +414,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { tcx, ctxt.param_env, ctxt.assoc_item.def_id, - self.infcx.resolve_vars_if_possible(&ctxt.substs), + self.infcx.resolve_vars_if_possible(ctxt.substs), ) { Ok(Some(instance)) => instance, _ => return false, @@ -474,7 +474,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct TraitObjectVisitor(Vec); impl TypeVisitor<'_> for TraitObjectVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index c061f485c1..4d3217a9c0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let Some((expected, found)) = - self.infcx.expected_found_str_ty(&ExpectedFound { expected, found }) + self.infcx.expected_found_str_ty(ExpectedFound { expected, found }) { // Highlighted the differences when showing the "expected/found" note. err.note_expected_found(&"", expected, &"", found); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index ca93b2777a..17a56046a5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -14,8 +14,8 @@ pub(super) struct AnonymousParamInfo<'tcx> { pub param: &'tcx hir::Param<'tcx>, /// The type corresponding to the anonymous region parameter. pub param_ty: Ty<'tcx>, - /// The ty::BoundRegion corresponding to the anonymous region. - pub bound_region: ty::BoundRegion, + /// The ty::BoundRegionKind corresponding to the anonymous region. + pub bound_region: ty::BoundRegionKind, /// The `Span` of the parameter type. pub param_ty_span: Span, /// Signals that the argument is the first parameter in the declaration. @@ -43,7 +43,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), ty::ReEarlyBound(ebr) => ( self.tcx().parent(ebr.def_id).unwrap(), - ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), + ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name), ), _ => return None, // not a free region }; @@ -55,12 +55,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let owner_id = hir.body_owner(body_id); let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); let poly_fn_sig = self.tcx().fn_sig(id); - let fn_sig = self.tcx().liberate_late_bound_regions(id, &poly_fn_sig); + let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig); body.params.iter().enumerate().find_map(|(index, param)| { // May return None; sometimes the tables are not yet populated. let ty = fn_sig.inputs()[index]; let mut found_anon_region = false; - let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { + let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| { if *r == *anon_region { found_anon_region = true; replace_region @@ -131,7 +131,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } pub(super) fn asyncness(&self, local_def_id: LocalDefId) -> Option { - // similar to the asyncness fn in rustc_ty::ty + // similar to the asyncness fn in rustc_ty_utils::ty let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id); let node = self.tcx().hir().get(hir_id); let fn_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?; @@ -145,7 +145,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub(super) fn is_return_type_anon( &self, scope_def_id: LocalDefId, - br: ty::BoundRegion, + br: ty::BoundRegionKind, decl: &hir::FnDecl<'_>, ) -> Option { let ret_ty = self.tcx().type_of(scope_def_id); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 9ac27030ad..7fb94332ca 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -24,7 +24,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; match *origin { infer::Subtype(ref trace) => { - if let Some((expected, found)) = self.values_str(&trace.values) { + if let Some((expected, found)) = self.values_str(trace.values) { label_or_note( trace.cause.span, &format!("...so that the {}", trace.cause.as_requirement_str()), diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index d7bc636db8..c292b2bdb3 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let (mut fudger, value) = self.probe(|_| { match f() { Ok(value) => { - let value = self.resolve_vars_if_possible(&value); + let value = self.resolve_vars_if_possible(value); // At this point, `value` could in principle refer // to inference variables that have been created during diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index e3365e8590..e794903fca 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -24,23 +24,23 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // as-is, we need to do some extra work here in order to make sure // that function subtyping works correctly with respect to regions // - // Note: this is a subtle algorithm. For a full explanation, - // please see the large comment at the end of the file in the (inlined) module - // `doc`. + // Note: this is a subtle algorithm. For a full explanation, please see + // the rustc dev guide: + // let span = self.trace.cause.span; self.infcx.commit_if_ok(|_| { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. - let b_prime = self.infcx.replace_bound_vars_with_placeholders(&b); + let b_prime = self.infcx.replace_bound_vars_with_placeholders(b); // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- // but no other pre-existing region variables -- can name // the placeholders. let (a_prime, _) = - self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, &a); + self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a); debug!("a_prime={:?}", a_prime); debug!("b_prime={:?}", b_prime); @@ -66,7 +66,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the [rustc dev guide]. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html - pub fn replace_bound_vars_with_placeholders(&self, binder: &ty::Binder) -> T + pub fn replace_bound_vars_with_placeholders(&self, binder: ty::Binder) -> T where T: TypeFoldable<'tcx>, { @@ -77,10 +77,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // (i.e., if there are no placeholders). let next_universe = self.universe().next_universe(); - let fld_r = |br| { + let fld_r = |br: ty::BoundRegion| { self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { universe: next_universe, - name: br, + name: br.kind, })) }; @@ -95,7 +95,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(ty::PlaceholderConst { universe: next_universe, - name: bound_var, + name: ty::BoundConst { var: bound_var, ty }, }), ty, }) @@ -113,10 +113,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!( "replace_bound_vars_with_placeholders(\ next_universe={:?}, \ - binder={:?}, \ result={:?}, \ map={:?})", - next_universe, binder, result, map, + next_universe, result, map, ); result diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index fcf1949933..d7b2ce7ee2 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -1001,7 +1001,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(&value, &mut false, |r, _db| match r { + tcx.fold_regions(value, &mut false, |r, _db| match r { ty::ReVar(rid) => self.resolve_var(*rid), _ => r, }) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index acded5351f..069f708856 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,5 +1,3 @@ -//! See the Book for more information. - pub use self::freshen::TypeFreshener; pub use self::LateBoundRegionConversionTime::*; pub use self::RegionVariableOrigin::*; @@ -345,7 +343,7 @@ pub struct InferCtxt<'a, 'tcx> { } /// See the `error_reporting` module for more details. -#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] pub enum ValuePairs<'tcx> { Types(ExpectedFound>), Regions(ExpectedFound>), @@ -452,7 +450,7 @@ pub enum RegionVariableOrigin { /// Region variables created for bound regions /// in a function or method that is called - LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime), + LateBoundRegion(Span, ty::BoundRegionKind, LateBoundRegionConversionTime), UpvarRegion(ty::UpvarId, Span), @@ -955,7 +953,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(self.commit_if_ok(|_snapshot| { let ty::SubtypePredicate { a_is_expected, a, b } = - self.replace_bound_vars_with_placeholders(&predicate); + self.replace_bound_vars_with_placeholders(predicate); let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -970,7 +968,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> UnitResult<'tcx> { self.commit_if_ok(|_snapshot| { let ty::OutlivesPredicate(r_a, r_b) = - self.replace_bound_vars_with_placeholders(&predicate); + self.replace_bound_vars_with_placeholders(predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || { RelateRegionParamBound(cause.span) }); @@ -1266,7 +1264,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { - self.resolve_vars_if_possible(&t).to_string() + self.resolve_vars_if_possible(t).to_string() } pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { @@ -1274,7 +1272,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { format!("({})", tstrs.join(", ")) } - pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { + pub fn trait_ref_to_string(&self, t: ty::TraitRef<'tcx>) -> String { self.resolve_vars_if_possible(t).print_only_trait_path().to_string() } @@ -1314,7 +1312,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// is left as is. This is an idempotent operation that does /// not affect inference state in any way and so you can do it /// at will. - pub fn resolve_vars_if_possible(&self, value: &T) -> T + pub fn resolve_vars_if_possible(&self, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -1334,9 +1332,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { where T: TypeFoldable<'tcx>, { - let mut r = resolve::UnresolvedTypeFinder::new(self); - value.visit_with(&mut r); - r.first_unresolved + value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value() } pub fn probe_const_var( @@ -1349,7 +1345,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn fully_resolve>(&self, value: &T) -> FixupResult<'tcx, T> { + pub fn fully_resolve>(&self, value: T) -> FixupResult<'tcx, T> { /*! * Attempts to resolve all type/region/const variables in * `value`. Region inference must have been run already (e.g., @@ -1383,7 +1379,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { where M: FnOnce(String) -> DiagnosticBuilder<'tcx>, { - let actual_ty = self.resolve_vars_if_possible(&actual_ty); + let actual_ty = self.resolve_vars_if_possible(actual_ty); debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); // Don't report an error if actual type is `Error`. @@ -1420,12 +1416,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, span: Span, lbrct: LateBoundRegionConversionTime, - value: &ty::Binder, + value: ty::Binder, ) -> (T, BTreeMap>) where T: TypeFoldable<'tcx>, { - let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct)); + let fld_r = + |br: ty::BoundRegion| self.next_region_var(LateBoundRegion(span, br.kind, lbrct)); let fld_t = |_| { self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, @@ -1508,7 +1505,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: Option, ) -> EvalToConstValueResult<'tcx> { let mut original_values = OriginalQueryValues::default(); - let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values); + let canonical = self.canonicalize_query((param_env, substs), &mut original_values); let (param_env, substs) = canonical.value; // The return value is the evaluated value which doesn't contain any reference to inference diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 9b2ffc7a92..97ef685cf6 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -176,7 +176,7 @@ where universe }); - let placeholder = ty::PlaceholderRegion { universe, name: br }; + let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; delegate.next_placeholder_region(placeholder) } else { delegate.next_existential_region_var(true) @@ -741,7 +741,10 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder>(&mut self, t: &ty::Binder) -> ControlFlow<()> { + fn visit_binder>( + &mut self, + t: &ty::Binder, + ) -> ControlFlow { self.target_index.shift_in(1); t.super_visit_with(self); self.target_index.shift_out(1); @@ -749,7 +752,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let ScopeInstantiator { bound_region_scope, next_region, .. } = self; match r { @@ -1005,6 +1008,6 @@ where self.first_free_index.shift_in(1); let result = self.relate(a.skip_binder(), a.skip_binder())?; self.first_free_index.shift_out(1); - Ok(ty::Binder::bind(result)) + Ok(a.rebind(result)) } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index eb1a780625..16d86e6243 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -167,7 +167,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { sup_type, sub_region, origin ); - let sup_type = self.resolve_vars_if_possible(&sup_type); + let sup_type = self.resolve_vars_if_possible(sup_type); if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) { let outlives = &mut TypeOutlives::new( @@ -205,7 +205,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { implicit_region_bound, param_env, ); - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); outlives.type_must_outlive(origin, ty, region); } } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 2b827f4f4e..f69212c599 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -124,10 +124,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { projection_ty: ty::ProjectionTy<'tcx>, ) -> Vec, ty::Region<'tcx>>> { let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx); - let erased_projection_ty = self.tcx.erase_regions(&projection_ty); + let erased_projection_ty = self.tcx.erase_regions(projection_ty); self.declared_generic_bounds_from_env_with_compare_fn(|ty| { if let ty::Projection(..) = ty.kind() { - let erased_ty = self.tcx.erase_regions(&ty); + let erased_ty = self.tcx.erase_regions(ty); erased_ty == erased_projection_ty } else { false diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index fe4ba5aa4e..d72be0134f 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -111,19 +111,17 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { /// involve some hashing and so forth). pub struct UnresolvedTypeFinder<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, - - /// Used to find the type parameter name and location for error reporting. - pub first_unresolved: Option<(Ty<'tcx>, Option)>, } impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - UnresolvedTypeFinder { infcx, first_unresolved: None } + UnresolvedTypeFinder { infcx } } } impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = (Ty<'tcx>, Option); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { if let ty::Infer(infer_ty) = *t.kind() { @@ -144,8 +142,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { } else { None }; - self.first_unresolved = Some((t, ty_var_span)); - ControlFlow::BREAK + ControlFlow::Break((t, ty_var_span)) } else { // Otherwise, visit its contents. t.super_visit_with(self) @@ -164,7 +161,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { /// Full type resolution replaces all type and region variables with /// their concrete results. If any variable cannot be replaced (never unified, etc) /// then an `Err` result is returned. -pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: &T) -> FixupResult<'tcx, T> +pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T> where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 1a1c2637a6..c4a2ecee09 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -60,16 +60,16 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { // TypeFoldable implementations. impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { traits::Obligation { - cause: self.cause.clone(), + cause: self.cause, recursion_depth: self.recursion_depth, predicate: self.predicate.fold_with(folder), param_env: self.param_env.fold_with(folder), } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.predicate.visit_with(visitor) } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index f6ef984078..8273c2d291 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -9,7 +9,7 @@ pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, pred: ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { - match pred.kind() { + match *pred.kind() { ty::PredicateKind::ForAll(binder) => { let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder)); tcx.reuse_or_mk_predicate(pred, new) @@ -309,7 +309,7 @@ impl<'tcx, I: Iterator>> Iterator for FilterToT fn next(&mut self) -> Option> { while let Some(obligation) = self.base_iterator.next() { if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() { - return Some(data); + return Some(data.value); } } None diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index e214493a56..2481a27dee 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -41,7 +41,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_privacy = { path = "../rustc_privacy" } rustc_resolve = { path = "../rustc_resolve" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_ty = { path = "../rustc_ty" } +rustc_ty_utils = { path = "../rustc_ty_utils" } tempfile = "3.0.5" [target.'cfg(windows)'.dependencies] diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 73a51ad477..28eb1fed6a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -25,8 +25,9 @@ use std::sync::{Arc, Mutex}; pub type Result = result::Result; /// Represents a compiler session. +/// /// Can be used to run `rustc_interface` queries. -/// Created by passing `Config` to `run_compiler`. +/// Created by passing [`Config`] to [`run_compiler`]. pub struct Compiler { pub(crate) sess: Lrc, codegen_backend: Lrc>, @@ -34,7 +35,6 @@ pub struct Compiler { pub(crate) input_path: Option, pub(crate) output_dir: Option, pub(crate) output_file: Option, - pub(crate) crate_name: Option, pub(crate) register_lints: Option>, pub(crate) override_queries: Option, @@ -56,6 +56,9 @@ impl Compiler { pub fn output_file(&self) -> &Option { &self.output_file } + pub fn register_lints(&self) -> &Option> { + &self.register_lints + } pub fn build_output_filenames( &self, sess: &Session, @@ -137,7 +140,6 @@ pub struct Config { /// Set to capture stderr output during compiler execution pub stderr: Option>>>, - pub crate_name: Option, pub lint_caps: FxHashMap, /// This is a callback from the driver that is called when we're registering lints; @@ -182,7 +184,6 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R input_path: config.input_path, output_dir: config.output_dir, output_file: config.output_file, - crate_name: config.crate_name, register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 88d2efe96d..0935eb2bd7 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,6 +1,6 @@ #![feature(bool_to_option)] #![feature(box_syntax)] -#![feature(set_stdio)] +#![feature(internal_output_capture)] #![feature(nll)] #![feature(generator_trait)] #![feature(generators)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fc227b9669..61ebd6d219 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,6 +6,7 @@ use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; @@ -20,7 +21,6 @@ use rustc_middle::dep_graph::DepGraph; use rustc_middle::middle; use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_mir as mir; use rustc_mir_build as mir_build; @@ -96,7 +96,7 @@ declare_box_region_type!( /// harness if one is to be provided, injection of a dependency on the /// standard library and prelude, and name resolution. /// -/// Returns `None` if we're aborting after handling -W help. +/// Returns [`None`] if we're aborting after handling -W help. pub fn configure_and_expand( sess: Lrc, lint_store: Lrc, @@ -240,16 +240,12 @@ fn configure_and_expand_inner<'a>( krate = sess.time("crate_injection", || { let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); - let (krate, name) = rustc_builtin_macros::standard_library_imports::inject( + rustc_builtin_macros::standard_library_imports::inject( krate, &mut resolver, &sess, alt_std_name, - ); - if let Some(name) = name { - sess.parse_sess.injected_crate_name.set(name).expect("not yet initialized"); - } - krate + ) }); util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer()); @@ -720,7 +716,7 @@ pub static DEFAULT_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { rustc_passes::provide(providers); rustc_resolve::provide(providers); rustc_traits::provide(providers); - rustc_ty::provide(providers); + rustc_ty_utils::provide(providers); rustc_metadata::provide(providers); rustc_lint::provide(providers); rustc_symbol_mangling::provide(providers); @@ -768,7 +764,7 @@ pub fn create_global_ctxt<'tcx>( Definitions::new(crate_name, sess.local_crate_disambiguator()), )); - let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); + let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess, defs); let codegen_backend = compiler.codegen_backend(); let mut local_providers = *DEFAULT_QUERY_PROVIDERS; @@ -837,6 +833,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { let local_def_id = tcx.hir().local_def_id(module); tcx.ensure().check_mod_loops(local_def_id); tcx.ensure().check_mod_attrs(local_def_id); + tcx.ensure().check_mod_naked_functions(local_def_id); tcx.ensure().check_mod_unstable_api_usage(local_def_id); tcx.ensure().check_mod_const_bodies(local_def_id); }); diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index d56115fd6a..de08a4c824 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -33,6 +33,8 @@ impl<'v> ItemLikeVisitor<'v> for Finder<'_> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 1de7350a3e..6ea0828cea 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::ErrorReported; @@ -12,7 +13,6 @@ use rustc_incremental::DepGraphFuture; use rustc_lint::LintStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_serialize::json; use rustc_session::config::{self, OutputFilenames, OutputType}; @@ -23,7 +23,11 @@ use std::cell::{Ref, RefCell, RefMut}; use std::rc::Rc; /// Represent the result of a query. -/// This result can be stolen with the `take` method and generated with the `compute` method. +/// +/// This result can be stolen with the [`take`] method and generated with the [`compute`] method. +/// +/// [`take`]: Self::take +/// [`compute`]: Self::compute pub struct Query { result: RefCell>>, } @@ -156,13 +160,11 @@ impl<'tcx> Queries<'tcx> { pub fn crate_name(&self) -> Result<&Query> { self.crate_name.compute(|| { - Ok(match self.compiler.crate_name { - Some(ref crate_name) => crate_name.clone(), - None => { - let parse_result = self.parse()?; - let krate = parse_result.peek(); - find_crate_name(self.session(), &krate.attrs, &self.compiler.input) - } + Ok({ + let parse_result = self.parse()?; + let krate = parse_result.peek(); + // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. + find_crate_name(self.session(), &krate.attrs, &self.compiler.input) }) }) } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 1fc2d281e7..3e94f16377 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -498,7 +498,6 @@ fn test_debugging_options_tracking_hash() { untracked!(no_parallel_llvm, true); untracked!(parse_only, true); untracked!(perf_stats, true); - untracked!(polonius, true); // `pre_link_arg` is omitted because it just forwards to `pre_link_args`. untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]); untracked!(print_link_args, true); @@ -547,7 +546,7 @@ fn test_debugging_options_tracking_hash() { tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); tracked!(dual_proc_macros, true); - tracked!(fewer_names, true); + tracked!(fewer_names, Some(true)); tracked!(force_overflow_checks, Some(true)); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); @@ -572,6 +571,7 @@ fn test_debugging_options_tracking_hash() { tracked!(osx_rpath_install_name, true); tracked!(panic_abort_tests, true); tracked!(plt, Some(true)); + tracked!(polonius, true); tracked!(precise_enum_drop_elaboration, false); tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); @@ -587,11 +587,12 @@ fn test_debugging_options_tracking_hash() { tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); - tracked!(symbol_mangling_version, SymbolManglingVersion::V0); + tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(tune_cpu, Some(String::from("abc"))); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); + tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, Some(1)); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index d9ec6d51cd..f34990a1a1 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,6 +1,5 @@ use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *}; use rustc_ast::ptr::P; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_ast::{self as ast, AttrVec, BlockCheckMode}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fingerprint::Fingerprint; @@ -20,12 +19,13 @@ use rustc_session::parse::CrateConfig; use rustc_session::CrateDisambiguator; use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session}; use rustc_span::edition::Edition; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::FileLoader; use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; -use std::io::{self, Write}; +use std::io; use std::lazy::SyncOnceCell; use std::mem; use std::ops::DerefMut; @@ -106,21 +106,6 @@ fn get_stack_size() -> Option { env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE) } -struct Sink(Arc>>); -impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} -impl io::LocalOutput for Sink { - fn clone_box(&self) -> Box { - Box::new(Self(self.0.clone())) - } -} - /// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need /// for `'static` bounds. #[cfg(not(parallel_compiler))] @@ -163,9 +148,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals R + Se let main_handler = move || { rustc_span::with_session_globals(edition, || { - if let Some(stderr) = stderr { - io::set_panic(Some(box Sink(stderr.clone()))); - } + io::set_output_capture(stderr.clone()); f() }) }; @@ -203,9 +186,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals R + Se // on the new threads. let main_handler = move |thread: rayon::ThreadBuilder| { rustc_span::SESSION_GLOBALS.set(session_globals, || { - if let Some(stderr) = stderr { - io::set_panic(Some(box Sink(stderr.clone()))); - } + io::set_output_capture(stderr.clone()); thread.run() }) }; @@ -531,8 +512,11 @@ pub(crate) fn check_attr_crate_type( if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().kind { let span = spanned.span; - let lev_candidate = - find_best_match_for_name(CRATE_TYPES.iter().map(|(k, _)| k), n, None); + let lev_candidate = find_best_match_for_name( + &CRATE_TYPES.iter().map(|(k, _)| *k).collect::>(), + n, + None, + ); if let Some(candidate) = lev_candidate { lint_buffer.buffer_lint_with_diagnostic( lint::builtin::UNKNOWN_CRATE_TYPES, @@ -826,7 +810,6 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: resolver.next_node_id(), kind: ast::StmtKind::Expr(expr), span: rustc_span::DUMMY_SP, - tokens: None, } } @@ -843,7 +826,6 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: self.resolver.next_node_id(), span: rustc_span::DUMMY_SP, kind: ast::StmtKind::Expr(loop_expr), - tokens: None, }; if self.within_static_or_const { diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 6539419aef..44fc4db7dc 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -267,8 +267,8 @@ pub fn is_whitespace(c: char) -> bool { pub fn is_id_start(c: char) -> bool { // This is XID_Start OR '_' (which formally is not a XID_Start). // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c)) } @@ -279,9 +279,9 @@ pub fn is_id_start(c: char) -> bool { pub fn is_id_continue(c: char) -> bool { // This is exactly XID_Continue. // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || ('0' <= c && c <= '9') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) + || ('0'..='9').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c)) } diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 697d25fdb5..b4dd0fc244 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -201,7 +201,7 @@ fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result return Err(EscapeError::LeadingUnderscoreUnicodeEscape), diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 760a8e385d..c56eb09b63 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -20,3 +20,4 @@ rustc_feature = { path = "../rustc_feature" } rustc_index = { path = "../rustc_index" } rustc_session = { path = "../rustc_session" } rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_parse_format = { path = "../rustc_parse_format" } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c65cf65b1c..676c85e4af 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2345,7 +2345,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { enum InitKind { Zeroed, Uninit, - }; + } /// Information about why a type cannot be initialized this way. /// Contains an error message and optionally a span to point at. diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 4cfeb0d968..780bf5fecf 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -19,7 +19,6 @@ use self::TargetLint::*; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast as ast; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability}; @@ -37,8 +36,10 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; use rustc_session::SessionLintStore; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; use rustc_target::abi::LayoutOf; +use tracing::debug; use std::cell::Cell; use std::slice; @@ -335,6 +336,20 @@ impl LintStore { } } + /// True if this symbol represents a lint group name. + pub fn is_lint_group(&self, lint_name: Symbol) -> bool { + debug!( + "is_lint_group(lint_name={:?}, lint_groups={:?})", + lint_name, + self.lint_groups.keys().collect::>() + ); + let lint_name_str = &*lint_name.as_str(); + self.lint_groups.contains_key(&lint_name_str) || { + let warnings_name_str = crate::WARNINGS.name_lower(); + lint_name_str == &*warnings_name_str + } + } + /// Checks the name of a lint for its existence, and whether it was /// renamed or removed. Generates a DiagnosticBuilder containing a /// warning for renamed and removed lints. This is over both lint @@ -411,7 +426,7 @@ impl LintStore { self.by_name.keys().map(|name| Symbol::intern(&name)).collect::>(); let suggestion = find_best_match_for_name( - symbols.iter(), + &symbols, Symbol::intern(&lint_name.to_lowercase()), None, ); @@ -786,7 +801,7 @@ impl<'tcx> LateContext<'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List>, + _predicates: &'tcx ty::List>>, ) -> Result { Ok(()) } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c2d98b8e4a..af5972c6c8 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, @@ -267,3 +267,47 @@ impl EarlyLintPass for LintPassImpl { } } } + +declare_tool_lint! { + pub rustc::EXISTING_DOC_KEYWORD, + Allow, + "Check that documented keywords in std and core actually exist", + report_in_external_macro: true +} + +declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]); + +fn is_doc_keyword(s: Symbol) -> bool { + s <= kw::Union +} + +impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { + fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { + for attr in item.attrs { + if !attr.has_name(sym::doc) { + continue; + } + if let Some(list) = attr.meta_item_list() { + for nested in list { + if nested.has_name(sym::keyword) { + let v = nested + .value_str() + .expect("#[doc(keyword = \"...\")] expected a value!"); + if is_doc_keyword(v) { + return; + } + cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { + lint.build(&format!( + "Found non-existing keyword `{}` used in \ + `#[doc(keyword = \"...\")]`", + v, + )) + .help("only existing keywords are allowed in core/std") + .emit(); + }); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index db48700c97..570578ff08 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -5,20 +5,27 @@ use rustc_ast::attr; use rustc_ast::unwrap_or; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; +use rustc_middle::lint::LevelSource; use rustc_middle::lint::LintDiagnosticBuilder; -use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; +use rustc_middle::lint::{ + struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet, +}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::{builtin, Level, Lint, LintId}; +use rustc_session::lint::{ + builtin::{self, FORBIDDEN_LINT_GROUPS}, + Level, Lint, LintId, +}; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP}; +use tracing::debug; use std::cmp; @@ -29,6 +36,8 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> LintLevelMap { let mut builder = LintLevelMapBuilder { levels, tcx, store }; let krate = tcx.hir().krate(); + builder.levels.id_to_set.reserve(krate.exported_macros.len() + 1); + let push = builder.levels.push(&krate.item.attrs, &store, true); builder.levels.register_id(hir::CRATE_HIR_ID); for macro_def in krate.exported_macros { @@ -46,6 +55,7 @@ pub struct LintLevelsBuilder<'s> { id_to_set: FxHashMap, cur: u32, warn_about_weird_lints: bool, + store: &'s LintStore, } pub struct BuilderPush { @@ -54,13 +64,14 @@ pub struct BuilderPush { } impl<'s> LintLevelsBuilder<'s> { - pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &LintStore) -> Self { + pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore) -> Self { let mut builder = LintLevelsBuilder { sess, sets: LintLevelSets::new(), cur: 0, id_to_set: Default::default(), warn_about_weird_lints, + store, }; builder.process_command_line(sess, store); assert_eq!(builder.sets.list.len(), 1); @@ -88,7 +99,7 @@ impl<'s> LintLevelsBuilder<'s> { }; for id in ids { self.check_gated_lint(id, DUMMY_SP); - let src = LintSource::CommandLine(lint_flag_val, orig_level); + let src = LintLevelSource::CommandLine(lint_flag_val, orig_level); specs.insert(id, (level, src)); } } @@ -96,6 +107,99 @@ impl<'s> LintLevelsBuilder<'s> { self.sets.list.push(LintSet::CommandLine { specs }); } + /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful + /// (e.g. if a forbid was already inserted on the same scope), then emits a + /// diagnostic with no change to `specs`. + fn insert_spec( + &mut self, + specs: &mut FxHashMap, + id: LintId, + (level, src): LevelSource, + ) { + // Setting to a non-forbid level is an error if the lint previously had + // a forbid level. Note that this is not necessarily true even with a + // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`. + // + // This means that this only errors if we're truly lowering the lint + // level from forbid. + if level != Level::Forbid { + if let (Level::Forbid, old_src) = + self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess) + { + // Backwards compatibility check: + // + // We used to not consider `forbid(lint_group)` + // as preventing `allow(lint)` for some lint `lint` in + // `lint_group`. For now, issue a future-compatibility + // warning for this case. + let id_name = id.lint.name_lower(); + let fcw_warning = match old_src { + LintLevelSource::Default => false, + LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol), + LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol), + }; + debug!( + "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}", + fcw_warning, specs, old_src, id_name + ); + + let decorate_diag_builder = |mut diag_builder: DiagnosticBuilder<'_>| { + diag_builder.span_label(src.span(), "overruled by previous forbid"); + match old_src { + LintLevelSource::Default => { + diag_builder.note(&format!( + "`forbid` lint level is the default for {}", + id.to_string() + )); + } + LintLevelSource::Node(_, forbid_source_span, reason) => { + diag_builder.span_label(forbid_source_span, "`forbid` level set here"); + if let Some(rationale) = reason { + diag_builder.note(&rationale.as_str()); + } + } + LintLevelSource::CommandLine(_, _) => { + diag_builder.note("`forbid` lint level was set on command line"); + } + } + diag_builder.emit(); + }; + if !fcw_warning { + let diag_builder = struct_span_err!( + self.sess, + src.span(), + E0453, + "{}({}) incompatible with previous forbid", + level.as_str(), + src.name(), + ); + decorate_diag_builder(diag_builder); + } else { + self.struct_lint( + FORBIDDEN_LINT_GROUPS, + Some(src.span().into()), + |diag_builder| { + let diag_builder = diag_builder.build(&format!( + "{}({}) incompatible with previous forbid", + level.as_str(), + src.name(), + )); + decorate_diag_builder(diag_builder); + }, + ); + } + + // Retain the forbid lint level, unless we are + // issuing a FCW. In the FCW case, we want to + // respect the new setting. + if !fcw_warning { + return; + } + } + } + specs.insert(id, (level, src)); + } + /// Pushes a list of AST lint attributes onto this context. /// /// This function will return a `BuilderPush` object which should be passed @@ -110,7 +214,7 @@ impl<'s> LintLevelsBuilder<'s> { /// `#[allow]` /// /// Don't forget to call `pop`! - pub fn push( + pub(crate) fn push( &mut self, attrs: &[ast::Attribute], store: &LintStore, @@ -219,10 +323,10 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { - let src = LintSource::Node(name, li.span(), reason); + let src = LintLevelSource::Node(name, li.span(), reason); for &id in ids { self.check_gated_lint(id, attr.span); - specs.insert(id, (level, src)); + self.insert_spec(&mut specs, id, (level, src)); } } @@ -230,13 +334,13 @@ impl<'s> LintLevelsBuilder<'s> { match result { Ok(ids) => { let complete_name = &format!("{}::{}", tool_name.unwrap(), name); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(complete_name), li.span(), reason, ); for id in ids { - specs.insert(*id, (level, src)); + self.insert_spec(&mut specs, *id, (level, src)); } } Err((Some(ids), new_lint_name)) => { @@ -267,13 +371,13 @@ impl<'s> LintLevelsBuilder<'s> { }, ); - let src = LintSource::Node( + let src = LintLevelSource::Node( Symbol::intern(&new_lint_name), li.span(), reason, ); for id in ids { - specs.insert(*id, (level, src)); + self.insert_spec(&mut specs, *id, (level, src)); } } Err((None, _)) => { @@ -346,7 +450,7 @@ impl<'s> LintLevelsBuilder<'s> { } let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), + LintLevelSource::Node(name, span, _) => (name, span), _ => continue, }; @@ -373,50 +477,6 @@ impl<'s> LintLevelsBuilder<'s> { } } - for (id, &(level, ref src)) in specs.iter() { - if level == Level::Forbid { - continue; - } - let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) { - (Some(Level::Forbid), src) => src, - _ => continue, - }; - let forbidden_lint_name = match forbid_src { - LintSource::Default => id.to_string(), - LintSource::Node(name, _, _) => name.to_string(), - LintSource::CommandLine(name, _) => name.to_string(), - }; - let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), - _ => continue, - }; - let mut diag_builder = struct_span_err!( - self.sess, - lint_attr_span, - E0453, - "{}({}) overruled by outer forbid({})", - level.as_str(), - lint_attr_name, - forbidden_lint_name - ); - diag_builder.span_label(lint_attr_span, "overruled by previous forbid"); - match forbid_src { - LintSource::Default => {} - LintSource::Node(_, forbid_source_span, reason) => { - diag_builder.span_label(forbid_source_span, "`forbid` level set here"); - if let Some(rationale) = reason { - diag_builder.note(&rationale.as_str()); - } - } - LintSource::CommandLine(_, _) => { - diag_builder.note("`forbid` lint level was set on command line"); - } - } - diag_builder.emit(); - // don't set a separate error for every lint in the group - break; - } - let prev = self.cur; if !specs.is_empty() { self.cur = self.sets.list.len() as u32; @@ -447,7 +507,7 @@ impl<'s> LintLevelsBuilder<'s> { } /// Find the lint level for a lint. - pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) { + pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) { self.sets.get_lint_level(lint, self.cur, None, self.sess) } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 24bfdad970..2336b52619 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -55,6 +55,7 @@ mod levels; mod methods; mod non_ascii_idents; mod nonstandard_style; +mod panic_fmt; mod passes; mod redundant_semicolon; mod traits; @@ -80,6 +81,7 @@ use internal::*; use methods::*; use non_ascii_idents::*; use nonstandard_style::*; +use panic_fmt::PanicFmt; use redundant_semicolon::*; use traits::*; use types::*; @@ -166,6 +168,7 @@ macro_rules! late_lint_passes { ClashingExternDeclarations: ClashingExternDeclarations::new(), DropTraitConstraints: DropTraitConstraints, TemporaryCStringAsPtr: TemporaryCStringAsPtr, + PanicFmt: PanicFmt, ] ); }; @@ -280,7 +283,6 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { UNUSED_MUT, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, - OVERLAPPING_PATTERNS, UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS, @@ -332,6 +334,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_renamed("intra_doc_link_resolution_failure", "broken_intra_doc_links"); + store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); store.register_removed("unknown_features", "replaced by an error"); store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); @@ -460,6 +463,8 @@ fn register_internals(store: &mut LintStore) { store.register_early_pass(|| box DefaultHashTypes::new()); store.register_lints(&LintPassImpl::get_lints()); store.register_early_pass(|| box LintPassImpl); + store.register_lints(&ExistingDocKeyword::get_lints()); + store.register_late_pass(|| box ExistingDocKeyword); store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|| box TyTyKind); store.register_group( @@ -472,6 +477,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(TY_PASS_BY_REFERENCE), LintId::of(USAGE_OF_QUALIFIED_TY), + LintId::of(EXISTING_DOC_KEYWORD), ], ); } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index f117ce1f80..6d61b86f32 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -94,9 +94,9 @@ fn to_camel_case(s: &str) -> String { } if new_word { - camel_cased_component.push_str(&c.to_uppercase().to_string()); + camel_cased_component.extend(c.to_uppercase()); } else { - camel_cased_component.push_str(&c.to_lowercase().to_string()); + camel_cased_component.extend(c.to_lowercase()); } prev_is_lower_case = c.is_lowercase(); @@ -127,14 +127,20 @@ impl NonCamelCaseTypes { if !is_camel_case(name) { cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| { let msg = format!("{} `{}` should have an upper camel case name", sort, name); - lint.build(&msg) - .span_suggestion( + let mut err = lint.build(&msg); + let cc = to_camel_case(name); + // We cannot provide meaningful suggestions + // if the characters are in the category of "Lowercase Letter". + if *name != cc { + err.span_suggestion( ident.span, "convert the identifier to upper camel case", to_camel_case(name), Applicability::MaybeIncorrect, - ) - .emit() + ); + } + + err.emit(); }) } } @@ -263,17 +269,21 @@ impl NonSnakeCase { let sc = NonSnakeCase::to_snake_case(name); let msg = format!("{} `{}` should have a snake case name", sort, name); let mut err = lint.build(&msg); - // We have a valid span in almost all cases, but we don't have one when linting a crate - // name provided via the command line. - if !ident.span.is_dummy() { - err.span_suggestion( - ident.span, - "convert the identifier to snake case", - sc, - Applicability::MaybeIncorrect, - ); - } else { - err.help(&format!("convert the identifier to snake case: `{}`", sc)); + // We cannot provide meaningful suggestions + // if the characters are in the category of "Uppercase Letter". + if *name != sc { + // We have a valid span in almost all cases, but we don't have one when linting a crate + // name provided via the command line. + if !ident.span.is_dummy() { + err.span_suggestion( + ident.span, + "convert the identifier to snake case", + sc, + Applicability::MaybeIncorrect, + ); + } else { + err.help(&format!("convert the identifier to snake case: `{}`", sc)); + } } err.emit(); @@ -441,14 +451,20 @@ impl NonUpperCaseGlobals { if name.chars().any(|c| c.is_lowercase()) { cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| { let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); - lint.build(&format!("{} `{}` should have an upper case name", sort, name)) - .span_suggestion( + let mut err = + lint.build(&format!("{} `{}` should have an upper case name", sort, name)); + // We cannot provide meaningful suggestions + // if the characters are in the category of "Lowercase Letter". + if *name != uc { + err.span_suggestion( ident.span, "convert the identifier to upper case", uc, Applicability::MaybeIncorrect, - ) - .emit(); + ); + } + + err.emit(); }) } } diff --git a/compiler/rustc_lint/src/panic_fmt.rs b/compiler/rustc_lint/src/panic_fmt.rs new file mode 100644 index 0000000000..e01ff1641b --- /dev/null +++ b/compiler/rustc_lint/src/panic_fmt.rs @@ -0,0 +1,151 @@ +use crate::{LateContext, LateLintPass, LintContext}; +use rustc_ast as ast; +use rustc_errors::{pluralize, Applicability}; +use rustc_hir as hir; +use rustc_middle::ty; +use rustc_parse_format::{ParseMode, Parser, Piece}; +use rustc_span::{sym, InnerSpan}; + +declare_lint! { + /// The `non_fmt_panic` lint detects `panic!("..")` with `{` or `}` in the string literal + /// when it is not used as a format string. + /// + /// ### Example + /// + /// ```rust,no_run + /// panic!("{}"); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `panic!("{}")` panics with the message `"{}"`, as a `panic!()` invocation + /// with a single argument does not use `format_args!()`. + /// A future edition of Rust will interpret this string as format string, + /// which would break this. + NON_FMT_PANIC, + Warn, + "detect braces in single-argument panic!() invocations", + report_in_external_macro +} + +declare_lint_pass!(PanicFmt => [NON_FMT_PANIC]); + +impl<'tcx> LateLintPass<'tcx> for PanicFmt { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Call(f, [arg]) = &expr.kind { + if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() { + if Some(def_id) == cx.tcx.lang_items().begin_panic_fn() + || Some(def_id) == cx.tcx.lang_items().panic_fn() + { + check_panic(cx, f, arg); + } + } + } + } +} + +fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Lit(lit) = &arg.kind { + if let ast::LitKind::Str(sym, _) = lit.node { + let mut expn = f.span.ctxt().outer_expn_data(); + if let Some(id) = expn.macro_def_id { + if cx.tcx.is_diagnostic_item(sym::std_panic_macro, id) + || cx.tcx.is_diagnostic_item(sym::core_panic_macro, id) + { + let fmt = sym.as_str(); + if !fmt.contains(&['{', '}'][..]) { + return; + } + + let fmt_span = arg.span.source_callsite(); + + let (snippet, style) = + match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) { + Ok(snippet) => { + // Count the number of `#`s between the `r` and `"`. + let style = snippet.strip_prefix('r').and_then(|s| s.find('"')); + (Some(snippet), style) + } + Err(_) => (None, None), + }; + + let mut fmt_parser = + Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format); + let n_arguments = + (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count(); + + // Unwrap another level of macro expansion if this panic!() + // was expanded from assert!() or debug_assert!(). + for &assert in &[sym::assert_macro, sym::debug_assert_macro] { + let parent = expn.call_site.ctxt().outer_expn_data(); + if parent + .macro_def_id + .map_or(false, |id| cx.tcx.is_diagnostic_item(assert, id)) + { + expn = parent; + } + } + + if n_arguments > 0 && fmt_parser.errors.is_empty() { + let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] { + [] => vec![fmt_span], + v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(), + }; + cx.struct_span_lint(NON_FMT_PANIC, arg_spans, |lint| { + let mut l = lint.build(match n_arguments { + 1 => "panic message contains an unused formatting placeholder", + _ => "panic message contains unused formatting placeholders", + }); + l.note("this message is not used as a format string when given without arguments, but will be in a future Rust edition"); + if expn.call_site.contains(arg.span) { + l.span_suggestion( + arg.span.shrink_to_hi(), + &format!("add the missing argument{}", pluralize!(n_arguments)), + ", ...".into(), + Applicability::HasPlaceholders, + ); + l.span_suggestion( + arg.span.shrink_to_lo(), + "or add a \"{}\" format string to use the message literally", + "\"{}\", ".into(), + Applicability::MachineApplicable, + ); + } + l.emit(); + }); + } else { + let brace_spans: Option> = snippet + .filter(|s| s.starts_with('"') || s.starts_with("r#")) + .map(|s| { + s.char_indices() + .filter(|&(_, c)| c == '{' || c == '}') + .map(|(i, _)| { + fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }) + }) + .collect() + }); + let msg = match &brace_spans { + Some(v) if v.len() == 1 => "panic message contains a brace", + _ => "panic message contains braces", + }; + cx.struct_span_lint(NON_FMT_PANIC, brace_spans.unwrap_or(vec![expn.call_site]), |lint| { + let mut l = lint.build(msg); + l.note("this message is not used as a format string, but will be in a future Rust edition"); + if expn.call_site.contains(arg.span) { + l.span_suggestion( + arg.span.shrink_to_lo(), + "add a \"{}\" format string to use the message literally", + "\"{}\", ".into(), + Applicability::MachineApplicable, + ); + } + l.emit(); + }); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index 84cc7b68d4..428198cae8 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -28,25 +28,40 @@ declare_lint_pass!(RedundantSemicolons => [REDUNDANT_SEMICOLONS]); impl EarlyLintPass for RedundantSemicolons { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { + let mut after_item_stmt = false; let mut seq = None; for stmt in block.stmts.iter() { match (&stmt.kind, &mut seq) { (StmtKind::Empty, None) => seq = Some((stmt.span, false)), (StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true), - (_, seq) => maybe_lint_redundant_semis(cx, seq), + (_, seq) => { + maybe_lint_redundant_semis(cx, seq, after_item_stmt); + after_item_stmt = matches!(stmt.kind, StmtKind::Item(_)); + } } } - maybe_lint_redundant_semis(cx, &mut seq); + maybe_lint_redundant_semis(cx, &mut seq, after_item_stmt); } } -fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) { +fn maybe_lint_redundant_semis( + cx: &EarlyContext<'_>, + seq: &mut Option<(Span, bool)>, + after_item_stmt: bool, +) { if let Some((span, multiple)) = seq.take() { // FIXME: Find a better way of ignoring the trailing // semicolon from macro expansion if span == rustc_span::DUMMY_SP { return; } + + // FIXME: Lint on semicolons after item statements + // once doing so doesn't break bootstrapping + if after_item_stmt { + return; + } + cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| { let (msg, rem) = if multiple { ("unnecessary trailing semicolons", "remove these semicolons") diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 467a3a4259..9ad9d53cd0 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -880,7 +880,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - match ty.kind() { + match *ty.kind() { ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => { FfiSafe } @@ -1044,7 +1044,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - let sig = tcx.erase_late_bound_regions(&sig); + let sig = tcx.erase_late_bound_regions(sig); if !sig.output().is_unit() { let r = self.check_type_for_ffi(cache, sig.output()); match r { @@ -1131,16 +1131,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { struct ProhibitOpaqueTypes<'a, 'tcx> { cx: &'a LateContext<'tcx>, - ty: Option>, - }; + } impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = Ty<'tcx>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { match ty.kind() { - ty::Opaque(..) => { - self.ty = Some(ty); - ControlFlow::BREAK - } + ty::Opaque(..) => ControlFlow::Break(ty), // Consider opaque types within projections FFI-safe if they do not normalize // to more opaque types. ty::Projection(..) => { @@ -1159,9 +1157,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None }; - ty.visit_with(&mut visitor); - if let Some(ty) = visitor.ty { + if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); true } else { @@ -1218,7 +1214,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) { let def_id = self.cx.tcx.hir().local_def_id(id); let sig = self.cx.tcx.fn_sig(def_id); - let sig = self.cx.tcx.erase_late_bound_regions(&sig); + let sig = self.cx.tcx.erase_late_bound_regions(sig); for (input_ty, input_hir) in sig.inputs().iter().zip(decl.inputs) { self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false); @@ -1295,7 +1291,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind { let item_def_id = cx.tcx.hir().local_def_id(it.hir_id); let t = cx.tcx.type_of(item_def_id); - let ty = cx.tcx.erase_regions(&t); + let ty = cx.tcx.erase_regions(t); let layout = match cx.layout_of(ty) { Ok(layout) => layout, Err( diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 4bbc180b22..5e1f94c071 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -218,8 +218,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Dynamic(binder, _) => { let mut has_emitted = false; - for predicate in binder.skip_binder().iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = + predicate.skip_binder() + { let def_id = trait_ref.def_id; let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post,); @@ -1152,7 +1154,7 @@ declare_lint! { /// ```rust /// #![feature(box_syntax)] /// fn main() { - /// let a = (box [1,2,3]).len(); + /// let a = (box [1, 2, 3]).len(); /// } /// ``` /// diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ad53f23757..655eb229e6 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -8,6 +8,42 @@ use crate::{declare_lint, declare_lint_pass, declare_tool_lint}; use rustc_span::edition::Edition; use rustc_span::symbol::sym; +declare_lint! { + /// The `forbidden_lint_groups` lint detects violations of + /// `forbid` applied to a lint group. Due to a bug in the compiler, + /// these used to be overlooked entirely. They now generate a warning. + /// + /// ### Example + /// + /// ```rust + /// #![forbid(warnings)] + /// #![deny(bad_style)] + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Recommended fix + /// + /// If your crate is using `#![forbid(warnings)]`, + /// we recommend that you change to `#![deny(warnings)]`. + /// + /// ### Explanation + /// + /// Due to a compiler bug, applying `forbid` to lint groups + /// previously had no effect. The bug is now fixed but instead of + /// enforcing `forbid` we issue this future-compatibility warning + /// to avoid breaking existing crates. + pub FORBIDDEN_LINT_GROUPS, + Warn, + "applying forbid to lint-groups", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #81670 ", + edition: None, + }; +} + declare_lint! { /// The `ill_formed_attribute_input` lint detects ill-formed attribute /// inputs that were previously accepted and used in practice. @@ -588,8 +624,8 @@ declare_lint! { } declare_lint! { - /// The `overlapping_patterns` lint detects `match` arms that have - /// [range patterns] that overlap. + /// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that + /// overlap on their endpoints. /// /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns /// @@ -607,13 +643,12 @@ declare_lint! { /// /// ### Explanation /// - /// It is likely a mistake to have range patterns in a match expression - /// that overlap. Check that the beginning and end values are what you - /// expect, and keep in mind that with `..=` the left and right bounds are - /// inclusive. - pub OVERLAPPING_PATTERNS, + /// It is likely a mistake to have range patterns in a match expression that overlap in this + /// way. Check that the beginning and end values are what you expect, and keep in mind that + /// with `..=` the left and right bounds are inclusive. + pub OVERLAPPING_RANGE_ENDPOINTS, Warn, - "detects overlapping patterns" + "detects range patterns with overlapping endpoints" } declare_lint! { @@ -1763,7 +1798,7 @@ declare_lint! { /// /// impl MyIterator for T where T: Iterator { } /// - /// let x = vec![1,2,3]; + /// let x = vec![1, 2, 3]; /// let _ = x.iter().is_sorted(); /// ``` /// @@ -2786,6 +2821,50 @@ declare_lint! { "detects deprecation attributes with no effect", } +declare_lint! { + /// The `unsupported_naked_functions` lint detects naked function + /// definitions that are unsupported but were previously accepted. + /// + /// ### Example + /// + /// ```rust + /// #![feature(naked_functions)] + /// + /// #[naked] + /// pub fn f() -> u32 { + /// 42 + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The naked functions must be defined using a single inline assembly + /// block. + /// + /// The execution must never fall through past the end of the assembly + /// code so the block must use `noreturn` option. The asm block can also + /// use `att_syntax` option, but other options are not allowed. + /// + /// The asm block must not contain any operands other than `const` and + /// `sym`. Additionally, naked function should specify a non-Rust ABI. + /// + /// While other definitions of naked functions were previously accepted, + /// they are unsupported and might not work reliably. This is a + /// [future-incompatible] lint that will transition into hard error in + /// the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub UNSUPPORTED_NAKED_FUNCTIONS, + Warn, + "unsupported naked function definitions", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #32408 ", + edition: None, + }; +} + declare_tool_lint! { pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL, Deny, @@ -2796,6 +2875,7 @@ declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. HardwiredLints => [ + FORBIDDEN_LINT_GROUPS, ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, ARITHMETIC_OVERFLOW, UNCONDITIONAL_PANIC, @@ -2809,7 +2889,7 @@ declare_lint_pass! { DEAD_CODE, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, - OVERLAPPING_PATTERNS, + OVERLAPPING_RANGE_ENDPOINTS, BINDINGS_WITH_VARIANT_NAME, UNUSED_MACROS, WARNINGS, @@ -2877,6 +2957,7 @@ declare_lint_pass! { UNINHABITED_STATIC, FUNCTION_ITEM_REFERENCES, USELESS_DEPRECATED, + UNSUPPORTED_NAKED_FUNCTIONS, ] } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index af9926400c..aec0fc253c 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -366,11 +366,25 @@ impl LintBuffer { /// ``` /// /// The `{{produces}}` tag will be automatically replaced with the output from -/// the example by the build system. You can build and view the rustc book -/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too -/// complex to run as a simple example (for example, it needs an extern -/// crate), mark it with `ignore` and manually paste the expected output below -/// the example. +/// the example by the build system. If the lint example is too complex to run +/// as a simple example (for example, it needs an extern crate), mark the code +/// block with `ignore` and manually replace the `{{produces}}` line with the +/// expected output in a `text` code block. +/// +/// If this is a rustdoc-only lint, then only include a brief introduction +/// with a link with the text `[rustdoc book]` so that the validator knows +/// that this is for rustdoc only (see BROKEN_INTRA_DOC_LINKS as an example). +/// +/// Commands to view and test the documentation: +/// +/// * `./x.py doc --stage=1 src/doc/rustc --open`: Builds the rustc book and opens it. +/// * `./x.py test src/tools/lint-docs`: Validates that the lint docs have the +/// correct style, and that the code example actually emits the expected +/// lint. +/// +/// If you have already built the compiler, and you want to make changes to +/// just the doc comments, then use the `--keep-stage=0` flag with the above +/// commands to avoid rebuilding the compiler. #[macro_export] macro_rules! declare_lint { ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 54b22ca49a..621363bed8 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -201,10 +201,10 @@ fn main() { cmd.args(&components); for lib in output(&mut cmd).split_whitespace() { - let name = if lib.starts_with("-l") { - &lib[2..] - } else if lib.starts_with('-') { - &lib[1..] + let name = if let Some(stripped) = lib.strip_prefix("-l") { + stripped + } else if let Some(stripped) = lib.strip_prefix('-') { + stripped } else if Path::new(lib).exists() { // On MSVC llvm-config will print the full name to libraries, but // we're only interested in the name part @@ -241,17 +241,17 @@ fn main() { cmd.arg(llvm_link_arg).arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { if is_crossed { - if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target)); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target)); + if let Some(stripped) = lib.strip_prefix("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target)); + } else if let Some(stripped) = lib.strip_prefix("-L") { + println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target)); } - } else if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", &lib[9..]); - } else if lib.starts_with("-l") { - println!("cargo:rustc-link-lib={}", &lib[2..]); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", &lib[2..]); + } else if let Some(stripped) = lib.strip_prefix("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", stripped); + } else if let Some(stripped) = lib.strip_prefix("-l") { + println!("cargo:rustc-link-lib={}", stripped); + } else if let Some(stripped) = lib.strip_prefix("-L") { + println!("cargo:rustc-link-search=native={}", stripped); } } @@ -262,10 +262,10 @@ fn main() { let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS"); if let Some(s) = llvm_linker_flags { for lib in s.into_string().unwrap().split_whitespace() { - if lib.starts_with("-l") { - println!("cargo:rustc-link-lib={}", &lib[2..]); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", &lib[2..]); + if let Some(stripped) = lib.strip_prefix("-l") { + println!("cargo:rustc-link-lib={}", stripped); + } else if let Some(stripped) = lib.strip_prefix("-L") { + println!("cargo:rustc-link-search=native={}", stripped); } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 2b1143a4ec..25badc3f4e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -3,7 +3,6 @@ #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/LEB128.h" #include @@ -13,15 +12,14 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( const char* const Filenames[], size_t FilenamesLen, RustStringRef BufferOut) { - // LLVM 11's CoverageFilenamesSectionWriter uses its new `Version4` format, - // so we're manually writing the `Version3` format ourselves. - RawRustStringOstream OS(BufferOut); - encodeULEB128(FilenamesLen, OS); + SmallVector FilenameRefs; for (size_t i = 0; i < FilenamesLen; i++) { - StringRef Filename(Filenames[i]); - encodeULEB128(Filename.size(), OS); - OS << Filename; + FilenameRefs.push_back(StringRef(Filenames[i])); } + auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter( + makeArrayRef(FilenameRefs)); + RawRustStringOstream OS(BufferOut); + FilenamesWriter.write(OS); } extern "C" void LLVMRustCoverageWriteMappingToBuffer( @@ -45,20 +43,40 @@ extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, con return wrap(createPGOFuncNameVar(*cast(unwrap(F)), FuncNameRef)); } -extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) { - StringRef NameRef(Name); - return IndexedInstrProf::ComputeHash(NameRef); +extern "C" uint64_t LLVMRustCoverageHashCString(const char *StrVal) { + StringRef StrRef(StrVal); + return IndexedInstrProf::ComputeHash(StrRef); +} + +extern "C" uint64_t LLVMRustCoverageHashByteArray( + const char *Bytes, + unsigned NumBytes) { + StringRef StrRef(Bytes, NumBytes); + return IndexedInstrProf::ComputeHash(StrRef); } -extern "C" void LLVMRustCoverageWriteSectionNameToString(LLVMModuleRef M, - RustStringRef Str) { +static void WriteSectionNameToString(LLVMModuleRef M, + InstrProfSectKind SK, + RustStringRef Str) { Triple TargetTriple(unwrap(M)->getTargetTriple()); - auto name = getInstrProfSectionName(IPSK_covmap, - TargetTriple.getObjectFormat()); + auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat()); RawRustStringOstream OS(Str); OS << name; } +extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M, + RustStringRef Str) { + WriteSectionNameToString(M, IPSK_covmap, Str); +} + +extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M, + RustStringRef Str) { +#if LLVM_VERSION_GE(11, 0) + WriteSectionNameToString(M, IPSK_covfun, Str); +// else do nothing; the `Version` check will abort codegen on the Rust side +#endif +} + extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { auto name = getCoverageMappingVarName(); RawRustStringOstream OS(Str); @@ -66,5 +84,9 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { } extern "C" uint32_t LLVMRustCoverageMappingVersion() { +#if LLVM_VERSION_GE(11, 0) + return coverage::CovMapVersion::Version4; +#else return coverage::CovMapVersion::Version3; +#endif } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 71ca4f23bb..2264908995 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -16,9 +16,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Passes/PassBuilder.h" -#if LLVM_VERSION_GE(9, 0) #include "llvm/Passes/StandardInstrumentations.h" -#endif #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -31,15 +29,11 @@ #include "llvm-c/Transforms/PassManagerBuilder.h" #include "llvm/Transforms/Instrumentation.h" -#if LLVM_VERSION_GE(9, 0) #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Support/TimeProfiler.h" -#endif #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" -#if LLVM_VERSION_GE(9, 0) #include "llvm/Transforms/Utils/CanonicalizeAliases.h" -#endif #include "llvm/Transforms/Utils/NameAnonGlobals.h" using namespace llvm; @@ -73,20 +67,18 @@ extern "C" void LLVMTimeTraceProfilerInitialize() { timeTraceProfilerInitialize( /* TimeTraceGranularity */ 0, /* ProcName */ "rustc"); -#elif LLVM_VERSION_GE(9, 0) +#else timeTraceProfilerInitialize(); #endif } extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { -#if LLVM_VERSION_GE(9, 0) StringRef FN(FileName); std::error_code EC; raw_fd_ostream OS(FN, EC, sys::fs::CD_CreateAlways); timeTraceProfilerWrite(OS); timeTraceProfilerCleanup(); -#endif } enum class LLVMRustPassKind { @@ -127,22 +119,14 @@ extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) { const bool CompileKernel = false; -#if LLVM_VERSION_GE(9, 0) return wrap(createModuleAddressSanitizerLegacyPassPass(CompileKernel, Recover)); -#else - return wrap(createAddressSanitizerModulePass(CompileKernel, Recover)); -#endif } extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool Recover) { -#if LLVM_VERSION_GE(9, 0) const bool CompileKernel = false; return wrap(createMemorySanitizerLegacyPassPass( MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel})); -#else - return wrap(createMemorySanitizerLegacyPassPass(TrackOrigins, Recover)); -#endif } extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() { @@ -466,7 +450,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool AsmComments, bool EmitStackSizeSection, bool RelaxELFRelocations, - bool UseInitArray) { + bool UseInitArray, + const char *SplitDwarfFile) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -492,6 +477,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.MCOptions.AsmVerbose = AsmComments; Options.MCOptions.PreserveAsmComments = AsmComments; Options.MCOptions.ABIName = ABIStr; + if (SplitDwarfFile) { + Options.MCOptions.SplitDwarfFile = SplitDwarfFile; + } Options.RelaxELFRelocations = RelaxELFRelocations; Options.UseInitArray = UseInitArray; @@ -626,7 +614,7 @@ static TargetMachine::CodeGenFileType fromRust(LLVMRustFileType Type) { extern "C" LLVMRustResult LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, - LLVMModuleRef M, const char *Path, + LLVMModuleRef M, const char *Path, const char *DwoPath, LLVMRustFileType RustFileType) { llvm::legacy::PassManager *PM = unwrap(PMR); auto FileType = fromRust(RustFileType); @@ -642,8 +630,22 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, } buffer_ostream BOS(OS); - unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, false); - PM->run(*unwrap(M)); + if (DwoPath) { + raw_fd_ostream DOS(DwoPath, EC, sys::fs::F_None); + EC.clear(); + if (EC) + ErrorInfo = EC.message(); + if (ErrorInfo != "") { + LLVMRustSetLastError(ErrorInfo.c_str()); + return LLVMRustResult::Failure; + } + buffer_ostream DBOS(DOS); + unwrap(Target)->addPassesToEmitFile(*PM, BOS, &DBOS, FileType, false); + PM->run(*unwrap(M)); + } else { + unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, false); + PM->run(*unwrap(M)); + } // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output // stream (OS), so the only real safe place to delete this is here? Don't we @@ -657,8 +659,6 @@ extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmS const char*); // IR name extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler -#if LLVM_VERSION_GE(9, 0) - std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) { if (any_isa(WrappedIr)) return any_cast(WrappedIr)->getName().str(); @@ -706,7 +706,6 @@ void LLVMSelfProfileInitializeCallbacks( AfterPassCallback(LlvmSelfProfiler); }); } -#endif enum class LLVMRustOptStage { PreLinkNoLTO, @@ -739,7 +738,6 @@ LLVMRustOptimizeWithNewPassManager( void* LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { -#if LLVM_VERSION_GE(9, 0) Module *TheModule = unwrap(ModuleRef); TargetMachine *TM = unwrap(TMRef); PassBuilder::OptimizationLevel OptLevel = fromRust(OptLevelRust); @@ -970,11 +968,6 @@ LLVMRustOptimizeWithNewPassManager( UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove MPM.run(*TheModule, MAM); -#else - // The new pass manager has been available for a long time, - // but we don't bother supporting it on old LLVM versions. - report_fatal_error("New pass manager only supported since LLVM 9"); -#endif } // Callback to demangle function name @@ -1325,12 +1318,9 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, GlobalValue::LinkageTypes NewLinkage) { Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; }; -#if LLVM_VERSION_GE(9, 0) + thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage, Ret->GUIDPreservedSymbols); -#else - thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage); -#endif // Here we calculate an `ExportedGUIDs` set for use in the `isExported` // callback below. This callback below will dictate the linkage for all diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 938eb19fae..c0ff62c17b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -124,9 +124,7 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, return wrap(unwrap(M) ->getOrInsertFunction(StringRef(Name, NameLen), unwrap(FunctionTy)) -#if LLVM_VERSION_GE(9, 0) .getCallee() -#endif ); } @@ -251,11 +249,7 @@ extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index, LLVMTypeRef Ty) { CallBase *Call = unwrap(Instr); -#if LLVM_VERSION_GE(9, 0) Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty)); -#else - Attribute Attr = Attribute::get(Call->getContext(), Attribute::ByVal); -#endif Call->addAttribute(Index, Attr); } @@ -296,11 +290,7 @@ extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn, extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index, LLVMTypeRef Ty) { Function *F = unwrap(Fn); -#if LLVM_VERSION_GE(9, 0) Attribute Attr = Attribute::getWithByValType(F->getContext(), unwrap(Ty)); -#else - Attribute Attr = Attribute::get(F->getContext(), Attribute::ByVal); -#endif F->addAttribute(Index, Attr); } @@ -616,11 +606,9 @@ static DISubprogram::DISPFlags fromRust(LLVMRustDISPFlags SPFlags) { if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagOptimized)) { Result |= DISubprogram::DISPFlags::SPFlagOptimized; } -#if LLVM_VERSION_GE(9, 0) if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) { Result |= DISubprogram::DISPFlags::SPFlagMainSubprogram; } -#endif return Result; } @@ -702,13 +690,14 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( const char *Producer, size_t ProducerLen, bool isOptimized, const char *Flags, unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, - LLVMRustDebugEmissionKind Kind) { + LLVMRustDebugEmissionKind Kind, + uint64_t DWOId, bool SplitDebugInlining) { auto *File = unwrapDI(FileRef); return wrap(Builder->createCompileUnit(Lang, File, StringRef(Producer, ProducerLen), isOptimized, Flags, RuntimeVer, StringRef(SplitName, SplitNameLen), - fromRust(Kind))); + fromRust(Kind), DWOId, SplitDebugInlining)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( @@ -744,10 +733,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( DITemplateParameterArray(unwrap(TParam)); DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); DINode::DIFlags llvmFlags = fromRust(Flags); -#if LLVM_VERSION_LT(9, 0) - if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) - llvmFlags |= DINode::DIFlags::FlagMainSubprogram; -#endif DISubprogram *Sub = Builder->createFunction( unwrapDI(Scope), StringRef(Name, NameLen), @@ -1478,7 +1463,7 @@ extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V, const char *Name, size_t NameLen) { Triple TargetTriple(unwrap(M)->getTargetTriple()); GlobalObject *GV = unwrap(V); - if (!TargetTriple.isOSBinFormatMachO()) { + if (TargetTriple.supportsCOMDAT()) { StringRef NameRef(Name, NameLen); GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef)); } diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index a381290d46..b2ffa271f6 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -167,6 +167,7 @@ pub fn initialize_available_targets() { LLVMInitializeWebAssemblyTargetInfo, LLVMInitializeWebAssemblyTarget, LLVMInitializeWebAssemblyTargetMC, - LLVMInitializeWebAssemblyAsmPrinter + LLVMInitializeWebAssemblyAsmPrinter, + LLVMInitializeWebAssemblyAsmParser ); } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 5c28839c9b..152ae159ae 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -21,7 +21,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { #[proc_macro] pub fn symbols(input: TokenStream) -> TokenStream { - symbols::symbols(input) + symbols::symbols(input.into()).into() } decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index fd85919636..12990ae2d9 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -353,7 +353,7 @@ fn add_query_description_impl( tcx: TyCtxt<'tcx>, id: SerializedDepNodeIndex ) -> Option { - tcx.queries.on_disk_cache.try_load_query_result(tcx, id) + tcx.queries.on_disk_cache.as_ref().and_then(|c| c.try_load_query_result(tcx, id)) } } }; diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 94d4ad78e8..5b932864df 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -1,8 +1,35 @@ -use proc_macro::TokenStream; +//! Proc macro which builds the Symbol table +//! +//! # Debugging +//! +//! Since this proc-macro does some non-trivial work, debugging it is important. +//! This proc-macro can be invoked as an ordinary unit test, like so: +//! +//! ```bash +//! cd compiler/rustc_macros +//! cargo test symbols::test_symbols -- --nocapture +//! ``` +//! +//! This unit test finds the `symbols!` invocation in `compiler/rustc_span/src/symbol.rs` +//! and runs it. It verifies that the output token stream can be parsed as valid module +//! items and that no errors were produced. +//! +//! You can also view the generated code by using `cargo expand`: +//! +//! ```bash +//! cargo install cargo-expand # this is necessary only once +//! cd compiler/rustc_span +//! cargo expand > /tmp/rustc_span.rs # it's a big file +//! ``` + +use proc_macro2::{Span, TokenStream}; use quote::quote; -use std::collections::HashSet; +use std::collections::HashMap; use syn::parse::{Parse, ParseStream, Result}; -use syn::{braced, parse_macro_input, Ident, LitStr, Token}; +use syn::{braced, punctuated::Punctuated, Ident, LitStr, Token}; + +#[cfg(test)] +mod tests; mod kw { syn::custom_keyword!(Keywords); @@ -19,7 +46,6 @@ impl Parse for Keyword { let name = input.parse()?; input.parse::()?; let value = input.parse()?; - input.parse::()?; Ok(Keyword { name, value }) } @@ -37,28 +63,14 @@ impl Parse for Symbol { Ok(_) => Some(input.parse()?), Err(_) => None, }; - input.parse::()?; Ok(Symbol { name, value }) } } -/// A type used to greedily parse another type until the input is empty. -struct List(Vec); - -impl Parse for List { - fn parse(input: ParseStream<'_>) -> Result { - let mut list = Vec::new(); - while !input.is_empty() { - list.push(input.parse()?); - } - Ok(List(list)) - } -} - struct Input { - keywords: List, - symbols: List, + keywords: Punctuated, + symbols: Punctuated, } impl Parse for Input { @@ -66,115 +78,141 @@ impl Parse for Input { input.parse::()?; let content; braced!(content in input); - let keywords = content.parse()?; + let keywords = Punctuated::parse_terminated(&content)?; input.parse::()?; let content; braced!(content in input); - let symbols = content.parse()?; + let symbols = Punctuated::parse_terminated(&content)?; Ok(Input { keywords, symbols }) } } +#[derive(Default)] +struct Errors { + list: Vec, +} + +impl Errors { + fn error(&mut self, span: Span, message: String) { + self.list.push(syn::Error::new(span, message)); + } +} + pub fn symbols(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as Input); + let (mut output, errors) = symbols_with_errors(input); + + // If we generated any errors, then report them as compiler_error!() macro calls. + // This lets the errors point back to the most relevant span. It also allows us + // to report as many errors as we can during a single run. + output.extend(errors.into_iter().map(|e| e.to_compile_error())); + + output +} + +fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { + let mut errors = Errors::default(); + + let input: Input = match syn::parse2(input) { + Ok(input) => input, + Err(e) => { + // This allows us to display errors at the proper span, while minimizing + // unrelated errors caused by bailing out (and not generating code). + errors.list.push(e); + Input { keywords: Default::default(), symbols: Default::default() } + } + }; let mut keyword_stream = quote! {}; let mut symbols_stream = quote! {}; - let mut digits_stream = quote! {}; let mut prefill_stream = quote! {}; let mut counter = 0u32; - let mut keys = HashSet::::new(); - let mut prev_key: Option = None; - let mut errors = Vec::::new(); - - let mut check_dup = |str: &str, errors: &mut Vec| { - if !keys.insert(str.to_string()) { - errors.push(format!("Symbol `{}` is duplicated", str)); + let mut keys = + HashMap::::with_capacity(input.keywords.len() + input.symbols.len() + 10); + let mut prev_key: Option<(Span, String)> = None; + + let mut check_dup = |span: Span, str: &str, errors: &mut Errors| { + if let Some(prev_span) = keys.get(str) { + errors.error(span, format!("Symbol `{}` is duplicated", str)); + errors.error(*prev_span, format!("location of previous definition")); + } else { + keys.insert(str.to_string(), span); } }; - let mut check_order = |str: &str, errors: &mut Vec| { - if let Some(ref prev_str) = prev_key { + let mut check_order = |span: Span, str: &str, errors: &mut Errors| { + if let Some((prev_span, ref prev_str)) = prev_key { if str < prev_str { - errors.push(format!("Symbol `{}` must precede `{}`", str, prev_str)); + errors.error(span, format!("Symbol `{}` must precede `{}`", str, prev_str)); + errors.error(prev_span, format!("location of previous symbol `{}`", prev_str)); } } - prev_key = Some(str.to_string()); + prev_key = Some((span, str.to_string())); }; // Generate the listed keywords. - for keyword in &input.keywords.0 { + for keyword in input.keywords.iter() { let name = &keyword.name; let value = &keyword.value; - check_dup(&value.value(), &mut errors); + let value_string = value.value(); + check_dup(keyword.name.span(), &value_string, &mut errors); prefill_stream.extend(quote! { #value, }); keyword_stream.extend(quote! { - #[allow(non_upper_case_globals)] pub const #name: Symbol = Symbol::new(#counter); }); counter += 1; } // Generate the listed symbols. - for symbol in &input.symbols.0 { + for symbol in input.symbols.iter() { let name = &symbol.name; let value = match &symbol.value { Some(value) => value.value(), None => name.to_string(), }; - check_dup(&value, &mut errors); - check_order(&name.to_string(), &mut errors); + check_dup(symbol.name.span(), &value, &mut errors); + check_order(symbol.name.span(), &name.to_string(), &mut errors); + prefill_stream.extend(quote! { #value, }); symbols_stream.extend(quote! { - #[allow(rustc::default_hash_types)] - #[allow(non_upper_case_globals)] pub const #name: Symbol = Symbol::new(#counter); }); counter += 1; } // Generate symbols for the strings "0", "1", ..., "9". + let digits_base = counter; + counter += 10; for n in 0..10 { let n = n.to_string(); - check_dup(&n, &mut errors); + check_dup(Span::call_site(), &n, &mut errors); prefill_stream.extend(quote! { #n, }); - digits_stream.extend(quote! { - Symbol::new(#counter), - }); - counter += 1; } + let _ = counter; // for future use - if !errors.is_empty() { - for error in errors.into_iter() { - eprintln!("error: {}", error) - } - panic!("errors in `Keywords` and/or `Symbols`"); - } + let output = quote! { + const SYMBOL_DIGITS_BASE: u32 = #digits_base; - let tt = TokenStream::from(quote! { - macro_rules! keywords { - () => { - #keyword_stream - } + #[doc(hidden)] + #[allow(non_upper_case_globals)] + mod kw_generated { + use super::Symbol; + #keyword_stream } - macro_rules! define_symbols { - () => { - #symbols_stream - - #[allow(non_upper_case_globals)] - pub const digits_array: &[Symbol; 10] = &[ - #digits_stream - ]; - } + #[allow(rustc::default_hash_types)] + #[allow(non_upper_case_globals)] + #[doc(hidden)] + pub mod sym_generated { + use super::Symbol; + #symbols_stream } impl Interner { @@ -184,11 +222,16 @@ pub fn symbols(input: TokenStream) -> TokenStream { ]) } } - }); + }; - // To see the generated code generated, uncomment this line, recompile, and - // run the resulting output through `rustfmt`. - //eprintln!("{}", tt); + (output, errors.list) - tt + // To see the generated code, use the "cargo expand" command. + // Do this once to install: + // cargo install cargo-expand + // + // Then, cd to rustc_span and run: + // cargo expand > /tmp/rustc_span_expanded.rs + // + // and read that file. } diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs new file mode 100644 index 0000000000..82b4b87697 --- /dev/null +++ b/compiler/rustc_macros/src/symbols/tests.rs @@ -0,0 +1,102 @@ +use super::*; + +// This test is mainly here for interactive development. Use this test while +// you're working on the proc-macro defined in this file. +#[test] +fn test_symbols() { + // We textually include the symbol.rs file, which contains the list of all + // symbols, keywords, and common words. Then we search for the + // `symbols! { ... }` call. + + static SYMBOL_RS_FILE: &str = include_str!("../../../rustc_span/src/symbol.rs"); + + let file = syn::parse_file(SYMBOL_RS_FILE).unwrap(); + let symbols_path: syn::Path = syn::parse_quote!(symbols); + + let m: &syn::ItemMacro = file + .items + .iter() + .filter_map(|i| { + if let syn::Item::Macro(m) = i { + if m.mac.path == symbols_path { Some(m) } else { None } + } else { + None + } + }) + .next() + .expect("did not find `symbols!` macro invocation."); + + let body_tokens = m.mac.tokens.clone(); + + test_symbols_macro(body_tokens, &[]); +} + +fn test_symbols_macro(input: TokenStream, expected_errors: &[&str]) { + let (output, found_errors) = symbols_with_errors(input); + + // It should always parse. + let _parsed_file = syn::parse2::(output).unwrap(); + + assert_eq!( + found_errors.len(), + expected_errors.len(), + "Macro generated a different number of errors than expected" + ); + + for (found_error, &expected_error) in found_errors.iter().zip(expected_errors.iter()) { + let found_error_str = format!("{}", found_error); + assert_eq!(found_error_str, expected_error); + } +} + +#[test] +fn check_dup_keywords() { + let input = quote! { + Keywords { + Crate: "crate", + Crate: "crate", + } + Symbols {} + }; + test_symbols_macro(input, &["Symbol `crate` is duplicated", "location of previous definition"]); +} + +#[test] +fn check_dup_symbol() { + let input = quote! { + Keywords {} + Symbols { + splat, + splat, + } + }; + test_symbols_macro(input, &["Symbol `splat` is duplicated", "location of previous definition"]); +} + +#[test] +fn check_dup_symbol_and_keyword() { + let input = quote! { + Keywords { + Splat: "splat", + } + Symbols { + splat, + } + }; + test_symbols_macro(input, &["Symbol `splat` is duplicated", "location of previous definition"]); +} + +#[test] +fn check_symbol_order() { + let input = quote! { + Keywords {} + Symbols { + zebra, + aardvark, + } + }; + test_symbols_macro( + input, + &["Symbol `aardvark` must precede `zebra`", "location of previous symbol `zebra`"], + ); +} diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 8fa6e6a710..082af087bf 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -6,6 +6,12 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: } s.add_bounds(synstructure::AddBounds::Generics); + let body_visit = s.each(|bind| { + quote! { + ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?; + } + }); + s.bind_with(|_| synstructure::BindStyle::Move); let body_fold = s.each_variant(|vi| { let bindings = vi.bindings(); vi.construct(|_, index| { @@ -16,26 +22,20 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: }) }); - let body_visit = s.each(|bind| { - quote! { - ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?; - } - }); - s.bound_impl( quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>), quote! { fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>( - &self, + self, __folder: &mut __F ) -> Self { - match *self { #body_fold } + match self { #body_fold } } fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>( &self, __folder: &mut __F - ) -> ::std::ops::ControlFlow<()> { + ) -> ::std::ops::ControlFlow<__F::BreakTy> { match *self { #body_visit } ::std::ops::ControlFlow::CONTINUE } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 33cbf0fb23..019ca5174a 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -706,7 +706,7 @@ impl<'a> CrateLoader<'a> { self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); } - fn inject_profiler_runtime(&mut self) { + fn inject_profiler_runtime(&mut self, krate: &ast::Crate) { if (self.sess.opts.debugging_opts.instrument_coverage || self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled()) @@ -714,6 +714,13 @@ impl<'a> CrateLoader<'a> { { info!("loading profiler"); + if self.sess.contains_name(&krate.attrs, sym::no_core) { + self.sess.err( + "`profiler_builtins` crate (required by compiler options) \ + is not compatible with crate attribute `#![no_core]`", + ); + } + let name = sym::profiler_builtins; let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None); let data = self.cstore.get_crate_data(cnum); @@ -879,7 +886,7 @@ impl<'a> CrateLoader<'a> { } pub fn postprocess(&mut self, krate: &ast::Crate) { - self.inject_profiler_runtime(); + self.inject_profiler_runtime(krate); self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs index 8675197656..4785b6c379 100644 --- a/compiler/rustc_metadata/src/foreign_modules.rs +++ b/compiler/rustc_metadata/src/foreign_modules.rs @@ -16,13 +16,13 @@ struct Collector<'tcx> { impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { - let fm = match it.kind { - hir::ItemKind::ForeignMod(ref fm) => fm, + let items = match it.kind { + hir::ItemKind::ForeignMod { items, .. } => items, _ => return, }; let foreign_items = - fm.items.iter().map(|it| self.tcx.hir().local_def_id(it.hir_id).to_def_id()).collect(); + items.iter().map(|it| self.tcx.hir().local_def_id(it.id.hir_id).to_def_id()).collect(); self.modules.push(ForeignModule { foreign_items, def_id: self.tcx.hir().local_def_id(it.hir_id).to_def_id(), @@ -31,4 +31,5 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {} + fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {} } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 77766be739..2560cfa746 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,5 +1,4 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] diff --git a/compiler/rustc_metadata/src/link_args.rs b/compiler/rustc_metadata/src/link_args.rs index d8f1679608..d088288c50 100644 --- a/compiler/rustc_metadata/src/link_args.rs +++ b/compiler/rustc_metadata/src/link_args.rs @@ -26,11 +26,11 @@ struct Collector<'tcx> { impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { - let fm = match it.kind { - hir::ItemKind::ForeignMod(ref fm) => fm, + let abi = match it.kind { + hir::ItemKind::ForeignMod { abi, .. } => abi, _ => return, }; - if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic { + if abi == Abi::Rust || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { return; } @@ -45,6 +45,7 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {} + fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {} } impl<'tcx> Collector<'tcx> { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 2f7c2c2c40..fe29f9d177 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -33,12 +33,12 @@ struct Collector<'tcx> { impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { - let fm = match it.kind { - hir::ItemKind::ForeignMod(ref fm) => fm, + let abi = match it.kind { + hir::ItemKind::ForeignMod { abi, .. } => abi, _ => return, }; - if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic { + if abi == Abi::Rust || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { return; } @@ -127,6 +127,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {} + fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {} } impl Collector<'tcx> { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 746c3b6af1..43f7b2a992 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -77,6 +77,10 @@ crate struct CrateMetadata { raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. source_map_import_info: OnceCell>, + /// For every definition in this crate, maps its `DefPathHash` to its + /// `DefIndex`. See `raw_def_id_to_def_id` for more details about how + /// this is used. + def_path_hash_map: OnceCell>, /// Used for decoding interpret::AllocIds in a cached & thread-safe manner. alloc_decoding_state: AllocDecodingState, /// The `DepNodeIndex` of the `DepNode` representing this upstream crate. @@ -644,6 +648,7 @@ impl EntryKind { EntryKind::TraitAlias => DefKind::TraitAlias, EntryKind::Enum(..) => DefKind::Enum, EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang), + EntryKind::ProcMacro(kind) => DefKind::Macro(kind), EntryKind::ForeignType => DefKind::ForeignTy, EntryKind::Impl(_) => DefKind::Impl, EntryKind::Closure => DefKind::Closure, @@ -685,20 +690,11 @@ impl CrateRoot<'_> { } impl<'a, 'tcx> CrateMetadataRef<'a> { - fn is_proc_macro(&self, id: DefIndex) -> bool { - self.root - .proc_macro_data - .as_ref() - .and_then(|data| data.macros.decode(self).find(|x| *x == id)) - .is_some() - } - fn maybe_kind(&self, item_id: DefIndex) -> Option { self.root.tables.kind.get(self, item_id).map(|k| k.decode(self)) } fn kind(&self, item_id: DefIndex) -> EntryKind { - assert!(!self.is_proc_macro(item_id)); self.maybe_kind(item_id).unwrap_or_else(|| { bug!( "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}", @@ -725,35 +721,24 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident { - if !self.is_proc_macro(item_index) { - let name = self - .def_key(item_index) - .disambiguated_data - .data - .get_opt_name() - .expect("no name in item_ident"); - let span = self - .root - .tables - .ident_span - .get(self, item_index) - .map(|data| data.decode((self, sess))) - .unwrap_or_else(|| panic!("Missing ident span for {:?} ({:?})", name, item_index)); - Ident::new(name, span) - } else { - Ident::new( - Symbol::intern(self.raw_proc_macro(item_index).name()), - self.get_span(item_index, sess), - ) - } + let name = self + .def_key(item_index) + .disambiguated_data + .data + .get_opt_name() + .expect("no name in item_ident"); + let span = self + .root + .tables + .ident_span + .get(self, item_index) + .map(|data| data.decode((self, sess))) + .unwrap_or_else(|| panic!("Missing ident span for {:?} ({:?})", name, item_index)); + Ident::new(name, span) } fn def_kind(&self, index: DefIndex) -> DefKind { - if !self.is_proc_macro(index) { - self.kind(index).def_kind() - } else { - DefKind::Macro(macro_kind(self.raw_proc_macro(index))) - } + self.kind(index).def_kind() } fn get_span(&self, index: DefIndex, sess: &Session) -> Span { @@ -784,6 +769,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } }; + let attrs: Vec<_> = self.get_item_attrs(id, sess).collect(); SyntaxExtension::new( sess, kind, @@ -791,7 +777,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { helper_attrs, self.root.edition, Symbol::intern(name), - &self.get_item_attrs(id, sess), + &attrs, ) } @@ -946,14 +932,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - self.root.tables.ty.get(self, id).unwrap().decode((self, tcx)) + self.root + .tables + .ty + .get(self, id) + .unwrap_or_else(|| panic!("Not a type: {:?}", id)) + .decode((self, tcx)) } fn get_stability(&self, id: DefIndex) -> Option { - match self.is_proc_macro(id) { - true => self.root.proc_macro_data.as_ref().unwrap().stability, - false => self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)), - } + self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)) } fn get_const_stability(&self, id: DefIndex) -> Option { @@ -961,19 +949,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_deprecation(&self, id: DefIndex) -> Option { - self.root - .tables - .deprecation - .get(self, id) - .filter(|_| !self.is_proc_macro(id)) - .map(|depr| depr.decode(self)) + self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self)) } fn get_visibility(&self, id: DefIndex) -> ty::Visibility { - match self.is_proc_macro(id) { - true => ty::Visibility::Public, - false => self.root.tables.visibility.get(self, id).unwrap().decode(self), - } + self.root.tables.visibility.get(self, id).unwrap().decode(self) } fn get_impl_data(&self, id: DefIndex) -> ImplData { @@ -1157,7 +1137,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // within the crate. We only need this for fictive constructors, // for other constructors correct visibilities // were already encoded in metadata. - let attrs = self.get_item_attrs(def_id.index, sess); + let attrs: Vec<_> = + self.get_item_attrs(def_id.index, sess).collect(); if sess.contains_name(&attrs, sym::non_exhaustive) { let crate_def_id = self.local_def_id(CRATE_DEF_INDEX); vis = ty::Visibility::Restricted(crate_def_id); @@ -1184,7 +1165,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn is_item_mir_available(&self, id: DefIndex) -> bool { - !self.is_proc_macro(id) && self.root.tables.mir.get(self, id).is_some() + self.root.tables.mir.get(self, id).is_some() } fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId { @@ -1200,7 +1181,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .mir .get(self, id) - .filter(|_| !self.is_proc_macro(id)) .unwrap_or_else(|| { bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id)) }) @@ -1216,7 +1196,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .mir_abstract_consts .get(self, id) - .filter(|_| !self.is_proc_macro(id)) .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } @@ -1225,7 +1204,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .unused_generic_params .get(self, id) - .filter(|_| !self.is_proc_macro(id)) .map(|params| params.decode(self)) .unwrap_or_default() } @@ -1235,7 +1213,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .promoted_mir .get(self, id) - .filter(|_| !self.is_proc_macro(id)) .unwrap_or_else(|| { bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id)) }) @@ -1283,8 +1260,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_item_variances(&self, id: DefIndex) -> Vec { - self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self).collect() + fn get_item_variances(&'a self, id: DefIndex) -> impl Iterator + 'a { + self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self) } fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind { @@ -1308,7 +1285,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Vec { + fn get_item_attrs( + &'a self, + node_id: DefIndex, + sess: &'a Session, + ) -> impl Iterator + 'a { // The attributes for a tuple struct/variant are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition @@ -1325,7 +1306,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .get(self, item_id) .unwrap_or_else(Lazy::empty) .decode((self, sess)) - .collect::>() } fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec> { @@ -1536,14 +1516,63 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { #[inline] fn def_key(&self, index: DefIndex) -> DefKey { - *self.def_key_cache.lock().entry(index).or_insert_with(|| { - let mut key = self.root.tables.def_keys.get(self, index).unwrap().decode(self); - if self.is_proc_macro(index) { - let name = self.raw_proc_macro(index).name(); - key.disambiguated_data.data = DefPathData::MacroNs(Symbol::intern(name)); + *self + .def_key_cache + .lock() + .entry(index) + .or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self)) + } + + /// Finds the corresponding `DefId` for the provided `DefPathHash`, if it exists. + /// This is used by incremental compilation to map a serialized `DefPathHash` to + /// its `DefId` in the current session. + /// Normally, only one 'main' crate will change between incremental compilation sessions: + /// all dependencies will be completely unchanged. In this case, we can avoid + /// decoding every `DefPathHash` in the crate, since the `DefIndex` from the previous + /// session will still be valid. If our 'guess' is wrong (the `DefIndex` no longer exists, + /// or has a different `DefPathHash`, then we need to decode all `DefPathHashes` to determine + /// the correct mapping). + fn def_path_hash_to_def_id( + &self, + krate: CrateNum, + index_guess: u32, + hash: DefPathHash, + ) -> Option { + let def_index_guess = DefIndex::from_u32(index_guess); + let old_hash = self + .root + .tables + .def_path_hashes + .get(self, def_index_guess) + .map(|lazy| lazy.decode(self)); + + // Fast path: the definition and its index is unchanged from the + // previous compilation session. There is no need to decode anything + // else + if old_hash == Some(hash) { + return Some(DefId { krate, index: def_index_guess }); + } + + let is_proc_macro = self.is_proc_macro_crate(); + + // Slow path: We need to find out the new `DefIndex` of the provided + // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash` + // stored in this crate. + let map = self.cdata.def_path_hash_map.get_or_init(|| { + let end_id = self.root.tables.def_path_hashes.size() as u32; + let mut map = FxHashMap::with_capacity_and_hasher(end_id as usize, Default::default()); + for i in 0..end_id { + let def_index = DefIndex::from_u32(i); + // There may be gaps in the encoded table if we're decoding a proc-macro crate + if let Some(hash) = self.root.tables.def_path_hashes.get(self, def_index) { + map.insert(hash.decode(self), def_index); + } else if !is_proc_macro { + panic!("Missing def_path_hashes entry for {:?}", def_index); + } } - key - }) + map + }); + map.get(&hash).map(|index| DefId { krate, index: *index }) } // Returns the path leading to the thing with this `id`. @@ -1568,23 +1597,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.def_path_hash_unlocked(index, &mut def_path_hashes) } - fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { - let mut def_path_hashes = self.def_path_hash_cache.lock(); - let mut def_index_to_data = |index| { - (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) - }; - if let Some(data) = &self.root.proc_macro_data { - std::iter::once(CRATE_DEF_INDEX) - .chain(data.macros.decode(self)) - .map(def_index_to_data) - .collect() - } else { - (0..self.num_def_ids()) - .map(|index| def_index_to_data(DefIndex::from_usize(index))) - .collect() - } - } - /// Get the `DepNodeIndex` corresponding this crate. The result of this /// method is cached in the `dep_node_index` field. fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { @@ -1824,6 +1836,7 @@ impl CrateMetadata { trait_impls, raw_proc_macros, source_map_import_info: OnceCell::new(), + def_path_hash_map: Default::default(), alloc_decoding_state, dep_node_index: AtomicCell::new(DepNodeIndex::INVALID), cnum, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index ddd85ab7aa..b7f2288521 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -138,7 +138,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, cdata.get_deprecation(def_id.index).map(DeprecationEntry::external) } item_attrs => { tcx.arena.alloc_from_iter( - cdata.get_item_attrs(def_id.index, tcx.sess).into_iter() + cdata.get_item_attrs(def_id.index, tcx.sess) ) } fn_arg_names => { cdata.get_fn_param_names(tcx, def_id.index) } rendered_const => { cdata.get_rendered_const(def_id.index) } @@ -415,11 +415,7 @@ impl CStore { let span = data.get_span(id.index, sess); - // Mark the attrs as used - let attrs = data.get_item_attrs(id.index, sess); - for attr in attrs.iter() { - sess.mark_attr_used(attr); - } + let attrs = data.get_item_attrs(id.index, sess).collect(); let ident = data.item_ident(id.index, sess); @@ -428,7 +424,7 @@ impl CStore { ident, id: ast::DUMMY_NODE_ID, span, - attrs: attrs.to_vec(), + attrs, kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), vis: ast::Visibility { span: span.shrink_to_lo(), @@ -460,6 +456,10 @@ impl CStore { pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) } + + pub fn num_def_ids(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() + } } impl CrateStore for CStore { @@ -502,12 +502,14 @@ impl CrateStore for CStore { self.get_crate_data(def.krate).def_path_hash(def.index) } - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)> { - self.get_crate_data(cnum).all_def_path_hashes_and_def_ids() - } - - fn num_def_ids(&self, cnum: CrateNum) -> usize { - self.get_crate_data(cnum).num_def_ids() + // See `CrateMetadataRef::def_path_hash_to_def_id` for more details + fn def_path_hash_to_def_id( + &self, + cnum: CrateNum, + index_guess: u32, + hash: DefPathHash, + ) -> Option { + self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash) } fn crates_untracked(&self) -> Vec { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a7cf1079b8..4dfe3e8487 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -9,6 +9,7 @@ use rustc_data_structures::sync::{join, Lrc}; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; use rustc_hir::lang_items; @@ -27,7 +28,7 @@ use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; -use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext}; +use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_target::abi::VariantIdx; @@ -318,10 +319,6 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { self.opaque.position() } - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn type_shorthands(&mut self) -> &mut FxHashMap, usize> { &mut self.type_shorthands } @@ -662,7 +659,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), - symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version, + symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(), crate_deps, dylib_dependency_formats, @@ -1225,7 +1222,7 @@ impl EncodeContext<'a, 'tcx> { hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.hir_id, m, &item.attrs); } - hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod, + hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod, hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm, hir::ItemKind::TyAlias(..) => EntryKind::Type, hir::ItemKind::OpaqueTy(..) => { @@ -1320,11 +1317,11 @@ impl EncodeContext<'a, 'tcx> { record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id)); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { - hir::ItemKind::ForeignMod(ref fm) => record!(self.tables.children[def_id] <- - fm.items + hir::ItemKind::ForeignMod { items, .. } => record!(self.tables.children[def_id] <- + items .iter() .map(|foreign_item| tcx.hir().local_def_id( - foreign_item.hir_id).local_def_index) + foreign_item.id.hir_id).local_def_index) ), hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <- self.tcx.adt_def(def_id).variants.iter().map(|v| { @@ -1539,12 +1536,41 @@ impl EncodeContext<'a, 'tcx> { // so we manually encode just the information that we need for proc_macro in &hir.krate().proc_macros { let id = proc_macro.owner.local_def_index; - let span = self.lazy(hir.span(*proc_macro)); + let mut name = hir.name(*proc_macro); + let span = hir.span(*proc_macro); // Proc-macros may have attributes like `#[allow_internal_unstable]`, // so downstream crates need access to them. - let attrs = self.lazy(hir.attrs(*proc_macro)); - self.tables.span.set(id, span); - self.tables.attributes.set(id, attrs); + let attrs = hir.attrs(*proc_macro); + let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) { + MacroKind::Bang + } else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) { + MacroKind::Attr + } else if let Some(attr) = tcx.sess.find_by_name(attrs, sym::proc_macro_derive) { + // This unwrap chain should have been checked by the proc-macro harness. + name = attr.meta_item_list().unwrap()[0] + .meta_item() + .unwrap() + .ident() + .unwrap() + .name; + MacroKind::Derive + } else { + bug!("Unknown proc-macro type for item {:?}", id); + }; + + let mut def_key = self.tcx.hir().def_key(proc_macro.owner); + def_key.disambiguated_data.data = DefPathData::MacroNs(name); + + let def_id = DefId::local(id); + record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind)); + record!(self.tables.attributes[def_id] <- attrs); + record!(self.tables.def_keys[def_id] <- def_key); + record!(self.tables.ident_span[def_id] <- span); + record!(self.tables.span[def_id] <- span); + record!(self.tables.visibility[def_id] <- ty::Visibility::Public); + if let Some(stability) = stability { + record!(self.tables.stability[def_id] <- stability); + } } Some(ProcMacroData { proc_macro_decls_static, stability, macros }) @@ -1836,7 +1862,7 @@ impl EncodeContext<'a, 'tcx> { | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) | hir::ItemKind::Mod(..) - | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::ExternCrate(..) | hir::ItemKind::Use(..) @@ -1913,6 +1939,8 @@ impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> { fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem<'v>) { // handled in `visit_item` above } + + fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {} } /// Used to prefetch queries which will be needed later by metadata encoding. @@ -1977,6 +2005,11 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> { hir::ImplItemKind::TyAlias(..) => (), } } + + fn visit_foreign_item(&self, _foreign_item: &'v hir::ForeignItem<'v>) { + // This should be kept in sync with `encode_info_for_foreign_item`. + // Foreign items contain no MIR. + } } // NOTE(eddyb) The following comment was preserved for posterity, even diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 2bd2019d3c..5360617890 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -20,6 +20,7 @@ use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; use rustc_session::CrateDisambiguator; use rustc_span::edition::Edition; +use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnId, Span}; use rustc_target::spec::{PanicStrategy, TargetTriple}; @@ -336,6 +337,7 @@ enum EntryKind { ForeignFn(Lazy), Mod(Lazy), MacroDef(Lazy), + ProcMacro(MacroKind), Closure, Generator(hir::GeneratorKind), Trait(Lazy), diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 3250f1830d..47b7768b41 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -30,3 +30,4 @@ chalk-ir = "0.36.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } measureme = "9.0.0" rustc_session = { path = "../rustc_session" } +rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index f6570cc95d..9a42bbe7ba 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -14,10 +14,10 @@ macro_rules! arena_types { [] layouts: rustc_target::abi::Layout, // AdtDef are interned and compared by address [] adt_def: rustc_middle::ty::AdtDef, - [] steal_mir: rustc_middle::ty::steal::Steal>, + [] steal_mir: rustc_data_structures::steal::Steal>, [decode] mir: rustc_middle::mir::Body<$tcx>, [] steal_promoted: - rustc_middle::ty::steal::Steal< + rustc_data_structures::steal::Steal< rustc_index::vec::IndexVec< rustc_middle::mir::Promoted, rustc_middle::mir::Body<$tcx> @@ -32,6 +32,7 @@ macro_rules! arena_types { [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<$tcx>, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, + [decode] code_region: rustc_middle::mir::coverage::CodeRegion, [] const_allocs: rustc_middle::mir::interpret::Allocation, // Required for the incremental on-disk cache [few] mir_keys: rustc_hir::def_id::DefIdSet, diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index a61b9af9ba..d954c8ab5f 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -193,6 +193,15 @@ macro_rules! define_dep_nodes { pub type DepNode = rustc_query_system::dep_graph::DepNode; + // We keep a lot of `DepNode`s in memory during compilation. It's not + // required that their size stay the same, but we don't want to change + // it inadvertently. This assert just ensures we're aware of any change. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + static_assert_size!(DepNode, 17); + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + static_assert_size!(DepNode, 24); + pub trait DepNodeExt: Sized { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a @@ -227,7 +236,7 @@ macro_rules! define_dep_nodes { debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); DepNode { kind, - hash: def_path_hash.0, + hash: def_path_hash.0.into(), } } @@ -243,8 +252,7 @@ macro_rules! define_dep_nodes { /// has been removed. fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option { if self.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() + tcx.queries.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())) } else { None } @@ -311,7 +319,17 @@ impl<'tcx> DepNodeParams> for DefId { } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { - tcx.def_path_hash(*self).0 + let hash = tcx.def_path_hash(*self); + // If this is a foreign `DefId`, store its current value + // in the incremental cache. When we decode the cache, + // we will use the old DefIndex as an initial guess for + // a lookup into the crate metadata. + if !self.is_local() { + if let Some(cache) = &tcx.queries.on_disk_cache { + cache.store_foreign_def_id_hash(*self, hash); + } + } + hash.0 } fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { @@ -350,7 +368,7 @@ impl<'tcx> DepNodeParams> for CrateNum { fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; - tcx.def_path_hash(def_id).0 + def_id.to_fingerprint(tcx) } fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 6697524279..728bfef9f4 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -91,6 +91,12 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { type DepKind = DepKind; type StableHashingContext = StableHashingContext<'tcx>; + fn register_reused_dep_node(&self, dep_node: &DepNode) { + if let Some(cache) = self.queries.on_disk_cache.as_ref() { + cache.register_reused_dep_node(*self, dep_node) + } + } + fn create_stable_hashing_context(&self) -> Self::StableHashingContext { TyCtxt::create_stable_hashing_context(*self) } @@ -164,11 +170,17 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { - self.queries.on_disk_cache.load_diagnostics(*self, prev_dep_node_index) + self.queries + .on_disk_cache + .as_ref() + .map(|c| c.load_diagnostics(*self, prev_dep_node_index)) + .unwrap_or_default() } fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec) { - self.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics) + if let Some(c) = self.queries.on_disk_cache.as_ref() { + c.store_diagnostics(dep_node_index, diagnostics) + } } fn store_diagnostics_for_anon_node( @@ -176,7 +188,9 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { dep_node_index: DepNodeIndex, diagnostics: ThinVec, ) { - self.queries.on_disk_cache.store_diagnostics_for_anon_node(dep_node_index, diagnostics) + if let Some(c) = self.queries.on_disk_cache.as_ref() { + c.store_diagnostics_for_anon_node(dep_node_index, diagnostics) + } } fn profiler(&self) -> &SelfProfilerRef { diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 516c9b6752..82cfca4f17 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -112,6 +112,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { items: _, trait_items: _, impl_items: _, + foreign_items: _, bodies: _, trait_impls: _, body_ids: _, @@ -319,6 +320,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.visit_impl_item(self.krate.impl_item(item_id)); } + fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { + self.visit_foreign_item(self.krate.foreign_item(foreign_id)); + } + fn visit_nested_body(&mut self, id: BodyId) { self.visit_body(self.krate.body(id)); } @@ -351,11 +356,17 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) { - self.insert(foreign_item.span, foreign_item.hir_id, Node::ForeignItem(foreign_item)); + fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { + debug_assert_eq!( + fi.hir_id.owner, + self.definitions.opt_hir_id_to_local_def_id(fi.hir_id).unwrap() + ); + self.with_dep_node_owner(fi.hir_id.owner, fi, |this, hash| { + this.insert_with_hash(fi.span, fi.hir_id, Node::ForeignItem(fi), hash); - self.with_parent(foreign_item.hir_id, |this| { - intravisit::walk_foreign_item(this, foreign_item); + this.with_parent(fi.hir_id, |this| { + intravisit::walk_foreign_item(this, fi); + }); }); } @@ -561,6 +572,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.visit_nested_impl_item(id); } + + fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef<'hir>) { + // Do not visit the duplicate information in ForeignItemRef. We want to + // map the actual nodes, not the duplicate ones in the *Ref. + let ForeignItemRef { id, ident: _, span: _, vis: _ } = *fi; + + self.visit_nested_foreign_item(id); + } } struct HirItemLike { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index d86e898719..598e28c1a3 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -47,7 +47,7 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { } } -fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> { +pub fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> { match &node { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) @@ -205,7 +205,7 @@ impl<'hir> Map<'hir> { ItemKind::TraitAlias(..) => DefKind::TraitAlias, ItemKind::ExternCrate(_) => DefKind::ExternCrate, ItemKind::Use(..) => DefKind::Use, - ItemKind::ForeignMod(..) => DefKind::ForeignMod, + ItemKind::ForeignMod { .. } => DefKind::ForeignMod, ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Impl { .. } => DefKind::Impl, }, @@ -309,6 +309,13 @@ impl<'hir> Map<'hir> { } } + pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { + match self.find(id.hir_id).unwrap() { + Node::ForeignItem(item) => item, + _ => bug!(), + } + } + pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap() } @@ -470,6 +477,10 @@ impl<'hir> Map<'hir> { for id in &module.impl_items { visitor.visit_impl_item(self.expect_impl_item(id.hir_id)); } + + for id in &module.foreign_items { + visitor.visit_foreign_item(self.expect_foreign_item(id.hir_id)); + } } /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. @@ -718,10 +729,11 @@ impl<'hir> Map<'hir> { let parent = self.get_parent_item(hir_id); if let Some(entry) = self.find_entry(parent) { if let Entry { - node: Node::Item(Item { kind: ItemKind::ForeignMod(ref nm), .. }), .. + node: Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }), + .. } = entry { - return nm.abi; + return *abi; } } bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent)) @@ -806,25 +818,34 @@ impl<'hir> Map<'hir> { /// Given a node ID, gets a list of attributes associated with the AST /// corresponding to the node-ID. pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { - let attrs = match self.find_entry(id).map(|entry| entry.node) { - Some(Node::Param(a)) => Some(&a.attrs[..]), - Some(Node::Local(l)) => Some(&l.attrs[..]), - Some(Node::Item(i)) => Some(&i.attrs[..]), - Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), - Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]), - Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]), - Some(Node::Variant(ref v)) => Some(&v.attrs[..]), - Some(Node::Field(ref f)) => Some(&f.attrs[..]), - Some(Node::Expr(ref e)) => Some(&*e.attrs), - Some(Node::Stmt(ref s)) => Some(s.kind.attrs(|id| self.item(id.id))), - Some(Node::Arm(ref a)) => Some(&*a.attrs), - Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), + let attrs = self.find_entry(id).map(|entry| match entry.node { + Node::Param(a) => &a.attrs[..], + Node::Local(l) => &l.attrs[..], + Node::Item(i) => &i.attrs[..], + Node::ForeignItem(fi) => &fi.attrs[..], + Node::TraitItem(ref ti) => &ti.attrs[..], + Node::ImplItem(ref ii) => &ii.attrs[..], + Node::Variant(ref v) => &v.attrs[..], + Node::Field(ref f) => &f.attrs[..], + Node::Expr(ref e) => &*e.attrs, + Node::Stmt(ref s) => s.kind.attrs(|id| self.item(id.id)), + Node::Arm(ref a) => &*a.attrs, + Node::GenericParam(param) => ¶m.attrs[..], // Unit/tuple structs/variants take the attributes straight from // the struct/variant definition. - Some(Node::Ctor(..)) => return self.attrs(self.get_parent_item(id)), - Some(Node::Crate(item)) => Some(&item.attrs[..]), - _ => None, - }; + Node::Ctor(..) => self.attrs(self.get_parent_item(id)), + Node::Crate(item) => &item.attrs[..], + Node::MacroDef(def) => def.attrs, + Node::AnonConst(..) + | Node::PathSegment(..) + | Node::Ty(..) + | Node::Pat(..) + | Node::Binding(..) + | Node::TraitRef(..) + | Node::Block(..) + | Node::Lifetime(..) + | Node::Visibility(..) => &[], + }); attrs.unwrap_or(&[]) } @@ -928,6 +949,10 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { self.impl_item(id) } + + fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { + self.foreign_item(id) + } } trait Named { @@ -1021,7 +1046,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { ItemKind::Const(..) => "const", ItemKind::Fn(..) => "fn", ItemKind::Mod(..) => "mod", - ItemKind::ForeignMod(..) => "foreign mod", + ItemKind::ForeignMod { .. } => "foreign mod", ItemKind::GlobalAsm(..) => "global asm", ItemKind::TyAlias(..) => "ty", ItemKind::OpaqueTy(..) => "opaque type", diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 5da4be4e98..1e2e9df88c 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -4,21 +4,43 @@ use crate::ty::Ty; use rustc_hir::HirId; use rustc_target::abi::VariantIdx; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub enum PlaceBase { - /// A temporary variable + /// A temporary variable. Rvalue, - /// A named `static` item + /// A named `static` item. StaticItem, - /// A named local variable + /// A named local variable. Local(HirId), - /// An upvar referenced by closure env + /// An upvar referenced by closure env. Upvar(ty::UpvarId), } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub enum ProjectionKind { - /// A dereference of a pointer, reference or `Box` of the given type + /// A dereference of a pointer, reference or `Box` of the given type. Deref, /// `B.F` where `B` is the base expression and `F` is @@ -36,19 +58,30 @@ pub enum ProjectionKind { Subslice, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub struct Projection<'tcx> { - /// Type after the projection is being applied. + /// Type after the projection is applied. pub ty: Ty<'tcx>, - /// Defines the type of access + /// Defines the kind of access made by the projection. pub kind: ProjectionKind, } /// A `Place` represents how a value is located in memory. /// -/// This is an HIR version of `mir::Place` -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +/// This is an HIR version of [`rustc_middle::mir::Place`]. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct Place<'tcx> { /// The type of the `PlaceBase` pub base_ty: Ty<'tcx>, @@ -60,13 +93,13 @@ pub struct Place<'tcx> { /// A `PlaceWithHirId` represents how a value is located in memory. /// -/// This is an HIR version of `mir::Place` -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +/// This is an HIR version of [`rustc_middle::mir::Place`]. +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct PlaceWithHirId<'tcx> { /// `HirId` of the expression or pattern producing this value. pub hir_id: HirId, - /// Information about the `Place` + /// Information about the `Place`. pub place: Place<'tcx>, } diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs index 8f15c99f95..573b514e84 100644 --- a/compiler/rustc_middle/src/ich/impls_ty.rs +++ b/compiler/rustc_middle/src/ich/impls_ty.rs @@ -70,16 +70,16 @@ impl<'a> HashStable> for ty::RegionKind { ty::ReEmpty(universe) => { universe.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrAnon(i)) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i) }) => { db.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrNamed(def_id, name)) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name) }) => { db.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrEnv) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv }) => { db.hash_stable(hcx, hasher); } ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { @@ -184,15 +184,6 @@ impl<'a> HashStable> for ty::FloatVid { } } -impl<'a, T> HashStable> for ty::steal::Steal -where - T: HashStable>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.borrow().hash_stable(hcx, hasher); - } -} - impl<'a> HashStable> for crate::middle::privacy::AccessLevels { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 1e15ae49a0..e106db38b2 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -40,7 +40,7 @@ pub struct Canonical<'tcx, V> { pub value: V, } -pub type CanonicalVarInfos<'tcx> = &'tcx List; +pub type CanonicalVarInfos<'tcx> = &'tcx List>; /// A set of values corresponding to the canonical variables from some /// `Canonical`. You can give these values to @@ -88,11 +88,11 @@ impl Default for OriginalQueryValues<'tcx> { /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] -pub struct CanonicalVarInfo { - pub kind: CanonicalVarKind, +pub struct CanonicalVarInfo<'tcx> { + pub kind: CanonicalVarKind<'tcx>, } -impl CanonicalVarInfo { +impl<'tcx> CanonicalVarInfo<'tcx> { pub fn universe(&self) -> ty::UniverseIndex { self.kind.universe() } @@ -113,7 +113,7 @@ impl CanonicalVarInfo { /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] -pub enum CanonicalVarKind { +pub enum CanonicalVarKind<'tcx> { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), @@ -132,10 +132,10 @@ pub enum CanonicalVarKind { Const(ty::UniverseIndex), /// A "placeholder" that represents "any const". - PlaceholderConst(ty::PlaceholderConst), + PlaceholderConst(ty::PlaceholderConst<'tcx>), } -impl CanonicalVarKind { +impl<'tcx> CanonicalVarKind<'tcx> { pub fn universe(self) -> ty::UniverseIndex { match self { CanonicalVarKind::Ty(kind) => match kind { @@ -286,13 +286,15 @@ impl<'tcx, V> Canonical<'tcx, V> { pub type QueryOutlivesConstraint<'tcx> = ty::Binder, Region<'tcx>>>; -CloneTypeFoldableAndLiftImpls! { - crate::infer::canonical::Certainty, - crate::infer::canonical::CanonicalVarInfo, - crate::infer::canonical::CanonicalVarKind, +TrivialTypeFoldableAndLiftImpls! { + for <'tcx> { + crate::infer::canonical::Certainty, + crate::infer::canonical::CanonicalVarInfo<'tcx>, + crate::infer::canonical::CanonicalVarKind<'tcx>, + } } -CloneTypeFoldableImpls! { +TrivialTypeFoldableImpls! { for <'tcx> { crate::infer::canonical::CanonicalVarInfos<'tcx>, } @@ -321,9 +323,10 @@ impl<'tcx> CanonicalVarValues<'tcx> { GenericArgKind::Type(..) => { tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() } - GenericArgKind::Lifetime(..) => tcx - .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))) - .into(), + GenericArgKind::Lifetime(..) => { + let br = ty::BoundRegion { kind: ty::BrAnon(i) }; + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() + } GenericArgKind::Const(ct) => tcx .mk_const(ty::Const { ty: ct.ty, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 4a1d5459d1..6ae83a7f66 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -8,7 +8,7 @@ //! - **MIR.** The "mid-level (M) intermediate representation (IR)" is //! defined in the `mir` module. This module contains only the //! *definition* of the MIR; the passes that transform and operate -//! on MIR are found in `librustc_mir` crate. +//! on MIR are found in `rustc_mir` crate. //! - **Types.** The internal representation of types used in rustc is //! defined in the `ty` module. This includes the **type context** //! (or `tcx`), which is the central context during most of @@ -51,6 +51,7 @@ #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] +#![feature(associated_type_defaults)] #![recursion_limit = "512"] #[macro_use] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 36ecd5b008..bd724a5830 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -5,15 +5,18 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; -use rustc_session::lint::{builtin, Level, Lint, LintId}; +use rustc_session::lint::{ + builtin::{self, FORBIDDEN_LINT_GROUPS}, + Level, Lint, LintId, +}; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; -use rustc_span::{Span, Symbol}; +use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; /// How a lint level was set. -#[derive(Clone, Copy, PartialEq, Eq, HashStable)] -pub enum LintSource { +#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)] +pub enum LintLevelSource { /// Lint is at the default level as declared /// in rustc or a plugin. Default, @@ -22,12 +25,31 @@ pub enum LintSource { Node(Symbol, Span, Option /* RFC 2383 reason */), /// Lint level was set by a command-line flag. - /// The provided `Level` is the level specified on the command line - - /// the actual level may be lower due to `--cap-lints` + /// The provided `Level` is the level specified on the command line. + /// (The actual level may be lower due to `--cap-lints`.) CommandLine(Symbol, Level), } -pub type LevelSource = (Level, LintSource); +impl LintLevelSource { + pub fn name(&self) -> Symbol { + match *self { + LintLevelSource::Default => symbol::kw::Default, + LintLevelSource::Node(name, _, _) => name, + LintLevelSource::CommandLine(name, _) => name, + } + } + + pub fn span(&self) -> Span { + match *self { + LintLevelSource::Default => DUMMY_SP, + LintLevelSource::Node(_, span, _) => span, + LintLevelSource::CommandLine(_, _) => DUMMY_SP, + } + } +} + +/// A tuple of a lint level and its source. +pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { pub list: Vec, @@ -68,7 +90,12 @@ impl LintLevelSets { // If we're about to issue a warning, check at the last minute for any // directives against the warnings "lint". If, for example, there's an // `allow(warnings)` in scope then we want to respect that instead. - if level == Level::Warn { + // + // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically + // triggers in cases (like #80988) where you have `forbid(warnings)`, + // and so if we turned that into an error, it'd defeat the purpose of the + // future compatibility warning. + if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) { let (warnings_level, warnings_src) = self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux); if let Some(configured_warning_level) = warnings_level { @@ -95,7 +122,7 @@ impl LintLevelSets { id: LintId, mut idx: u32, aux: Option<&FxHashMap>, - ) -> (Option, LintSource) { + ) -> (Option, LintLevelSource) { if let Some(specs) = aux { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); @@ -107,7 +134,7 @@ impl LintLevelSets { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); } - return (None, LintSource::Default); + return (None, LintLevelSource::Default); } LintSet::Node { ref specs, parent } => { if let Some(&(level, src)) = specs.get(&id) { @@ -195,7 +222,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd, ) { @@ -205,7 +232,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option, decorate: Box FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { @@ -256,14 +283,14 @@ pub fn struct_lint_level<'s, 'd>( let name = lint.name_lower(); match src { - LintSource::Default => { + LintLevelSource::Default => { sess.diag_note_once( &mut err, DiagnosticMessageId::from(lint), &format!("`#[{}({})]` on by default", level.as_str(), name), ); } - LintSource::CommandLine(lint_flag_val, orig_level) => { + LintLevelSource::CommandLine(lint_flag_val, orig_level) => { let flag = match orig_level { Level::Warn => "-W", Level::Deny => "-D", @@ -292,7 +319,7 @@ pub fn struct_lint_level<'s, 'd>( ); } } - LintSource::Node(lint_attr_name, src, reason) => { + LintLevelSource::Node(lint_attr_name, src, reason) => { if let Some(rationale) = reason { err.note(&rationale.as_str()); } diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 921086366b..c0f2a76c19 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -48,21 +48,21 @@ macro_rules! CloneLiftImpls { /// Used for types that are `Copy` and which **do not care arena /// allocated data** (i.e., don't need to be folded). #[macro_export] -macro_rules! CloneTypeFoldableImpls { +macro_rules! TrivialTypeFoldableImpls { (for <$tcx:lifetime> { $($ty:ty,)+ }) => { $( impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty { fn super_fold_with>( - &self, + self, _: &mut F ) -> $ty { - Clone::clone(self) + self } fn super_visit_with>( &self, _: &mut F) - -> ::std::ops::ControlFlow<()> + -> ::std::ops::ControlFlow { ::std::ops::ControlFlow::CONTINUE } @@ -71,7 +71,7 @@ macro_rules! CloneTypeFoldableImpls { }; ($($ty:ty,)+) => { - CloneTypeFoldableImpls! { + TrivialTypeFoldableImpls! { for <'tcx> { $($ty,)+ } @@ -80,9 +80,9 @@ macro_rules! CloneTypeFoldableImpls { } #[macro_export] -macro_rules! CloneTypeFoldableAndLiftImpls { +macro_rules! TrivialTypeFoldableAndLiftImpls { ($($t:tt)*) => { - CloneTypeFoldableImpls! { $($t)* } + TrivialTypeFoldableImpls! { $($t)* } CloneLiftImpls! { $($t)* } } } @@ -96,7 +96,7 @@ macro_rules! EnumTypeFoldableImpl { $(where $($wc)*)* { fn super_fold_with>( - &self, + self, folder: &mut V, ) -> Self { EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output()) @@ -105,7 +105,7 @@ macro_rules! EnumTypeFoldableImpl { fn super_visit_with>( &self, visitor: &mut V, - ) -> ::std::ops::ControlFlow<()> { + ) -> ::std::ops::ControlFlow { EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) } } diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index ae9e4d364d..6d2c43874b 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -189,8 +189,12 @@ pub trait CrateStore { fn def_kind(&self, def: DefId) -> DefKind; fn def_path(&self, def: DefId) -> DefPath; fn def_path_hash(&self, def: DefId) -> DefPathHash; - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>; - fn num_def_ids(&self, cnum: CrateNum) -> usize; + fn def_path_hash_to_def_id( + &self, + cnum: CrateNum, + index_guess: u32, + hash: DefPathHash, + ) -> Option; // "queries" used in resolve that aren't tracked for incremental compilation fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 41342764ba..61f850c2fc 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -43,8 +43,7 @@ fn update_limit( let value_span = attr .meta() - .and_then(|meta| meta.name_value_literal().cloned()) - .map(|lit| lit.span) + .and_then(|meta| meta.name_value_literal_span()) .unwrap_or(attr.span); let error_str = match e.kind() { diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 254b57a005..54188985d7 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -8,7 +8,9 @@ use rustc_macros::HashStable; use std::fmt; use std::hash::Hash; -// Accessibility levels, sorted in ascending order +/// Represents the levels of accessibility an item can have. +/// +/// The variants are sorted in ascending order of accessibility. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)] pub enum AccessLevel { /// Superset of `AccessLevel::Reachable` used to mark impl Trait items. @@ -18,13 +20,13 @@ pub enum AccessLevel { /// public, then type `T` is reachable. Its values can be obtained by other crates /// even if the type itself is not nameable. Reachable, - /// Public items + items accessible to other crates with help of `pub use` re-exports + /// Public items + items accessible to other crates with the help of `pub use` re-exports. Exported, - /// Items accessible to other crates directly, without help of re-exports + /// Items accessible to other crates directly, without the help of re-exports. Public, } -// Accessibility levels for reachable HIR nodes +/// Holds a map of accessibility levels for reachable HIR nodes. #[derive(Clone)] pub struct AccessLevels { pub map: FxHashMap, diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index d060549ca8..eb48198991 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -332,7 +332,7 @@ pub struct ScopeTree { pub struct YieldData { /// The `Span` of the yield. pub span: Span, - /// The number of expressions and patterns appearing before the `yield` in the body plus one. + /// The number of expressions and patterns appearing before the `yield` in the body, plus one. pub expr_and_pat_count: usize, pub source: hir::YieldSource, } @@ -449,9 +449,7 @@ impl ScopeTree { } /// Checks whether the given scope contains a `yield`. If so, - /// returns `Some((span, expr_count))` with the span of a yield we found and - /// the number of expressions and patterns appearing before the `yield` in the body + 1. - /// If there a are multiple yields in a scope, the one with the highest number is returned. + /// returns `Some(YieldData)`. If not, returns `None`. pub fn yield_in_scope(&self, scope: Scope) -> Option { self.yield_in_scope.get(&scope).cloned() } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 978f08927c..4f08057a7e 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ pub use self::StabilityLevel::*; use crate::ty::{self, TyCtxt}; -use rustc_ast::CRATE_NODE_ID; +use rustc_ast::NodeId; use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -132,37 +132,37 @@ pub fn report_unstable( /// Checks whether an item marked with `deprecated(since="X")` is currently /// deprecated (i.e., whether X is not greater than the current rustc version). pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool { - let since = if let Some(since) = since { - if is_since_rustc_version { - since - } else { - // We assume that the deprecation is in effect if it's not a - // rustc version. - return true; - } - } else { - // If since attribute is not set, then we're definitely in effect. - return true; - }; fn parse_version(ver: &str) -> Vec { // We ignore non-integer components of the version (e.g., "nightly"). ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() } - if let Some(rustc) = option_env!("CFG_RELEASE") { - let since: Vec = parse_version(&since); - let rustc: Vec = parse_version(rustc); - // We simply treat invalid `since` attributes as relating to a previous - // Rust version, thus always displaying the warning. - if since.len() != 3 { - return true; - } - since <= rustc - } else { - // By default, a deprecation warning applies to - // the current version of the compiler. - true + if !is_since_rustc_version { + // The `since` field doesn't have semantic purpose in the stable `deprecated` + // attribute, only in `rustc_deprecated`. + return true; } + + if let Some(since) = since { + if since == "TBD" { + return false; + } + + if let Some(rustc) = option_env!("CFG_RELEASE") { + let since: Vec = parse_version(&since); + let rustc: Vec = parse_version(rustc); + // We simply treat invalid `since` attributes as relating to a previous + // Rust version, thus always displaying the warning. + if since.len() != 3 { + return true; + } + return since <= rustc; + } + }; + + // Assume deprecation is in effect if "since" field is missing + // or if we can't determine the current Rust version. + true } pub fn deprecation_suggestion( @@ -182,19 +182,24 @@ pub fn deprecation_suggestion( } pub fn deprecation_message(depr: &Deprecation, kind: &str, path: &str) -> (String, &'static Lint) { - let (message, lint) = if deprecation_in_effect( - depr.is_since_rustc_version, - depr.since.map(Symbol::as_str).as_deref(), - ) { + let since = depr.since.map(Symbol::as_str); + let (message, lint) = if deprecation_in_effect(depr.is_since_rustc_version, since.as_deref()) { (format!("use of deprecated {} `{}`", kind, path), DEPRECATED) } else { ( - format!( - "use of {} `{}` that will be deprecated in future version {}", - kind, - path, - depr.since.unwrap() - ), + if since.as_deref() == Some("TBD") { + format!( + "use of {} `{}` that will be deprecated in a future Rust version", + kind, path + ) + } else { + format!( + "use of {} `{}` that will be deprecated in future version {}", + kind, + path, + since.unwrap() + ) + }, DEPRECATED_IN_FUTURE, ) }; @@ -211,13 +216,14 @@ pub fn early_report_deprecation( suggestion: Option, lint: &'static Lint, span: Span, + node_id: NodeId, ) { if span.in_derive_expansion() { return; } let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span); - lint_buffer.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag); + lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag); } fn late_report_deprecation( diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 6b46d7c497..8a6bf9dff7 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -21,9 +21,9 @@ rustc_index::newtype_index! { impl ExpressionOperandId { /// An expression operand for a "zero counter", as described in the following references: /// - /// * - /// * - /// * + /// * + /// * + /// * /// /// This operand can be used to count two or more separate code regions with a single counter, /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e35ff6b996..397d2ffd56 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -29,7 +29,7 @@ impl From for ErrorHandled { } } -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { ErrorHandled, } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bcf8579731..80b5864213 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -132,7 +132,6 @@ pub use self::pointer::{Pointer, PointerArithmetic}; /// Uniquely identifies one of the following: /// - A constant /// - A static -/// - A const fn where all arguments (if any) are zero-sized types #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, Lift)] pub struct GlobalId<'tcx> { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index f366681bc7..0517ec5bb1 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -67,7 +67,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(¶m_env.and(cid)); + let inputs = self.erase_regions(param_env.and(cid)); if let Some(span) = span { self.at(span).eval_to_const_value_raw(inputs) } else { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5fe7b0f647..ad48c35104 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -420,7 +420,9 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all /// locals that are neither arguments nor the return place). #[inline] - pub fn vars_and_temps_iter(&self) -> impl Iterator + ExactSizeIterator { + pub fn vars_and_temps_iter( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { let arg_count = self.arg_count; let local_count = self.local_decls.len(); (arg_count + 1..local_count).map(Local::new) @@ -742,7 +744,7 @@ pub enum ImplicitSelfKind { None, } -CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } +TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } mod binding_form_impl { use crate::ich::StableHashingContext; @@ -809,7 +811,7 @@ pub struct LocalDecl<'tcx> { /// after typeck. /// /// This should be sound because the drop flags are fully algebraic, and - /// therefore don't affect the OIBIT or outlives properties of the + /// therefore don't affect the auto-trait or outlives properties of the /// generator. pub internal: bool, @@ -1058,6 +1060,23 @@ impl<'tcx> LocalDecl<'tcx> { } } +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +pub enum VarDebugInfoContents<'tcx> { + /// NOTE(eddyb) There's an unenforced invariant that this `Place` is + /// based on a `Local`, not a `Static`, and contains no indexing. + Place(Place<'tcx>), + Const(Constant<'tcx>), +} + +impl<'tcx> Debug for VarDebugInfoContents<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + match self { + VarDebugInfoContents::Const(c) => write!(fmt, "{}", c), + VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p), + } + } +} + /// Debug information pertaining to a user variable. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] pub struct VarDebugInfo<'tcx> { @@ -1069,9 +1088,7 @@ pub struct VarDebugInfo<'tcx> { pub source_info: SourceInfo, /// Where the data for this user variable is to be found. - /// NOTE(eddyb) There's an unenforced invariant that this `Place` is - /// based on a `Local`, not a `Static`, and contains no indexing. - pub place: Place<'tcx>, + pub value: VarDebugInfoContents<'tcx>, } /////////////////////////////////////////////////////////////////////////// @@ -1739,6 +1756,21 @@ impl<'tcx> Place<'tcx> { pub fn as_ref(&self) -> PlaceRef<'tcx> { PlaceRef { local: self.local, projection: &self.projection } } + + /// Iterate over the projections in evaluation order, i.e., the first element is the base with + /// its projection and then subsequently more projections are added. + /// As a concrete example, given the place a.b.c, this would yield: + /// - (a, .b) + /// - (a.b, .c) + /// Given a place without projections, the iterator is empty. + pub fn iter_projections( + self, + ) -> impl Iterator, PlaceElem<'tcx>)> + DoubleEndedIterator { + self.projection.iter().enumerate().map(move |(i, proj)| { + let base = PlaceRef { local: self.local, projection: &self.projection[..i] }; + (base, proj) + }) + } } impl From for Place<'_> { @@ -2452,32 +2484,20 @@ impl UserTypeProjection { } } -CloneTypeFoldableAndLiftImpls! { ProjectionKind, } +TrivialTypeFoldableAndLiftImpls! { ProjectionKind, } impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { - fn super_fold_with>(&self, folder: &mut F) -> Self { - use crate::mir::ProjectionElem::*; - - let base = self.base.fold_with(folder); - let projs: Vec<_> = self - .projs - .iter() - .map(|&elem| match elem { - Deref => Deref, - Field(f, ()) => Field(f, ()), - Index(()) => Index(()), - Downcast(symbol, variantidx) => Downcast(symbol, variantidx), - ConstantIndex { offset, min_length, from_end } => { - ConstantIndex { offset, min_length, from_end } - } - Subslice { from, to, from_end } => Subslice { from, to, from_end }, - }) - .collect(); - - UserTypeProjection { base, projs } + fn super_fold_with>(self, folder: &mut F) -> Self { + UserTypeProjection { + base: self.base.fold_with(folder), + projs: self.projs.fold_with(folder), + } } - fn super_visit_with>(&self, visitor: &mut Vs) -> ControlFlow<()> { + fn super_visit_with>( + &self, + visitor: &mut Vs, + ) -> ControlFlow { self.base.visit_with(visitor) // Note: there's nothing in `self.proj` to visit. } diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs index a8b7488335..fd6bb76dc4 100644 --- a/compiler/rustc_middle/src/mir/predecessors.rs +++ b/compiler/rustc_middle/src/mir/predecessors.rs @@ -75,6 +75,6 @@ impl HashStable for PredecessorCache { } } -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { PredecessorCache, } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 6022194342..89a93096f1 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -46,7 +46,7 @@ pub enum UnsafetyViolationDetails { UseOfMutableStatic, UseOfExternStatic, DerefOfRawPointer, - AssignToNonCopyUnionField, + AssignToDroppingUnionField, AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, @@ -94,8 +94,8 @@ impl UnsafetyViolationDetails { "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \ and cause data races: all of these are undefined behavior", ), - AssignToNonCopyUnionField => ( - "assignment to non-`Copy` union field", + AssignToDroppingUnionField => ( + "assignment to union field that might need dropping", "the previous content of the field will be dropped, which causes undefined \ behavior if the field was not properly initialized", ), @@ -233,14 +233,15 @@ pub struct BorrowCheckResult<'tcx> { /// The result of the `mir_const_qualif` query. /// -/// Each field corresponds to an implementer of the `Qualif` trait in -/// `librustc_mir/transform/check_consts/qualifs.rs`. See that file for more information on each +/// Each field (except `error_occured`) corresponds to an implementer of the `Qualif` trait in +/// `rustc_mir/src/transform/check_consts/qualifs.rs`. See that file for more information on each /// `Qualif`. #[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)] pub struct ConstQualifs { pub has_mut_interior: bool, pub needs_drop: bool, pub custom_eq: bool, + pub error_occured: Option, } /// After we borrow check a closure, we are left with various diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f0bfdae261..1b2c1076a6 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -136,6 +136,15 @@ impl<'tcx> Place<'tcx> { } } +impl<'tcx> PlaceRef<'tcx> { + pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + Place::ty_from(self.local, &self.projection, local_decls, tcx) + } +} + pub enum RvalueInitializationState { Shallow, Deep, diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 0801188b27..da8e189ba9 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -2,8 +2,9 @@ use super::*; use crate::ty; +use rustc_data_structures::functor::IdFunctor; -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { BlockTailInfo, MirPhase, SourceInfo, @@ -15,34 +16,33 @@ CloneTypeFoldableAndLiftImpls! { } impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { use crate::mir::TerminatorKind::*; let kind = match self.kind { Goto { target } => Goto { target }, - SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt { + SwitchInt { discr, switch_ty, targets } => SwitchInt { discr: discr.fold_with(folder), switch_ty: switch_ty.fold_with(folder), - targets: targets.clone(), + targets, }, - Drop { ref place, target, unwind } => { + Drop { place, target, unwind } => { Drop { place: place.fold_with(folder), target, unwind } } - DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace { + DropAndReplace { place, value, target, unwind } => DropAndReplace { place: place.fold_with(folder), value: value.fold_with(folder), target, unwind, }, - Yield { ref value, resume, ref resume_arg, drop } => Yield { + Yield { value, resume, resume_arg, drop } => Yield { value: value.fold_with(folder), resume, resume_arg: resume_arg.fold_with(folder), drop, }, - Call { ref func, ref args, ref destination, cleanup, from_hir_call, fn_span } => { - let dest = - destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); + Call { func, args, destination, cleanup, from_hir_call, fn_span } => { + let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest)); Call { func: func.fold_with(folder), @@ -53,17 +53,17 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { fn_span, } } - Assert { ref cond, expected, ref msg, target, cleanup } => { + Assert { cond, expected, msg, target, cleanup } => { use AssertKind::*; let msg = match msg { BoundsCheck { len, index } => { BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) } } - Overflow(op, l, r) => Overflow(*op, l.fold_with(folder), r.fold_with(folder)), + Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)), OverflowNeg(op) => OverflowNeg(op.fold_with(folder)), DivisionByZero(op) => DivisionByZero(op.fold_with(folder)), RemainderByZero(op) => RemainderByZero(op.fold_with(folder)), - ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg.clone(), + ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg, }; Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup } } @@ -76,7 +76,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { FalseEdge { real_target, imaginary_target } } FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, - InlineAsm { template, ref operands, options, line_spans, destination } => InlineAsm { + InlineAsm { template, operands, options, line_spans, destination } => InlineAsm { template, operands: operands.fold_with(folder), options, @@ -87,7 +87,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Terminator { source_info: self.source_info, kind } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { use crate::mir::TerminatorKind::*; match self.kind { @@ -140,61 +140,56 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { - fn super_fold_with>(&self, _: &mut F) -> Self { - *self + fn super_fold_with>(self, _: &mut F) -> Self { + self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.local.visit_with(visitor)?; self.projection.visit_with(visitor) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_place_elems(&v) + fn super_fold_with>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { use crate::mir::Rvalue::*; - match *self { - Use(ref op) => Use(op.fold_with(folder)), - Repeat(ref op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)), + match self { + Use(op) => Use(op.fold_with(folder)), + Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)), ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)), - Ref(region, bk, ref place) => { - Ref(region.fold_with(folder), bk, place.fold_with(folder)) - } - AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)), - Len(ref place) => Len(place.fold_with(folder)), - Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), - BinaryOp(op, ref rhs, ref lhs) => { - BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) - } - CheckedBinaryOp(op, ref rhs, ref lhs) => { + Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)), + AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)), + Len(place) => Len(place.fold_with(folder)), + Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), + BinaryOp(op, rhs, lhs) => BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + CheckedBinaryOp(op, rhs, lhs) => { CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) } - UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), - Discriminant(ref place) => Discriminant(place.fold_with(folder)), + UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)), + Discriminant(place) => Discriminant(place.fold_with(folder)), NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), - Aggregate(ref kind, ref fields) => { - let kind = box match **kind { + Aggregate(kind, fields) => { + let kind = kind.map_id(|kind| match kind { AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), AggregateKind::Tuple => AggregateKind::Tuple, AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt( @@ -210,13 +205,13 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Generator(id, substs, movablity) => { AggregateKind::Generator(id, substs.fold_with(folder), movablity) } - }; + }); Aggregate(kind, fields.fold_with(folder)) } } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { use crate::mir::Rvalue::*; match *self { Use(ref op) => op.visit_with(visitor), @@ -263,15 +258,15 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)), - Operand::Move(ref place) => Operand::Move(place.fold_with(folder)), - Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), + fn super_fold_with>(self, folder: &mut F) -> Self { + match self { + Operand::Copy(place) => Operand::Copy(place.fold_with(folder)), + Operand::Move(place) => Operand::Move(place.fold_with(folder)), + Operand::Constant(c) => Operand::Constant(c.fold_with(folder)), } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match *self { Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), Operand::Constant(ref c) => c.visit_with(visitor), @@ -280,10 +275,10 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { use crate::mir::ProjectionElem::*; - match *self { + match self { Deref => Deref, Field(f, ty) => Field(f, ty.fold_with(folder)), Index(v) => Index(v.fold_with(folder)), @@ -295,7 +290,10 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut Vs) -> ControlFlow<()> { + fn super_visit_with>( + &self, + visitor: &mut Vs, + ) -> ControlFlow { use crate::mir::ProjectionElem::*; match self { @@ -307,41 +305,41 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for Field { - fn super_fold_with>(&self, _: &mut F) -> Self { - *self + fn super_fold_with>(self, _: &mut F) -> Self { + self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { - fn super_fold_with>(&self, _: &mut F) -> Self { - *self + fn super_fold_with>(self, _: &mut F) -> Self { + self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix { - fn super_fold_with>(&self, _: &mut F) -> Self { - self.clone() + fn super_fold_with>(self, _: &mut F) -> Self { + self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { Constant { span: self.span, user_ty: self.user_ty.fold_with(folder), literal: self.literal.fold_with(folder), } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.literal.visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index d8d639ab73..e281010eb0 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1,70 +1,70 @@ +//! # The MIR Visitor +//! +//! ## Overview +//! +//! There are two visitors, one for immutable and one for mutable references, +//! but both are generated by the following macro. The code is written according +//! to the following conventions: +//! +//! - introduce a `visit_foo` and a `super_foo` method for every MIR type +//! - `visit_foo`, by default, calls `super_foo` +//! - `super_foo`, by default, destructures the `foo` and calls `visit_foo` +//! +//! This allows you as a user to override `visit_foo` for types are +//! interested in, and invoke (within that method) call +//! `self.super_foo` to get the default behavior. Just as in an OO +//! language, you should never call `super` methods ordinarily except +//! in that circumstance. +//! +//! For the most part, we do not destructure things external to the +//! MIR, e.g., types, spans, etc, but simply visit them and stop. This +//! avoids duplication with other visitors like `TypeFoldable`. +//! +//! ## Updating +//! +//! The code is written in a very deliberate style intended to minimize +//! the chance of things being overlooked. You'll notice that we always +//! use pattern matching to reference fields and we ensure that all +//! matches are exhaustive. +//! +//! For example, the `super_basic_block_data` method begins like this: +//! +//! ```rust +//! fn super_basic_block_data(&mut self, +//! block: BasicBlock, +//! data: & $($mutability)? BasicBlockData<'tcx>) { +//! let BasicBlockData { +//! statements, +//! terminator, +//! is_cleanup: _ +//! } = *data; +//! +//! for statement in statements { +//! self.visit_statement(block, statement); +//! } +//! +//! ... +//! } +//! ``` +//! +//! Here we used `let BasicBlockData { } = *data` deliberately, +//! rather than writing `data.statements` in the body. This is because if one +//! adds a new field to `BasicBlockData`, one will be forced to revise this code, +//! and hence one will (hopefully) invoke the correct visit methods (if any). +//! +//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. +//! That means you never write `..` to skip over fields, nor do you write `_` +//! to skip over variants in a `match`. +//! +//! The only place that `_` is acceptable is to match a field (or +//! variant argument) that does not require visiting, as in +//! `is_cleanup` above. + use crate::mir::*; use crate::ty::subst::SubstsRef; use crate::ty::{CanonicalUserTypeAnnotation, Ty}; use rustc_span::Span; -// # The MIR Visitor -// -// ## Overview -// -// There are two visitors, one for immutable and one for mutable references, -// but both are generated by the following macro. The code is written according -// to the following conventions: -// -// - introduce a `visit_foo` and a `super_foo` method for every MIR type -// - `visit_foo`, by default, calls `super_foo` -// - `super_foo`, by default, destructures the `foo` and calls `visit_foo` -// -// This allows you as a user to override `visit_foo` for types are -// interested in, and invoke (within that method) call -// `self.super_foo` to get the default behavior. Just as in an OO -// language, you should never call `super` methods ordinarily except -// in that circumstance. -// -// For the most part, we do not destructure things external to the -// MIR, e.g., types, spans, etc, but simply visit them and stop. This -// avoids duplication with other visitors like `TypeFoldable`. -// -// ## Updating -// -// The code is written in a very deliberate style intended to minimize -// the chance of things being overlooked. You'll notice that we always -// use pattern matching to reference fields and we ensure that all -// matches are exhaustive. -// -// For example, the `super_basic_block_data` method begins like this: -// -// ```rust -// fn super_basic_block_data(&mut self, -// block: BasicBlock, -// data: & $($mutability)? BasicBlockData<'tcx>) { -// let BasicBlockData { -// statements, -// terminator, -// is_cleanup: _ -// } = *data; -// -// for statement in statements { -// self.visit_statement(block, statement); -// } -// -// ... -// } -// ``` -// -// Here we used `let BasicBlockData { } = *data` deliberately, -// rather than writing `data.statements` in the body. This is because if one -// adds a new field to `BasicBlockData`, one will be forced to revise this code, -// and hence one will (hopefully) invoke the correct visit methods (if any). -// -// For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. -// That means you never write `..` to skip over fields, nor do you write `_` -// to skip over variants in a `match`. -// -// The only place that `_` is acceptable is to match a field (or -// variant argument) that does not require visiting, as in -// `is_cleanup` above. - macro_rules! make_mir_visitor { ($visitor_trait_name:ident, $($mutability:ident)?) => { pub trait $visitor_trait_name<'tcx> { @@ -254,7 +254,7 @@ macro_rules! make_mir_visitor { macro_rules! basic_blocks { (mut) => (body.basic_blocks_mut().iter_enumerated_mut()); () => (body.basic_blocks().iter_enumerated()); - }; + } for (bb, data) in basic_blocks!($($mutability)?) { self.visit_basic_block_data(bb, data); } @@ -275,7 +275,7 @@ macro_rules! make_mir_visitor { macro_rules! type_annotations { (mut) => (body.user_type_annotations.iter_enumerated_mut()); () => (body.user_type_annotations.iter_enumerated()); - }; + } for (index, annotation) in type_annotations!($($mutability)?) { self.visit_user_type_annotation( @@ -829,16 +829,20 @@ macro_rules! make_mir_visitor { let VarDebugInfo { name: _, source_info, - place, + value, } = var_debug_info; self.visit_source_info(source_info); let location = START_BLOCK.start_location(); - self.visit_place( - place, - PlaceContext::NonUse(NonUseContext::VarDebugInfo), - location, - ); + match value { + VarDebugInfoContents::Const(c) => self.visit_constant(c, location), + VarDebugInfoContents::Place(place) => + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ), + } } fn super_source_scope(&mut self, @@ -909,7 +913,7 @@ macro_rules! make_mir_visitor { macro_rules! basic_blocks { (mut) => (body.basic_blocks_mut()); () => (body.basic_blocks()); - }; + } let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block]; if basic_block.statements.len() == location.statement_index { if let Some(ref $($mutability)? terminator) = basic_block.terminator { @@ -1017,11 +1021,14 @@ macro_rules! visit_place_fns { let mut context = context; if !place.projection.is_empty() { - context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; + if context.is_use() { + // ^ Only change the context if it is a real use, not a "use" in debuginfo. + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; + } } self.visit_local(&place.local, context, location); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 72360e219e..1b5f7a2c12 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -130,8 +130,8 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { key.is_local() } load_cached(tcx, id) { - let generics: Option = tcx.queries.on_disk_cache - .try_load_query_result(tcx, id); + let generics: Option = tcx.queries.on_disk_cache.as_ref() + .and_then(|c| c.try_load_query_result(tcx, id)); generics } } @@ -346,6 +346,21 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + /// Returns the name of the file that contains the function body, if instrumented for coverage. + query covered_file_name(key: DefId) -> Option { + desc { |tcx| "retrieving the covered file name, if instrumented, for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + } + + /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the + /// function was optimized out before codegen, and before being added to the Coverage Map. + query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> { + desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + } + /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own /// `DefId`. This function returns all promoteds in the specified body. The body references /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because @@ -367,7 +382,7 @@ rustc_queries! { TypeChecking { /// Erases regions from `ty` to yield a new type. - /// Normally you would just use `tcx.erase_regions(&value)`, + /// Normally you would just use `tcx.erase_regions(value)`, /// however, which uses this query as a kind of cache. query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { // This query is not expected to have input -- as a result, it @@ -635,6 +650,10 @@ rustc_queries! { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } + query check_mod_naked_functions(key: LocalDefId) -> () { + desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } + } + query check_mod_item_types(key: LocalDefId) -> () { desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) } } @@ -688,8 +707,8 @@ rustc_queries! { cache_on_disk_if { true } load_cached(tcx, id) { let typeck_results: Option> = tcx - .queries.on_disk_cache - .try_load_query_result(tcx, id); + .queries.on_disk_cache.as_ref() + .and_then(|c| c.try_load_query_result(tcx, id)); typeck_results.map(|x| &*tcx.arena.alloc(x)) } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 4deb7225dc..0a663f793a 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -16,6 +16,7 @@ use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::Constness; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use smallvec::SmallVec; @@ -70,7 +71,7 @@ pub enum Reveal { /// be observable directly by the user, `Reveal::All` /// should not be used by checks which may expose /// type equality or type contents to the user. - /// There are some exceptions, e.g., around OIBITS and + /// There are some exceptions, e.g., around auto traits and /// transmute-checking, which expose some details, but /// not the whole concrete type of the `impl Trait`. All, @@ -457,7 +458,7 @@ pub enum ImplSource<'tcx, N> { /// for some type parameter. The `Vec` represents the /// obligations incurred from normalizing the where-clause (if /// any). - Param(Vec), + Param(Vec, Constness), /// Virtual calls through an object. Object(ImplSourceObjectData<'tcx, N>), @@ -487,7 +488,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec { match self { ImplSource::UserDefined(i) => i.nested, - ImplSource::Param(n) => n, + ImplSource::Param(n, _) => n, ImplSource::Builtin(i) => i.nested, ImplSource::AutoImpl(d) => d.nested, ImplSource::Closure(c) => c.nested, @@ -502,7 +503,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { pub fn borrow_nested_obligations(&self) -> &[N] { match &self { ImplSource::UserDefined(i) => &i.nested[..], - ImplSource::Param(n) => &n[..], + ImplSource::Param(n, _) => &n[..], ImplSource::Builtin(i) => &i.nested[..], ImplSource::AutoImpl(d) => &d.nested[..], ImplSource::Closure(c) => &c.nested[..], @@ -524,7 +525,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { substs: i.substs, nested: i.nested.into_iter().map(f).collect(), }), - ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()), + ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct), ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData { nested: i.nested.into_iter().map(f).collect(), }), diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index c570ad3273..e056240f94 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -101,7 +101,7 @@ pub enum SelectionCandidate<'tcx> { /// `false` if there are no *further* obligations. has_nested: bool, }, - ParamCandidate(ty::PolyTraitRef<'tcx>), + ParamCandidate(ty::ConstnessAnd>), ImplCandidate(DefId), AutoImplCandidate(DefId), diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index b8f6675b8e..5a17d38c73 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -21,7 +21,9 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { super::ImplSource::Object(ref d) => write!(f, "{:?}", d), - super::ImplSource::Param(ref n) => write!(f, "ImplSourceParamData({:?})", n), + super::ImplSource::Param(ref n, ct) => { + write!(f, "ImplSourceParamData({:?}, {:?})", n, ct) + } super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), @@ -105,7 +107,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, /////////////////////////////////////////////////////////////////////////// // Lift implementations -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { super::IfExpressionCause, super::ImplSourceDiscriminantKindData, } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 27bccc0bca..a5962e3b3b 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -118,6 +118,6 @@ impl TypeRelation<'tcx> for Match<'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } } diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index 3237147c8b..7ab192daf4 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -8,7 +8,7 @@ pub enum BindingMode { BindByValue(Mutability), } -CloneTypeFoldableAndLiftImpls! { BindingMode, } +TrivialTypeFoldableAndLiftImpls! { BindingMode, } impl BindingMode { pub fn convert(ba: BindingAnnotation) -> BindingMode { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index aaf6a85704..df59469021 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -69,7 +69,6 @@ impl OpaqueEncoder for rustc_serialize::opaque::Encoder { pub trait TyEncoder<'tcx>: Encoder { const CLEAR_CROSS_CRATE: bool; - fn tcx(&self) -> TyCtxt<'tcx>; fn position(&self) -> usize; fn type_shorthands(&mut self) -> &mut FxHashMap, usize>; fn predicate_shorthands(&mut self) -> &mut FxHashMap, usize>; @@ -162,7 +161,8 @@ encodable_via_deref! { ty::Region<'tcx>, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, - &'tcx mir::BorrowCheckResult<'tcx> + &'tcx mir::BorrowCheckResult<'tcx>, + &'tcx mir::coverage::CodeRegion } pub trait TyDecoder<'tcx>: Decoder { @@ -278,7 +278,7 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Region<'tcx> { impl<'tcx, D: TyDecoder<'tcx>> Decodable for CanonicalVarInfos<'tcx> { fn decode(decoder: &mut D) -> Result { let len = decoder.read_usize()?; - let interned: Result, _> = + let interned: Result>, _> = (0..len).map(|_| Decodable::decode(decoder)).collect(); Ok(decoder.tcx().intern_canonical_var_infos(interned?.as_slice())) } @@ -320,10 +320,14 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> + for ty::List>> +{ fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { let len = decoder.read_usize()?; - Ok(decoder.tcx().mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) + Ok(decoder + .tcx() + .mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) } } @@ -372,11 +376,12 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, - &'tcx ty::List>, + &'tcx ty::List>>, &'tcx Allocation, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, - &'tcx mir::BorrowCheckResult<'tcx> + &'tcx mir::BorrowCheckResult<'tcx>, + &'tcx mir::coverage::CodeRegion } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index ede2852200..ecf2837b3e 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -23,7 +23,7 @@ pub enum ConstKind<'tcx> { Bound(ty::DebruijnIndex, ty::BoundVar), /// A placeholder const - universally quantified higher-ranked const. - Placeholder(ty::PlaceholderConst), + Placeholder(ty::PlaceholderConst<'tcx>), /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other /// variants when the code is monomorphic enough for that. @@ -103,9 +103,9 @@ impl<'tcx> ConstKind<'tcx> { // so that we don't try to invoke this query with // any region variables. let param_env_and_substs = tcx - .erase_regions(¶m_env) + .erase_regions(param_env) .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(&substs)); + .and(tcx.erase_regions(substs)); // HACK(eddyb) when the query key would contain inference variables, // attempt using identity substs and `ParamEnv` instead, that will succeed diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7263d06b61..9b944f202a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,11 +1,11 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::{self, DepConstructor, DepGraph}; +use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt}; use crate::hir::exports::ExportMap; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource}; +use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle; use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata}; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; @@ -14,7 +14,6 @@ use crate::mir::interpret::{self, Allocation, ConstValue, Scalar}; use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::traits; use crate::ty::query::{self, TyCtxtAt}; -use crate::ty::steal::Steal; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::TyKind::*; use crate::ty::{ @@ -33,16 +32,19 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{ hash_stable_hashmap, HashStable, StableHasher, StableVec, }; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; -use rustc_data_structures::unhash::UnhashMap; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_hir::definitions::{DefPathHash, Definitions}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::definitions::Definitions; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; +use rustc_hir::{ + Constness, HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate, +}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; @@ -83,9 +85,9 @@ pub struct CtxtInterners<'tcx> { type_: InternedSet<'tcx, TyS<'tcx>>, type_list: InternedSet<'tcx, List>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, - canonical_var_infos: InternedSet<'tcx, List>, + canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind>, - existential_predicates: InternedSet<'tcx, List>>, + poly_existential_predicates: InternedSet<'tcx, List>>>, predicate: InternedSet<'tcx, PredicateInner<'tcx>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, @@ -101,7 +103,7 @@ impl<'tcx> CtxtInterners<'tcx> { type_list: Default::default(), substs: Default::default(), region: Default::default(), - existential_predicates: Default::default(), + poly_existential_predicates: Default::default(), canonical_var_infos: Default::default(), predicate: Default::default(), predicates: Default::default(), @@ -297,6 +299,7 @@ pub struct ResolvedOpaqueTy<'tcx> { /// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for /// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`. #[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] +#[derive(TypeFoldable)] pub struct GeneratorInteriorTypeCause<'tcx> { /// Type of the captured binding. pub ty: Ty<'tcx>, @@ -415,9 +418,13 @@ pub struct TypeckResults<'tcx> { /// entire variable. pub closure_captures: ty::UpvarListMap, + /// Tracks the minimum captures required for a closure; + /// see `MinCaptureInformationMap` for more details. + pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>, + /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). - pub generator_interior_types: Vec>, + pub generator_interior_types: ty::Binder>>, /// We sometimes treat byte string literals (which are of type `&[u8; N]`) /// as `&[u8]`, depending on the pattern in which they are used. @@ -448,7 +455,8 @@ impl<'tcx> TypeckResults<'tcx> { tainted_by_errors: None, concrete_opaque_types: Default::default(), closure_captures: Default::default(), - generator_interior_types: Default::default(), + closure_min_captures: Default::default(), + generator_interior_types: ty::Binder::dummy(Default::default()), treat_byte_string_as_slice: Default::default(), } } @@ -617,6 +625,19 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured + /// by the closure. + pub fn closure_min_captures_flattened( + &self, + closure_def_id: DefId, + ) -> impl Iterator> { + self.closure_min_captures + .get(&closure_def_id) + .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter())) + .into_iter() + .flatten() + } + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { self.upvar_capture_map[&upvar_id] } @@ -683,6 +704,7 @@ impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { tainted_by_errors, ref concrete_opaque_types, ref closure_captures, + ref closure_min_captures, ref generator_interior_types, ref treat_byte_string_as_slice, } = *self; @@ -717,6 +739,7 @@ impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { tainted_by_errors.hash_stable(hcx, hasher); concrete_opaque_types.hash_stable(hcx, hasher); closure_captures.hash_stable(hcx, hasher); + closure_min_captures.hash_stable(hcx, hasher); generator_interior_types.hash_stable(hcx, hasher); treat_byte_string_as_slice.hash_stable(hcx, hasher); }) @@ -867,7 +890,7 @@ pub struct FreeRegionInfo { // `LocalDefId` corresponding to FreeRegion pub def_id: LocalDefId, // the bound region corresponding to FreeRegion - pub boundregion: ty::BoundRegion, + pub boundregion: ty::BoundRegionKind, // checks if bound region is in Impl Item pub is_impl_item: bool, } @@ -936,10 +959,6 @@ pub struct GlobalCtxt<'tcx> { pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>, pub(crate) definitions: &'tcx Definitions, - /// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate - /// as well as all upstream crates. Only populated in incremental mode. - pub def_path_hash_to_def_id: Option>, - pub queries: query::Queries<'tcx>, maybe_unused_trait_imports: FxHashSet, @@ -1087,7 +1106,7 @@ impl<'tcx> TyCtxt<'tcx> { krate: &'tcx hir::Crate<'tcx>, definitions: &'tcx Definitions, dep_graph: DepGraph, - on_disk_query_result_cache: query::OnDiskCache<'tcx>, + on_disk_query_result_cache: Option>, crate_name: &str, output_filenames: &OutputFilenames, ) -> GlobalCtxt<'tcx> { @@ -1104,21 +1123,6 @@ impl<'tcx> TyCtxt<'tcx> { let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1); providers[LOCAL_CRATE] = local_providers; - let def_path_hash_to_def_id = if s.opts.build_dep_graph() { - let capacity = definitions.def_path_table().num_def_ids() - + crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::(); - let mut map = UnhashMap::with_capacity_and_hasher(capacity, Default::default()); - - map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE)); - for cnum in &crates { - map.extend(cstore.all_def_path_hashes_and_def_ids(*cnum).into_iter()); - } - - Some(map) - } else { - None - }; - let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); for (hir_id, v) in krate.trait_map.iter() { let map = trait_map.entry(hir_id.owner).or_default(); @@ -1146,7 +1150,6 @@ impl<'tcx> TyCtxt<'tcx> { extern_prelude: resolutions.extern_prelude, untracked_crate: krate, definitions, - def_path_hash_to_def_id, queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache), ty_rcache: Default::default(), pred_rcache: Default::default(), @@ -1320,7 +1323,8 @@ impl<'tcx> TyCtxt<'tcx> { // We cannot use the query versions of crates() and crate_hash(), since // those would need the DepNodes that we are allocating here. for cnum in self.cstore.crates_untracked() { - let dep_node = DepConstructor::CrateMetadata(self, cnum); + let def_path_hash = self.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }); + let dep_node = DepNode::from_def_path_hash(def_path_hash, DepKind::CrateMetadata); let crate_hash = self.cstore.crate_hash_untracked(cnum); self.dep_graph.with_task( dep_node, @@ -1336,7 +1340,7 @@ impl<'tcx> TyCtxt<'tcx> { where E: ty::codec::OpaqueEncoder, { - self.queries.on_disk_cache.serialize(self, encoder) + self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(())) } /// If `true`, we should use the MIR-based borrowck, but also @@ -1408,7 +1412,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Returns the `DefId` and the `BoundRegion` corresponding to the given region. + // Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { @@ -1416,7 +1420,7 @@ impl<'tcx> TyCtxt<'tcx> { } ty::ReEarlyBound(ref ebr) => ( self.parent(ebr.def_id).unwrap().expect_local(), - ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), + ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name), ), _ => return None, // not a free region }; @@ -1504,7 +1508,7 @@ impl<'tcx> TyCtxt<'tcx> { match ret_ty.kind() { ty::FnDef(_, _) => { let sig = ret_ty.fn_sig(self); - let output = self.erase_late_bound_regions(&sig.output()); + let output = self.erase_late_bound_regions(sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); Some((output, fn_decl.output.span())) @@ -1620,14 +1624,16 @@ nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} -nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} +nop_list_lift! {poly_existential_predicates; ty::Binder> => ty::Binder>} nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} -nop_list_lift! {canonical_var_infos; CanonicalVarInfo => CanonicalVarInfo} +nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} nop_list_lift! {projs; ProjectionKind => ProjectionKind} // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} +CloneLiftImpls! { for<'tcx> { Constness, } } + pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; @@ -2058,8 +2064,9 @@ macro_rules! slice_interners { slice_interners!( type_list: _intern_type_list(Ty<'tcx>), substs: _intern_substs(GenericArg<'tcx>), - canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo), - existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>), + canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>), + poly_existential_predicates: + _intern_poly_existential_predicates(ty::Binder>), predicates: _intern_predicates(Predicate<'tcx>), projs: _intern_projs(ProjectionKind), place_elems: _intern_place_elems(PlaceElem<'tcx>), @@ -2290,7 +2297,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_dynamic( self, - obj: ty::Binder<&'tcx List>>, + obj: &'tcx List>>, reg: ty::Region<'tcx>, ) -> Ty<'tcx> { self.mk_ty(Dynamic(obj, reg)) @@ -2420,13 +2427,17 @@ impl<'tcx> TyCtxt<'tcx> { Place { local: place.local, projection: self.intern_place_elems(&projection) } } - pub fn intern_existential_predicates( + pub fn intern_poly_existential_predicates( self, - eps: &[ExistentialPredicate<'tcx>], - ) -> &'tcx List> { + eps: &[ty::Binder>], + ) -> &'tcx List>> { assert!(!eps.is_empty()); - assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater)); - self._intern_existential_predicates(eps) + assert!( + eps.array_windows() + .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder()) + != Ordering::Greater) + ); + self._intern_poly_existential_predicates(eps) } pub fn intern_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List> { @@ -2457,7 +2468,10 @@ impl<'tcx> TyCtxt<'tcx> { if ts.is_empty() { List::empty() } else { self._intern_place_elems(ts) } } - pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> { + pub fn intern_canonical_var_infos( + self, + ts: &[CanonicalVarInfo<'tcx>], + ) -> CanonicalVarInfos<'tcx> { if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) } } @@ -2480,13 +2494,16 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn mk_existential_predicates< - I: InternAs<[ExistentialPredicate<'tcx>], &'tcx List>>, + pub fn mk_poly_existential_predicates< + I: InternAs< + [ty::Binder>], + &'tcx List>>, + >, >( self, iter: I, ) -> I::Output { - iter.intern_with(|xs| self.intern_existential_predicates(xs)) + iter.intern_with(|xs| self.intern_poly_existential_predicates(xs)) } pub fn mk_predicates], &'tcx List>>>( @@ -2542,7 +2559,7 @@ impl<'tcx> TyCtxt<'tcx> { self, lint: &'static Lint, mut id: hir::HirId, - ) -> (Level, LintSource) { + ) -> (Level, LintLevelSource) { let sets = self.lint_levels(LOCAL_CRATE); loop { if let Some(pair) = sets.level_and_source(lint, id, self.sess) { diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 48d0fc1839..4412ba9408 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -15,17 +15,17 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns an equivalent value with all free regions removed (note /// that late-bound regions remain, because they are important for /// subtyping, but they are anonymized and normalized as well).. - pub fn erase_regions(self, value: &T) -> T + pub fn erase_regions(self, value: T) -> T where T: TypeFoldable<'tcx>, { // If there's nothing to erase avoid performing the query at all if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { - return value.clone(); + return value; } - + debug!("erase_regions({:?})", value); let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }); - debug!("erase_regions({:?}) = {:?}", value, value1); + debug!("erase_regions = {:?}", value1); value1 } } @@ -43,7 +43,7 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> { if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) } } - fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 5ec0ec0c56..fc02e78b2f 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,6 +1,6 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::diagnostics::suggest_constraining_type_param; -use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; use rustc_ast as ast; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, DiagnosticBuilder}; @@ -42,8 +42,8 @@ pub enum TypeError<'tcx> { ArgCount, RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>), + RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), + RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>), RegionsPlaceholderMismatch, Sorts(ExpectedFound>), @@ -58,7 +58,7 @@ pub enum TypeError<'tcx> { CyclicTy(Ty<'tcx>), CyclicConst(&'tcx ty::Const<'tcx>), ProjectionMismatched(ExpectedFound), - ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), + ExistentialMismatch(ExpectedFound<&'tcx ty::List>>>), ObjectUnsafeCoercion(DefId), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), @@ -94,7 +94,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } } - let br_string = |br: ty::BoundRegion| match br { + let br_string = |br: ty::BoundRegionKind| match br { ty::BrNamed(_, name) => format!(" {}", name), _ => String::new(), }; diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 8b97a87f21..4de3d15924 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -160,19 +160,15 @@ impl FlagComputation { } &ty::Dynamic(obj, r) => { - self.bound_computation(obj, |computation, obj| { - for predicate in obj.iter() { - match predicate { - ty::ExistentialPredicate::Trait(tr) => { - computation.add_substs(tr.substs) - } - ty::ExistentialPredicate::Projection(p) => { - computation.add_existential_projection(&p); - } - ty::ExistentialPredicate::AutoTrait(_) => {} + for predicate in obj.iter() { + self.bound_computation(predicate, |computation, predicate| match predicate { + ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), + ty::ExistentialPredicate::Projection(p) => { + computation.add_existential_projection(&p); } - } - }); + ty::ExistentialPredicate::AutoTrait(_) => {} + }); + } self.add_region(r); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 70a8157c04..382f3708c3 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -44,13 +44,13 @@ use std::ops::ControlFlow; /// /// To implement this conveniently, use the derive macro located in librustc_macros. pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { - fn super_fold_with>(&self, folder: &mut F) -> Self; - fn fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self; + fn fold_with>(self, folder: &mut F) -> Self { self.super_fold_with(folder) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()>; - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow; + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { self.super_visit_with(visitor) } @@ -73,7 +73,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break() + self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) } fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) @@ -142,26 +142,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn still_further_specializable(&self) -> bool { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } - - /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. - fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> ControlFlow<()>) -> ControlFlow<()> { - pub struct Visitor(F); - - impl<'tcx, F: FnMut(Ty<'tcx>) -> ControlFlow<()>> TypeVisitor<'tcx> for Visitor { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { - self.0(ty) - } - } - - self.visit_with(&mut Visitor(visit)) - } } impl TypeFoldable<'tcx> for hir::Constness { - fn super_fold_with>(&self, _: &mut F) -> Self { - *self + fn super_fold_with>(self, _: &mut F) -> Self { + self } - fn super_visit_with>(&self, _: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } @@ -174,7 +161,7 @@ impl TypeFoldable<'tcx> for hir::Constness { pub trait TypeFolder<'tcx>: Sized { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; - fn fold_binder(&mut self, t: &Binder) -> Binder + fn fold_binder(&mut self, t: Binder) -> Binder where T: TypeFoldable<'tcx>, { @@ -195,23 +182,25 @@ pub trait TypeFolder<'tcx>: Sized { } pub trait TypeVisitor<'tcx>: Sized { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + type BreakTy = !; + + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { t.super_visit_with(self) } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { c.super_visit_with(self) } - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow { p.super_visit_with(self) } } @@ -266,7 +255,7 @@ impl<'tcx> TyCtxt<'tcx> { /// and skipped. pub fn fold_regions( self, - value: &T, + value: T, skipped_regions: &mut bool, mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, ) -> T @@ -329,14 +318,19 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnMut(ty::Region<'tcx>) -> bool, { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_binder>( + &mut self, + t: &Binder, + ) -> ControlFlow { self.outer_index.shift_in(1); let result = t.as_ref().skip_binder().visit_with(self); self.outer_index.shift_out(1); result } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { ControlFlow::CONTINUE @@ -351,7 +345,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) @@ -406,7 +400,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { self.tcx } - fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -466,7 +460,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { self.tcx } - fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -540,8 +534,8 @@ impl<'tcx> TyCtxt<'tcx> { /// results returned by the closure; the closure is expected to /// return a free region (relative to this binder), and hence the /// binder is removed in the return type. The closure is invoked - /// once for each unique `BoundRegion`; multiple references to the - /// same `BoundRegion` will reuse the previous result. A map is + /// once for each unique `BoundRegionKind`; multiple references to the + /// same `BoundRegionKind` will reuse the previous result. A map is /// returned at the end with each bound region and the free region /// that replaced it. /// @@ -549,8 +543,8 @@ impl<'tcx> TyCtxt<'tcx> { /// contain escaping bound types. pub fn replace_late_bound_regions( self, - value: &Binder, - fld_r: F, + value: Binder, + mut fld_r: F, ) -> (T, BTreeMap>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, @@ -561,7 +555,10 @@ impl<'tcx> TyCtxt<'tcx> { let fld_c = |bound_ct, ty| { self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty }) }; - self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c) + let mut region_map = BTreeMap::new(); + let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br)); + let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c); + (value, region_map) } /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping @@ -569,38 +566,22 @@ impl<'tcx> TyCtxt<'tcx> { /// closure replaces escaping bound consts. pub fn replace_escaping_bound_vars( self, - value: &T, + value: T, mut fld_r: F, mut fld_t: G, mut fld_c: H, - ) -> (T, BTreeMap>) + ) -> T where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - use rustc_data_structures::fx::FxHashMap; - - let mut region_map = BTreeMap::new(); - let mut type_map = FxHashMap::default(); - let mut const_map = FxHashMap::default(); - if !value.has_escaping_bound_vars() { - (value.clone(), region_map) + value } else { - let mut real_fld_r = |br| *region_map.entry(br).or_insert_with(|| fld_r(br)); - - let mut real_fld_t = - |bound_ty| *type_map.entry(bound_ty).or_insert_with(|| fld_t(bound_ty)); - - let mut real_fld_c = - |bound_ct, ty| *const_map.entry(bound_ct).or_insert_with(|| fld_c(bound_ct, ty)); - - let mut replacer = - BoundVarReplacer::new(self, &mut real_fld_r, &mut real_fld_t, &mut real_fld_c); - let result = value.fold_with(&mut replacer); - (result, region_map) + let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c); + value.fold_with(&mut replacer) } } @@ -609,8 +590,8 @@ impl<'tcx> TyCtxt<'tcx> { /// types. pub fn replace_bound_vars( self, - value: &Binder, - fld_r: F, + value: Binder, + mut fld_r: F, fld_t: G, fld_c: H, ) -> (T, BTreeMap>) @@ -620,23 +601,22 @@ impl<'tcx> TyCtxt<'tcx> { H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c) + let mut region_map = BTreeMap::new(); + let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br)); + let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c); + (value, region_map) } /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. - pub fn liberate_late_bound_regions( - self, - all_outlive_scope: DefId, - value: &ty::Binder, - ) -> T + pub fn liberate_late_bound_regions(self, all_outlive_scope: DefId, value: ty::Binder) -> T where T: TypeFoldable<'tcx>, { self.replace_late_bound_regions(value, |br| { self.mk_region(ty::ReFree(ty::FreeRegion { scope: all_outlive_scope, - bound_region: br, + bound_region: br.kind, })) }) .0 @@ -649,7 +629,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_constrained_late_bound_regions( self, value: &Binder, - ) -> FxHashSet + ) -> FxHashSet where T: TypeFoldable<'tcx>, { @@ -660,7 +640,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_referenced_late_bound_regions( self, value: &Binder, - ) -> FxHashSet + ) -> FxHashSet where T: TypeFoldable<'tcx>, { @@ -671,7 +651,7 @@ impl<'tcx> TyCtxt<'tcx> { self, value: &Binder, just_constraint: bool, - ) -> FxHashSet + ) -> FxHashSet where T: TypeFoldable<'tcx>, { @@ -683,7 +663,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also /// method lookup and a few other places where precise region relationships are not required. - pub fn erase_late_bound_regions(self, value: &Binder) -> T + pub fn erase_late_bound_regions(self, value: Binder) -> T where T: TypeFoldable<'tcx>, { @@ -698,14 +678,15 @@ impl<'tcx> TyCtxt<'tcx> { /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. - pub fn anonymize_late_bound_regions(self, sig: &Binder) -> Binder + pub fn anonymize_late_bound_regions(self, sig: Binder) -> Binder where T: TypeFoldable<'tcx>, { let mut counter = 0; Binder::bind( self.replace_late_bound_regions(sig, |_| { - let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter))); + let br = ty::BoundRegion { kind: ty::BrAnon(counter) }; + let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br)); counter += 1; r }) @@ -740,7 +721,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { self.tcx } - fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -804,7 +785,7 @@ pub fn shift_region<'tcx>( } } -pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T +pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T where T: TypeFoldable<'tcx>, { @@ -813,6 +794,9 @@ where value.fold_with(&mut Shifter::new(tcx, amount)) } +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundEscapingVars; + /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a /// bound region or a bound type. /// @@ -844,93 +828,114 @@ struct HasEscapingVarsVisitor { } impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + type BreakTy = FoundEscapingVars; + + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { // If the outer-exclusive-binder is *strictly greater* than // `outer_index`, that means that `t` contains some content // bound at `outer_index` or above (because // `outer_exclusive_binder` is always 1 higher than the // content in `t`). Therefore, `t` has some escaping vars. if t.outer_exclusive_binder > self.outer_index { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { // If the region is bound by `outer_index` or anything outside // of outer index, then it escapes the binders we have // visited. if r.bound_at_or_above_binder(self.outer_index) { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } } - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow { // we don't have a `visit_infer_const` callback, so we have to // hook in here to catch this case (annoying...), but // otherwise we do want to remember to visit the rest of the // const, as it has types/regions embedded in a lot of other // places. match ct.val { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => ControlFlow::BREAK, + ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { + ControlFlow::Break(FoundEscapingVars) + } _ => ct.super_visit_with(self), } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { if predicate.inner.outer_exclusive_binder > self.outer_index { - ControlFlow::BREAK + ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE } } } +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundFlags; + // FIXME: Optimize for checking for infer flags struct HasTypeFlagsVisitor { flags: ty::TypeFlags, } impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { + type BreakTy = FoundFlags; + + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags(), self.flags ); - if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if t.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); - if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); - if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", predicate, predicate.inner.flags, self.flags ); if predicate.inner.flags.intersects(self.flags) { - ControlFlow::BREAK + ControlFlow::Break(FoundFlags) } else { ControlFlow::CONTINUE } @@ -941,7 +946,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { /// into a hash set. struct LateBoundRegionsCollector { current_index: ty::DebruijnIndex, - regions: FxHashSet, + regions: FxHashSet, /// `true` if we only want regions that are known to be /// "constrained" when you equate this type with another type. In @@ -964,14 +969,14 @@ impl LateBoundRegionsCollector { } impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { self.current_index.shift_in(1); let result = t.super_visit_with(self); self.current_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { // if we are only looking for "constrained" region, we have to // ignore the inputs to a projection, as they may not appear // in the normalized form @@ -984,7 +989,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { t.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { // if we are only looking for "constrained" region, we have to // ignore the inputs of an unevaluated const, as they may not appear // in the normalized form @@ -997,10 +1002,10 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { c.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if let ty::ReLateBound(debruijn, br) = *r { if debruijn == self.current_index { - self.regions.insert(br); + self.regions.insert(br.kind); } } ControlFlow::CONTINUE diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs index ee6b06a1cc..d9aebfc829 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs @@ -17,7 +17,7 @@ pub struct DefIdForest { /// If A and B are DefIds in the `DefIdForest`, and A is a descendant /// of B, then only B will be in `root_ids`. /// We use a `SmallVec` here because (for its use for caching inhabitedness) - /// its rare that this will contain even two IDs. + /// it's rare that this will contain even two IDs. root_ids: SmallVec<[DefId; 1]>, } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 306cebd9cb..413c9cca58 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -359,15 +359,15 @@ impl<'tcx> Instance<'tcx> { // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)` // below is more likely to ignore the bounds in scope (e.g. if the only // generic parameters mentioned by `substs` were lifetime ones). - let substs = tcx.erase_regions(&substs); + let substs = tcx.erase_regions(substs); // FIXME(eddyb) should this always use `param_env.with_reveal_all()`? if let Some((did, param_did)) = def.as_const_arg() { tcx.resolve_instance_of_const_arg( - tcx.erase_regions(¶m_env.and((did, param_did, substs))), + tcx.erase_regions(param_env.and((did, param_did, substs))), ) } else { - tcx.resolve_instance(tcx.erase_regions(¶m_env.and((def.did, substs)))) + tcx.resolve_instance(tcx.erase_regions(param_env.and((def.did, substs)))) } } @@ -452,7 +452,7 @@ impl<'tcx> Instance<'tcx> { let self_ty = tcx.mk_closure(closure_did, substs); let sig = substs.as_closure().sig(); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); @@ -485,7 +485,7 @@ impl<'tcx> Instance<'tcx> { &self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - v: &T, + v: T, ) -> T where T: TypeFoldable<'tcx> + Clone, @@ -493,7 +493,7 @@ impl<'tcx> Instance<'tcx> { if let Some(substs) = self.substs_for_mir_body() { tcx.subst_and_normalize_erasing_regions(substs, param_env, v) } else { - tcx.normalize_erasing_regions(param_env, v.clone()) + tcx.normalize_erasing_regions(param_env, v) } } @@ -540,7 +540,7 @@ fn polymorphize<'tcx>( struct PolymorphizationFolder<'tcx> { tcx: TyCtxt<'tcx>, - }; + } impl ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 1e93c3650b..b545b92c92 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -15,7 +15,7 @@ use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::DUMMY_SP; use rustc_target::abi::call::{ - ArgAbi, ArgAttribute, ArgAttributes, Conv, FnAbi, PassMode, Reg, RegKind, + ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, }; use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy}; @@ -176,7 +176,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { match *self { LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty), LayoutError::SizeOverflow(ty) => { - write!(f, "the type `{}` is too big for the current architecture", ty) + write!(f, "values of the type `{}` are too big for the current architecture", ty) } } } @@ -631,30 +631,106 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // SIMD vector types. - ty::Adt(def, ..) if def.repr.simd() => { - let element = self.layout_of(ty.simd_type(tcx))?; - let count = ty.simd_size(tcx); - assert!(count > 0); - let scalar = match element.abi { - Abi::Scalar(ref scalar) => scalar.clone(), - _ => { + ty::Adt(def, substs) if def.repr.simd() => { + // Supported SIMD vectors are homogeneous ADTs with at least one field: + // + // * #[repr(simd)] struct S(T, T, T, T); + // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T } + // * #[repr(simd)] struct S([T; 4]) + // + // where T is a primitive scalar (integer/float/pointer). + + // SIMD vectors with zero fields are not supported. + // (should be caught by typeck) + if def.non_enum_variant().fields.is_empty() { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + } + + // Type of the first ADT field: + let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs); + + // Heterogeneous SIMD vectors are not supported: + // (should be caught by typeck) + for fi in &def.non_enum_variant().fields { + if fi.ty(tcx, substs) != f0_ty { + tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty)); + } + } + + // The element type and number of elements of the SIMD vector + // are obtained from: + // + // * the element type and length of the single array field, if + // the first field is of array type, or + // + // * the homogenous field type and the number of fields. + let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() { + // First ADT field is an array: + + // SIMD vectors with multiple array fields are not supported: + // (should be caught by typeck) + if def.non_enum_variant().fields.len() != 1 { tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element.ty + "monomorphising SIMD type `{}` with more than one array field", + ty )); } + + // Extract the number of elements from the layout of the array field: + let len = if let Ok(TyAndLayout { + layout: Layout { fields: FieldsShape::Array { count, .. }, .. }, + .. + }) = self.layout_of(f0_ty) + { + count + } else { + return Err(LayoutError::Unknown(ty)); + }; + + (*e_ty, *len, true) + } else { + // First ADT field is not an array: + (f0_ty, def.non_enum_variant().fields.len() as _, false) }; - let size = - element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?; + + // SIMD vectors of zero length are not supported. + // + // Can't be caught in typeck if the array length is generic. + if e_len == 0 { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + } + + // Compute the ABI of the element type: + let e_ly = self.layout_of(e_ty)?; + let e_abi = if let Abi::Scalar(ref scalar) = e_ly.abi { + scalar.clone() + } else { + // This error isn't caught in typeck, e.g., if + // the element type of the vector is generic. + tcx.sess.fatal(&format!( + "monomorphising SIMD type `{}` with a non-primitive-scalar \ + (integer/float/pointer) element type `{}`", + ty, e_ty + )) + }; + + // Compute the size and alignment of the vector: + let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?; let align = dl.vector_align(size); let size = size.align_to(align.abi); + // Compute the placement of the vector fields: + let fields = if is_array { + FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] } + } else { + FieldsShape::Array { stride: e_ly.size, count: e_len } + }; + tcx.intern_layout(Layout { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Array { stride: element.size, count }, - abi: Abi::Vector { element: scalar, count }, - largest_niche: element.largest_niche.clone(), + fields, + abi: Abi::Vector { element: e_abi, count: e_len }, + largest_niche: e_ly.largest_niche.clone(), size, align, }) @@ -1756,7 +1832,7 @@ impl<'tcx> SizeSkeleton<'tcx> { match tail.kind() { ty::Param(_) | ty::Projection(_) => { debug_assert!(tail.has_param_types_or_consts()); - Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(&tail) }) + Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } _ => bug!( "SizeSkeleton::compute({}): layout errored ({}), yet \ @@ -2029,121 +2105,148 @@ where } fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { - let tcx = cx.tcx(); - let tag_layout = |tag: &Scalar| -> C::TyAndLayout { - let layout = Layout::scalar(cx, tag.clone()); - MaybeResult::from(Ok(TyAndLayout { - layout: tcx.intern_layout(layout), - ty: tag.value.to_ty(tcx), - })) - }; + enum TyMaybeWithLayout { + Ty(C::Ty), + TyAndLayout(C::TyAndLayout), + } - cx.layout_of(match *this.ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::FnPtr(_) - | ty::Never - | ty::FnDef(..) - | ty::GeneratorWitness(..) - | ty::Foreign(..) - | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this), - - // Potentially-fat pointers. - ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < this.fields.count()); - - // Reuse the fat `*T` type as its own thin pointer data field. - // This provides information about, e.g., DST struct pointees - // (which may have no non-DST form), and will work as long - // as the `Abi` or `FieldsShape` is checked by users. - if i == 0 { - let nil = tcx.mk_unit(); - let ptr_ty = if this.ty.is_unsafe_ptr() { - tcx.mk_mut_ptr(nil) - } else { - tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) - }; - return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map( - |mut ptr_layout| { - ptr_layout.ty = this.ty; - ptr_layout - }, - )); - } + fn ty_and_layout_kind< + C: LayoutOf, TyAndLayout: MaybeResult>> + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, + >( + this: TyAndLayout<'tcx>, + cx: &C, + i: usize, + ty: C::Ty, + ) -> TyMaybeWithLayout { + let tcx = cx.tcx(); + let tag_layout = |tag: &Scalar| -> C::TyAndLayout { + let layout = Layout::scalar(cx, tag.clone()); + MaybeResult::from(Ok(TyAndLayout { + layout: tcx.intern_layout(layout), + ty: tag.value.to_ty(tcx), + })) + }; - match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { - ty::Slice(_) | ty::Str => tcx.types.usize, - ty::Dynamic(_, _) => { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) - /* FIXME: use actual fn pointers - Warning: naively computing the number of entries in the - vtable by counting the methods on the trait + methods on - all parent traits does not work, because some methods can - be not object safe and thus excluded from the vtable. - Increase this counter if you tried to implement this but - failed to do it without duplicating a lot of code from - other places in the compiler: 2 - tcx.mk_tup(&[ - tcx.mk_array(tcx.types.usize, 3), - tcx.mk_array(Option), - ]) - */ + match *ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::FnPtr(_) + | ty::Never + | ty::FnDef(..) + | ty::GeneratorWitness(..) + | ty::Foreign(..) + | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this), + + // Potentially-fat pointers. + ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + assert!(i < this.fields.count()); + + // Reuse the fat `*T` type as its own thin pointer data field. + // This provides information about, e.g., DST struct pointees + // (which may have no non-DST form), and will work as long + // as the `Abi` or `FieldsShape` is checked by users. + if i == 0 { + let nil = tcx.mk_unit(); + let ptr_ty = if ty.is_unsafe_ptr() { + tcx.mk_mut_ptr(nil) + } else { + tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) + }; + return TyMaybeWithLayout::TyAndLayout(MaybeResult::from( + cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| { + ptr_layout.ty = ty; + ptr_layout + }), + )); } - _ => bug!("TyAndLayout::field_type({:?}): not applicable", this), - } - } - // Arrays and slices. - ty::Array(element, _) | ty::Slice(element) => element, - ty::Str => tcx.types.u8, - - // Tuples, generators and closures. - ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().nth(i).unwrap(), - - ty::Generator(def_id, ref substs, _) => match this.variants { - Variants::Single { index } => substs - .as_generator() - .state_tys(def_id, tcx) - .nth(index.as_usize()) - .unwrap() - .nth(i) - .unwrap(), - Variants::Multiple { ref tag, tag_field, .. } => { - if i == tag_field { - return tag_layout(tag); + match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { + ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize), + ty::Dynamic(_, _) => { + TyMaybeWithLayout::Ty(tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.mk_array(tcx.types.usize, 3), + )) + /* FIXME: use actual fn pointers + Warning: naively computing the number of entries in the + vtable by counting the methods on the trait + methods on + all parent traits does not work, because some methods can + be not object safe and thus excluded from the vtable. + Increase this counter if you tried to implement this but + failed to do it without duplicating a lot of code from + other places in the compiler: 2 + tcx.mk_tup(&[ + tcx.mk_array(tcx.types.usize, 3), + tcx.mk_array(Option), + ]) + */ + } + _ => bug!("TyAndLayout::field_type({:?}): not applicable", this), } - substs.as_generator().prefix_tys().nth(i).unwrap() } - }, - ty::Tuple(tys) => tys[i].expect_ty(), + // Arrays and slices. + ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element), + ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8), - // SIMD vector types. - ty::Adt(def, ..) if def.repr.simd() => this.ty.simd_type(tcx), + // Tuples, generators and closures. + ty::Closure(_, ref substs) => { + ty_and_layout_kind(this, cx, i, substs.as_closure().tupled_upvars_ty()) + } - // ADTs. - ty::Adt(def, substs) => { - match this.variants { - Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs), + ty::Generator(def_id, ref substs, _) => match this.variants { + Variants::Single { index } => TyMaybeWithLayout::Ty( + substs + .as_generator() + .state_tys(def_id, tcx) + .nth(index.as_usize()) + .unwrap() + .nth(i) + .unwrap(), + ), + Variants::Multiple { ref tag, tag_field, .. } => { + if i == tag_field { + return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); + } + TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap()) + } + }, + + ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i].expect_ty()), - // Discriminant field for enums (where applicable). - Variants::Multiple { ref tag, .. } => { - assert_eq!(i, 0); - return tag_layout(tag); + // ADTs. + ty::Adt(def, substs) => { + match this.variants { + Variants::Single { index } => { + TyMaybeWithLayout::Ty(def.variants[index].fields[i].ty(tcx, substs)) + } + + // Discriminant field for enums (where applicable). + Variants::Multiple { ref tag, .. } => { + assert_eq!(i, 0); + return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); + } } } + + ty::Projection(_) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Opaque(..) + | ty::Param(_) + | ty::Infer(_) + | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty), } + } - ty::Projection(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Opaque(..) - | ty::Param(_) - | ty::Infer(_) - | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty), + cx.layout_of(match ty_and_layout_kind(this, cx, i, this.ty) { + TyMaybeWithLayout::Ty(result) => result, + TyMaybeWithLayout::TyAndLayout(result) => return result, }) } @@ -2352,7 +2455,8 @@ impl<'tcx> ty::Instance<'tcx> { ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let br = ty::BoundRegion { kind: ty::BrEnv }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); @@ -2545,7 +2649,7 @@ where ) -> Self { debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args); - let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); use rustc_target::spec::abi::Abi::*; let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) { @@ -2619,7 +2723,7 @@ where is_return: bool| { // Booleans are always an i1 that needs to be zero-extended. if scalar.is_bool() { - attrs.set(ArgAttribute::ZExt); + attrs.ext(ArgExtension::Zext); return; } @@ -2745,7 +2849,7 @@ where || abi == SpecAbi::RustIntrinsic || abi == SpecAbi::PlatformIntrinsic { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, is_ret: bool| { + let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { if arg.is_ignore() { return; } @@ -2783,9 +2887,9 @@ where _ => return, } - // Return structures up to 2 pointers in size by value, matching `ScalarPair`. LLVM - // will usually return these in 2 registers, which is more efficient than by-ref. - let max_by_val_size = if is_ret { Pointer.size(cx) * 2 } else { Pointer.size(cx) }; + // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`. + // LLVM will usually pass these in 2 registers, which is more efficient than by-ref. + let max_by_val_size = Pointer.size(cx) * 2; let size = arg.layout.size; if arg.layout.is_unsized() || size > max_by_val_size { @@ -2797,12 +2901,9 @@ where arg.cast_to(Reg { kind: RegKind::Integer, size }); } }; - fixup(&mut self.ret, true); + fixup(&mut self.ret); for arg in &mut self.args { - fixup(arg, false); - } - if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); + fixup(arg); } return; } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 83a2bdf90f..e657088a5e 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -24,7 +24,7 @@ extern "C" { /// This means we can use pointer for both /// equality comparisons and hashing. /// -/// Unlike slices, The types contained in `List` are expected to be `Copy` +/// Unlike slices, the types contained in `List` are expected to be `Copy` /// and iterating over a `List` returns `T` instead of a reference. /// /// Note: `Slice` was already taken by the `Ty`. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0042b4a3a4..8395692446 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1,3 +1,14 @@ +//! Defines how the compiler represents types internally. +//! +//! Two important entities in this module are: +//! +//! - [`rustc_middle::ty::Ty`], used to represent the semantics of a type. +//! - [`rustc_middle::ty::TyCtxt`], the central data structure in the compiler. +//! +//! For more information, see ["The `ty` module: representing types"] in the ructc-dev-guide. +//! +//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html + // ignore-tidy-filelength pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor}; pub use self::AssocItemContainer::*; @@ -6,6 +17,7 @@ pub use self::IntVarValue::*; pub use self::Variance::*; use crate::hir::exports::ExportMap; +use crate::hir::place::Place as HirPlace; use crate::ich::StableHashingContext; use crate::middle::cstore::CrateStoreDyn; use crate::middle::resolve_lifetime::ObjectLifetimeDefault; @@ -50,13 +62,13 @@ use std::ops::{ControlFlow, Range}; use std::ptr; use std::str; -pub use self::sty::BoundRegion::*; +pub use self::sty::BoundRegionKind::*; pub use self::sty::InferTy::*; pub use self::sty::RegionKind; pub use self::sty::RegionKind::*; pub use self::sty::TyKind::*; -pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST}; -pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; +pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar}; +pub use self::sty::{BoundRegion, BoundRegionKind, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts}; pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts}; @@ -66,6 +78,7 @@ pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{PolyTraitRef, TraitRef, TyKind}; pub use crate::ty::diagnostics::*; +pub use rustc_type_ir::{DebruijnIndex, TypeFlags, INNERMOST}; pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; @@ -106,7 +119,6 @@ pub mod outlives; pub mod print; pub mod query; pub mod relate; -pub mod steal; pub mod subst; pub mod trait_def; pub mod util; @@ -497,91 +509,6 @@ pub struct CReaderCacheKey { pub pos: usize, } -bitflags! { - /// Flags that we track on types. These flags are propagated upwards - /// through the type during type construction, so that we can quickly check - /// whether the type has various kinds of types in it without recursing - /// over the type itself. - pub struct TypeFlags: u32 { - // Does this have parameters? Used to determine whether substitution is - // required. - /// Does this have [Param]? - const HAS_TY_PARAM = 1 << 0; - /// Does this have [ReEarlyBound]? - const HAS_RE_PARAM = 1 << 1; - /// Does this have [ConstKind::Param]? - const HAS_CT_PARAM = 1 << 2; - - const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_RE_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits; - - /// Does this have [Infer]? - const HAS_TY_INFER = 1 << 3; - /// Does this have [ReVar]? - const HAS_RE_INFER = 1 << 4; - /// Does this have [ConstKind::Infer]? - const HAS_CT_INFER = 1 << 5; - - /// Does this have inference variables? Used to determine whether - /// inference is required. - const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_RE_INFER.bits - | TypeFlags::HAS_CT_INFER.bits; - - /// Does this have [Placeholder]? - const HAS_TY_PLACEHOLDER = 1 << 6; - /// Does this have [RePlaceholder]? - const HAS_RE_PLACEHOLDER = 1 << 7; - /// Does this have [ConstKind::Placeholder]? - const HAS_CT_PLACEHOLDER = 1 << 8; - - /// `true` if there are "names" of regions and so forth - /// that are local to a particular fn/inferctxt - const HAS_FREE_LOCAL_REGIONS = 1 << 9; - - /// `true` if there are "names" of types and regions and so forth - /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits - | TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_CT_INFER.bits - | TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits - | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; - - /// Does this have [Projection]? - const HAS_TY_PROJECTION = 1 << 10; - /// Does this have [Opaque]? - const HAS_TY_OPAQUE = 1 << 11; - /// Does this have [ConstKind::Unevaluated]? - const HAS_CT_PROJECTION = 1 << 12; - - /// Could this type be normalized further? - const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits - | TypeFlags::HAS_TY_OPAQUE.bits - | TypeFlags::HAS_CT_PROJECTION.bits; - - /// Is an error type/const reachable? - const HAS_ERROR = 1 << 13; - - /// Does this have any region that "appears free" in the type? - /// Basically anything but [ReLateBound] and [ReErased]. - const HAS_FREE_REGIONS = 1 << 14; - - /// Does this have any [ReLateBound] regions? Used to check - /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 15; - - /// Does this have any [ReErased] regions? - const HAS_RE_ERASED = 1 << 16; - - /// Does this value have parameters/placeholders/inference variables which could be - /// replaced later, in a way that would change the results of `impl` specialization? - const STILL_FURTHER_SPECIALIZABLE = 1 << 17; - } -} - #[allow(rustc::usage_of_ty_tykind)] pub struct TyS<'tcx> { /// This field shouldn't be used directly and may be removed in the future. @@ -611,6 +538,18 @@ pub struct TyS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } +impl<'tcx> TyS<'tcx> { + /// A constructor used only for internal testing. + #[allow(rustc::usage_of_ty_tykind)] + pub fn make_for_test( + kind: TyKind<'tcx>, + flags: TypeFlags, + outer_exclusive_binder: ty::DebruijnIndex, + ) -> TyS<'tcx> { + TyS { kind, flags, outer_exclusive_binder } + } +} + // `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] static_assert_size!(TyS<'_>, 32); @@ -660,7 +599,18 @@ impl<'a, 'tcx> HashStable> for TyS<'tcx> { #[rustc_diagnostic_item = "Ty"] pub type Ty<'tcx> = &'tcx TyS<'tcx>; -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub struct UpvarPath { pub hir_id: hir::HirId, } @@ -668,13 +618,19 @@ pub struct UpvarPath { /// Upvars do not get their own `NodeId`. Instead, we use the pair of /// the original var ID (that is, the root variable that is referenced /// by the upvar) and the ID of the closure expression. -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct UpvarId { pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, } -#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] +impl UpvarId { + pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId { + UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id } + } +} + +#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, @@ -728,7 +684,7 @@ pub enum BorrowKind { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases @@ -745,7 +701,7 @@ pub enum UpvarCapture<'tcx> { ByRef(UpvarBorrow<'tcx>), } -#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct UpvarBorrow<'tcx> { /// The kind of borrow: by-ref upvars have access to shared /// immutable borrows, which are not part of the normal language @@ -756,6 +712,56 @@ pub struct UpvarBorrow<'tcx> { pub region: ty::Region<'tcx>, } +/// Given the closure DefId this map provides a map of root variables to minimum +/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure. +pub type MinCaptureInformationMap<'tcx> = FxHashMap>; + +/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`. +/// Used to track the minimum set of `Place`s that need to be captured to support all +/// Places captured by the closure starting at a given root variable. +/// +/// This provides a convenient and quick way of checking if a variable being used within +/// a closure is a capture of a local variable. +pub type RootVariableMinCaptureList<'tcx> = FxIndexMap>; + +/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s. +pub type MinCaptureList<'tcx> = Vec>; + +/// A `Place` and the corresponding `CaptureInfo`. +#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +pub struct CapturedPlace<'tcx> { + pub place: HirPlace<'tcx>, + pub info: CaptureInfo<'tcx>, +} + +/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) +/// for a particular capture as well as identifying the part of the source code +/// that triggered this capture to occur. +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +pub struct CaptureInfo<'tcx> { + /// Expr Id pointing to use that resulted in selecting the current capture kind + /// + /// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is + /// possible that we don't see the use of a particular place resulting in expr_id being + /// None. In such case we fallback on uvpars_mentioned for span. + /// + /// Eg: + /// ```rust,no_run + /// let x = 5; + /// + /// let c = || { + /// let _ = x + /// }; + /// ``` + /// + /// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured, + /// but we won't see it being used during capture analysis, since it's essentially a discard. + pub expr_id: Option, + + /// Capture mode that was selected + pub capture_kind: UpvarCapture<'tcx>, +} + pub type UpvarListMap = FxHashMap>; pub type UpvarCaptureMap<'tcx> = FxHashMap>; @@ -1154,17 +1160,16 @@ pub enum PredicateAtom<'tcx> { TypeWellFormedFromEnv(Ty<'tcx>), } -impl<'tcx> PredicateAtom<'tcx> { +impl<'tcx> Binder> { /// Wraps `self` with the given qualifier if this predicate has any unbound variables. pub fn potentially_quantified( self, tcx: TyCtxt<'tcx>, qualifier: impl FnOnce(Binder>) -> PredicateKind<'tcx>, ) -> Predicate<'tcx> { - if self.has_escaping_bound_vars() { - qualifier(Binder::bind(self)) - } else { - PredicateKind::Atom(self) + match self.no_bound_vars() { + Some(atom) => PredicateKind::Atom(atom), + None => qualifier(self), } .to_predicate(tcx) } @@ -1257,7 +1262,11 @@ impl<'tcx> Predicate<'tcx> { let substs = trait_ref.skip_binder().substs; let pred = self.skip_binders(); let new = pred.subst(tcx, substs); - if new != pred { new.potentially_quantified(tcx, PredicateKind::ForAll) } else { self } + if new != pred { + ty::Binder::bind(new).potentially_quantified(tcx, PredicateKind::ForAll) + } else { + self + } } } @@ -1284,6 +1293,10 @@ impl<'tcx> PolyTraitPredicate<'tcx> { // Ok to skip binder since trait `DefId` does not care about regions. self.skip_binder().def_id() } + + pub fn self_ty(self) -> ty::Binder> { + self.map_bound(|trait_ref| trait_ref.self_ty()) + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -1408,36 +1421,40 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::Trait(self.value.skip_binder(), self.constness) + self.value + .map_bound(|value| PredicateAtom::Trait(value, self.constness)) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::RegionOutlives(self.skip_binder()) + self.map_bound(|value| PredicateAtom::RegionOutlives(value)) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::TypeOutlives(self.skip_binder()) + self.map_bound(|value| PredicateAtom::TypeOutlives(value)) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateAtom::Projection(self.skip_binder()) + self.map_bound(|value| PredicateAtom::Projection(value)) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> Predicate<'tcx> { - pub fn to_opt_poly_trait_ref(self) -> Option> { - match self.skip_binders() { - PredicateAtom::Trait(t, _) => Some(ty::Binder::bind(t.trait_ref)), + pub fn to_opt_poly_trait_ref(self) -> Option>> { + let predicate = self.bound_atom(); + match predicate.skip_binder() { + PredicateAtom::Trait(t, constness) => { + Some(ConstnessAnd { constness, value: predicate.rebind(t.trait_ref) }) + } PredicateAtom::Projection(..) | PredicateAtom::Subtype(..) | PredicateAtom::RegionOutlives(..) @@ -1452,8 +1469,9 @@ impl<'tcx> Predicate<'tcx> { } pub fn to_opt_type_outlives(self) -> Option> { - match self.skip_binders() { - PredicateAtom::TypeOutlives(data) => Some(ty::Binder::bind(data)), + let predicate = self.bound_atom(); + match predicate.skip_binder() { + PredicateAtom::TypeOutlives(data) => Some(predicate.rebind(data)), PredicateAtom::Trait(..) | PredicateAtom::Projection(..) | PredicateAtom::Subtype(..) @@ -1580,11 +1598,9 @@ impl UniverseIndex { } } -/// The "placeholder index" fully defines a placeholder region. -/// Placeholder regions are identified by both a **universe** as well -/// as a "bound-region" within that universe. The `bound_region` is -/// basically a name -- distinct bound regions within the same -/// universe are just two regions with an unknown relationship to one +/// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are +/// identified by both a universe, as well as a name residing within that universe. Distinct bound +/// regions/types/consts within the same universe simply have an unknown relationship to one /// another. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] pub struct Placeholder { @@ -1602,40 +1618,72 @@ where } } -pub type PlaceholderRegion = Placeholder; +pub type PlaceholderRegion = Placeholder; pub type PlaceholderType = Placeholder; -pub type PlaceholderConst = Placeholder; +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(TyEncodable, TyDecodable, PartialOrd, Ord)] +pub struct BoundConst<'tcx> { + pub var: BoundVar, + pub ty: Ty<'tcx>, +} -/// A `DefId` which is potentially bundled with its corresponding generic parameter -/// in case `did` is a const argument. -/// -/// This is used to prevent cycle errors during typeck -/// as `type_of(const_arg)` depends on `typeck(owning_body)` -/// which once again requires the type of its generic arguments. +pub type PlaceholderConst<'tcx> = Placeholder>; + +/// A `DefId` which, in case it is a const argument, is potentially bundled with +/// the `DefId` of the generic parameter it instantiates. /// -/// Luckily we only need to deal with const arguments once we -/// know their corresponding parameters. We (ab)use this by -/// calling `type_of(param_did)` for these arguments. +/// This is used to avoid calls to `type_of` for const arguments during typeck +/// which cause cycle errors. /// /// ```rust /// #![feature(const_generics)] /// /// struct A; /// impl A { -/// fn foo(&self) -> usize { N } +/// fn foo(&self) -> [u8; N] { [0; N] } +/// // ^ const parameter /// } /// struct B; /// impl B { -/// fn foo(&self) -> usize { 42 } +/// fn foo(&self) -> usize { 42 } +/// // ^ const parameter /// } /// /// fn main() { /// let a = A; -/// a.foo::<7>(); +/// let _b = a.foo::<{ 3 + 7 }>(); +/// // ^^^^^^^^^ const argument /// } /// ``` +/// +/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know +/// which `foo` is used until we know the type of `a`. +/// +/// We only know the type of `a` once we are inside of `typeck(main)`. +/// We also end up normalizing the type of `_b` during `typeck(main)` which +/// requires us to evaluate the const argument. +/// +/// To evaluate that const argument we need to know its type, +/// which we would get using `type_of(const_arg)`. This requires us to +/// resolve `foo` as it can be either `usize` or `u8` in this example. +/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`, +/// which results in a cycle. +/// +/// In short we must not call `type_of(const_arg)` during `typeck(main)`. +/// +/// When first creating the `ty::Const` of the const argument inside of `typeck` we have +/// already resolved `foo` so we know which const parameter this argument instantiates. +/// This means that we also know the expected result of `type_of(const_arg)` even if we +/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is +/// trivial to compute. +/// +/// If we now want to use that constant in a place which potentionally needs its type +/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`, +/// except that instead of a `Ty` we bundle the `DefId` of the const parameter. +/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some` +/// to get the type of `did`. #[derive(Copy, Clone, Debug, TypeFoldable, Lift, TyEncodable, TyDecodable)] #[derive(PartialEq, Eq, PartialOrd, Ord)] #[derive(Hash, HashStable)] @@ -1646,7 +1694,7 @@ pub struct WithOptConstParam { /// /// Note that even if `did` is a const argument, this may still be `None`. /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)` - /// to potentially update `param_did` in case it `None`. + /// to potentially update `param_did` in the case it is `None`. pub const_param_did: Option, } @@ -1772,11 +1820,11 @@ impl<'a, 'tcx> HashStable> for ParamEnv<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.caller_bounds().visit_with(visitor)?; self.reveal().visit_with(visitor) } @@ -1874,7 +1922,7 @@ impl<'tcx> ParamEnv<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] pub struct ConstnessAnd { pub constness: Constness, pub value: T, diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index a594a8ad51..9d97815a5f 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -30,7 +30,7 @@ impl<'tcx> TyCtxt<'tcx> { // Erase first before we do the real query -- this keeps the // cache from being too polluted. - let value = self.erase_regions(&value); + let value = self.erase_regions(value); if !value.has_projections() { value } else { @@ -49,7 +49,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn normalize_erasing_late_bound_regions( self, param_env: ty::ParamEnv<'tcx>, - value: &ty::Binder, + value: ty::Binder, ) -> T where T: TypeFoldable<'tcx>, @@ -65,7 +65,7 @@ impl<'tcx> TyCtxt<'tcx> { self, param_substs: SubstsRef<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 2e00be2395..c79e06b7fd 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -63,7 +63,7 @@ pub trait Printer<'tcx>: Sized { fn print_dyn_existential( self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result; fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result; @@ -343,7 +343,9 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { } } -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List> { +impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> + for &'tcx ty::List>> +{ type Output = P::DynExistential; type Error = P::Error; fn print(&self, cx: P) -> Result { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1e4fd0921e..9b178d9d2b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -125,13 +125,13 @@ pub struct RegionHighlightMode { highlight_regions: [Option<(ty::RegionKind, usize)>; 3], /// If enabled, when printing a "free region" that originated from - /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily + /// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily /// have names print as normal. /// /// This is used when you have a signature like `fn foo(x: &u32, /// y: &'a u32)` and we want to give a name to the region of the /// reference `x`. - highlight_bound_region: Option<(ty::BoundRegion, usize)>, + highlight_bound_region: Option<(ty::BoundRegionKind, usize)>, } impl RegionHighlightMode { @@ -175,7 +175,7 @@ impl RegionHighlightMode { /// Highlight the given bound region. /// We can only highlight one bound region at a time. See /// the field `highlight_bound_region` for more detailed notes. - pub fn highlighting_bound_region(&mut self, br: ty::BoundRegion, number: usize) { + pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind, number: usize) { assert!(self.highlight_bound_region.is_none()); self.highlight_bound_region = Some((br, number)); } @@ -209,6 +209,17 @@ pub trait PrettyPrinter<'tcx>: value.as_ref().skip_binder().print(self) } + fn wrap_binder Result>( + self, + value: &ty::Binder, + f: F, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, + { + f(value.as_ref().skip_binder(), self) + } + /// Prints comma-separated elements. fn comma_sep(mut self, mut elems: impl Iterator) -> Result where @@ -753,72 +764,77 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { - define_scoped_cx!(self); - // Generate the main trait ref, including associated types. let mut first = true; if let Some(principal) = predicates.principal() { - p!(print_def_path(principal.def_id, &[])); - - let mut resugared = false; - - // Special-case `Fn(...) -> ...` and resugar it. - let fn_trait_kind = self.tcx().fn_trait_kind_from_lang_item(principal.def_id); - if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { - if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { - let mut projections = predicates.projection_bounds(); - if let (Some(proj), None) = (projections.next(), projections.next()) { - let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); - p!(pretty_fn_sig(&tys, false, proj.ty)); - resugared = true; + self = self.wrap_binder(&principal, |principal, mut cx| { + define_scoped_cx!(cx); + p!(print_def_path(principal.def_id, &[])); + + let mut resugared = false; + + // Special-case `Fn(...) -> ...` and resugar it. + let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id); + if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() { + if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { + let mut projections = predicates.projection_bounds(); + if let (Some(proj), None) = (projections.next(), projections.next()) { + let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); + p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty)); + resugared = true; + } } } - } - // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, - // in order to place the projections inside the `<...>`. - if !resugared { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx().mk_ty_infer(ty::FreshTy(0)); - let principal = principal.with_self_ty(self.tcx(), dummy_self); + // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, + // in order to place the projections inside the `<...>`. + if !resugared { + // Use a type that can't appear in defaults of type parameters. + let dummy_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0)); + let principal = principal.with_self_ty(cx.tcx(), dummy_cx); + + let args = cx.generic_args_to_print( + cx.tcx().generics_of(principal.def_id), + principal.substs, + ); + + // Don't print `'_` if there's no unerased regions. + let print_regions = args.iter().any(|arg| match arg.unpack() { + GenericArgKind::Lifetime(r) => *r != ty::ReErased, + _ => false, + }); + let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { + GenericArgKind::Lifetime(_) => print_regions, + _ => true, + }); + let mut projections = predicates.projection_bounds(); - let args = self.generic_args_to_print( - self.tcx().generics_of(principal.def_id), - principal.substs, - ); + let arg0 = args.next(); + let projection0 = projections.next(); + if arg0.is_some() || projection0.is_some() { + let args = arg0.into_iter().chain(args); + let projections = projection0.into_iter().chain(projections); - // Don't print `'_` if there's no unerased regions. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, - _ => false, - }); - let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); - let mut projections = predicates.projection_bounds(); - - let arg0 = args.next(); - let projection0 = projections.next(); - if arg0.is_some() || projection0.is_some() { - let args = arg0.into_iter().chain(args); - let projections = projection0.into_iter().chain(projections); - - p!(generic_delimiters(|mut cx| { - cx = cx.comma_sep(args)?; - if arg0.is_some() && projection0.is_some() { - write!(cx, ", ")?; - } - cx.comma_sep(projections) - })); + p!(generic_delimiters(|mut cx| { + cx = cx.comma_sep(args)?; + if arg0.is_some() && projection0.is_some() { + write!(cx, ", ")?; + } + cx.comma_sep(projections) + })); + } } - } + Ok(cx) + })?; + first = false; } + define_scoped_cx!(self); + // Builtin bounds. // FIXME(eddyb) avoid printing twice (needed to ensure // that the auto traits are sorted *and* printed via cx). @@ -1391,7 +1407,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { fn print_dyn_existential( self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { self.pretty_print_dyn_existential(predicates) } @@ -1537,6 +1553,17 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { self.pretty_in_binder(value) } + fn wrap_binder Result>( + self, + value: &ty::Binder, + f: C, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, + { + self.pretty_wrap_binder(value, f) + } + fn typed_value( mut self, f: impl FnOnce(Self) -> Result, @@ -1584,7 +1611,7 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { data.name != kw::Invalid && data.name != kw::UnderscoreLifetime } - ty::ReLateBound(_, br) + ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { @@ -1663,7 +1690,7 @@ impl FmtPrinter<'_, '_, F> { return Ok(self); } } - ty::ReLateBound(_, br) + ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { @@ -1750,12 +1777,12 @@ impl FmtPrinter<'_, 'tcx, F> { define_scoped_cx!(self); let mut region_index = self.region_index; - let new_value = self.tcx.replace_late_bound_regions(value, |br| { + let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| { let _ = start_or_continue(&mut self, "for<", ", "); - let br = match br { + let kind = match br.kind { ty::BrNamed(_, name) => { let _ = write!(self, "{}", name); - br + br.kind } ty::BrAnon(_) | ty::BrEnv => { let name = loop { @@ -1769,7 +1796,7 @@ impl FmtPrinter<'_, 'tcx, F> { ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) } }; - self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)) + self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind })) }); start_or_continue(&mut self, "", "> ")?; @@ -1790,14 +1817,30 @@ impl FmtPrinter<'_, 'tcx, F> { Ok(inner) } + pub fn pretty_wrap_binder Result>( + self, + value: &ty::Binder, + f: C, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, + { + let old_region_index = self.region_index; + let (new, new_value) = self.name_all_regions(value)?; + let mut inner = f(&new_value.0, new)?; + inner.region_index = old_region_index; + inner.binder_depth -= 1; + Ok(inner) + } + fn prepare_late_bound_region_info(&mut self, value: &ty::Binder) where T: TypeFoldable<'tcx>, { struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { - if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) = *r { self.0.insert(name); } r.super_visit_with(self) @@ -1906,12 +1949,12 @@ impl ty::Binder> { forward_display_to_print! { Ty<'tcx>, - &'tcx ty::List>, + &'tcx ty::List>>, &'tcx ty::Const<'tcx>, // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. - ty::Binder<&'tcx ty::List>>, + ty::Binder>, ty::Binder>, ty::Binder>, ty::Binder>, diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 7ba4d5a14d..b269dd09b7 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -28,13 +28,13 @@ use crate::traits::query::{ }; use crate::traits::specialization_graph; use crate::traits::{self, ImplSource}; -use crate::ty::steal::Steal; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::StableVec; +use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; @@ -220,7 +220,7 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &De .map(|c| c.is_green()) .unwrap_or(false)); - let key = as DepNodeParams>>::recover(tcx, dep_node).unwrap(); + let key = as DepNodeParams>>::recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); if queries::$name::cache_on_disk(tcx, &key, None) { let _ = tcx.$name(key); } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 173e9a3192..8a1165bbd6 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use crate::mir::{self, interpret}; use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder}; @@ -11,6 +11,7 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; +use rustc_hir::definitions::Definitions; use rustc_index::vec::{Idx, IndexVec}; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; use rustc_session::{CrateDisambiguator, Session}; @@ -21,6 +22,8 @@ use rustc_span::hygiene::{ use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP}; +use std::collections::hash_map::Entry; +use std::iter::FromIterator; use std::mem; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -80,6 +83,31 @@ pub struct OnDiskCache<'sess> { expn_data: FxHashMap, // Additional information used when decoding hygiene data. hygiene_context: HygieneDecodeContext, + // Maps `DefPathHash`es to their `RawDefId`s from the *previous* + // compilation session. This is used as an initial 'guess' when + // we try to map a `DefPathHash` to its `DefId` in the current compilation + // session. + foreign_def_path_hashes: FxHashMap, + + // The *next* compilation sessison's `foreign_def_path_hashes` - at + // the end of our current compilation session, this will get written + // out to the `foreign_def_path_hashes` field of the `Footer`, which + // will become `foreign_def_path_hashes` of the next compilation session. + // This stores any `DefPathHash` that we may need to map to a `DefId` + // during the next compilation session. + latest_foreign_def_path_hashes: Lock>, + + // Maps `DefPathHashes` to their corresponding `LocalDefId`s for all + // local items in the current compilation session. This is only populated + // when we are in incremental mode and have loaded a pre-existing cache + // from disk, since this map is only used when deserializing a `DefPathHash` + // from the incremental cache. + local_def_path_hash_to_def_id: FxHashMap, + // Caches all lookups of `DefPathHashes`, both for local and foreign + // definitions. A definition from the previous compilation session + // may no longer exist in the current compilation session, so + // we use `Option` so that we can cache a lookup failure. + def_path_hash_to_def_id_cache: Lock>>, } // This type is used only for serialization and deserialization. @@ -95,6 +123,7 @@ struct Footer { syntax_contexts: FxHashMap, // See `OnDiskCache.expn_data` expn_data: FxHashMap, + foreign_def_path_hashes: FxHashMap, } type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; @@ -118,9 +147,36 @@ impl AbsoluteBytePos { } } +/// Represents a potentially invalid `DefId`. This is used during incremental +/// compilation to represent a `DefId` from the *previous* compilation session, +/// which may no longer be valid. This is used to help map a `DefPathHash` +/// to a `DefId` in the current compilation session. +#[derive(Encodable, Decodable, Copy, Clone, Debug)] +crate struct RawDefId { + // We deliberately do not use `CrateNum` and `DefIndex` + // here, since a crate/index from the previous compilation + // session may no longer exist. + pub krate: u32, + pub index: u32, +} + +fn make_local_def_path_hash_map(definitions: &Definitions) -> FxHashMap { + FxHashMap::from_iter( + definitions + .def_path_table() + .all_def_path_hashes_and_def_ids(LOCAL_CRATE) + .map(|(hash, def_id)| (hash, def_id.as_local().unwrap())), + ) +} + impl<'sess> OnDiskCache<'sess> { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { + pub fn new( + sess: &'sess Session, + data: Vec, + start_pos: usize, + definitions: &Definitions, + ) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -155,6 +211,10 @@ impl<'sess> OnDiskCache<'sess> { syntax_contexts: footer.syntax_contexts, expn_data: footer.expn_data, hygiene_context: Default::default(), + foreign_def_path_hashes: footer.foreign_def_path_hashes, + latest_foreign_def_path_hashes: Default::default(), + local_def_path_hash_to_def_id: make_local_def_path_hash_map(definitions), + def_path_hash_to_def_id_cache: Default::default(), } } @@ -173,6 +233,10 @@ impl<'sess> OnDiskCache<'sess> { syntax_contexts: FxHashMap::default(), expn_data: FxHashMap::default(), hygiene_context: Default::default(), + foreign_def_path_hashes: Default::default(), + latest_foreign_def_path_hashes: Default::default(), + local_def_path_hash_to_def_id: Default::default(), + def_path_hash_to_def_id_cache: Default::default(), } } @@ -200,6 +264,22 @@ impl<'sess> OnDiskCache<'sess> { (file_to_file_index, file_index_to_stable_id) }; + // Register any dep nodes that we reused from the previous session, + // but didn't `DepNode::construct` in this session. This ensures + // that their `DefPathHash` to `RawDefId` mappings are registered + // in 'latest_foreign_def_path_hashes' if necessary, since that + // normally happens in `DepNode::construct`. + tcx.dep_graph.register_reused_dep_nodes(tcx); + + // Load everything into memory so we can write it out to the on-disk + // cache. The vast majority of cacheable query results should already + // be in memory, so this should be a cheap operation. + // Do this *before* we clone 'latest_foreign_def_path_hashes', since + // loading existing queries may cause us to create new DepNodes, which + // may in turn end up invoking `store_foreign_def_id_hash` + tcx.dep_graph.exec_cache_promotions(tcx); + + let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone(); let hygiene_encode_context = HygieneEncodeContext::default(); let mut encoder = CacheEncoder { @@ -211,13 +291,9 @@ impl<'sess> OnDiskCache<'sess> { source_map: CachingSourceMapView::new(tcx.sess.source_map()), file_to_file_index, hygiene_context: &hygiene_encode_context, + latest_foreign_def_path_hashes, }; - // Load everything into memory so we can write it out to the on-disk - // cache. The vast majority of cacheable query results should already - // be in memory, so this should be a cheap operation. - tcx.dep_graph.exec_cache_promotions(tcx); - // Encode query results. let mut query_result_index = EncodedQueryResultIndex::new(); @@ -312,6 +388,9 @@ impl<'sess> OnDiskCache<'sess> { }, )?; + let foreign_def_path_hashes = + std::mem::take(&mut encoder.latest_foreign_def_path_hashes); + // `Encode the file footer. let footer_pos = encoder.position() as u64; encoder.encode_tagged( @@ -324,6 +403,7 @@ impl<'sess> OnDiskCache<'sess> { interpret_alloc_index, syntax_contexts, expn_data: expn_ids, + foreign_def_path_hashes, }, )?; @@ -374,6 +454,56 @@ impl<'sess> OnDiskCache<'sess> { debug_assert!(prev.is_none()); } + fn get_raw_def_id(&self, hash: &DefPathHash) -> Option { + self.foreign_def_path_hashes.get(hash).copied() + } + + fn try_remap_cnum(&self, tcx: TyCtxt<'_>, cnum: u32) -> Option { + let cnum_map = + self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..])); + debug!("try_remap_cnum({}): cnum_map={:?}", cnum, cnum_map); + + cnum_map[CrateNum::from_u32(cnum)] + } + + pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { + // We may overwrite an existing entry, but it will have the same value, + // so it's fine + self.latest_foreign_def_path_hashes + .lock() + .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); + } + + /// If the given `dep_node`'s hash still exists in the current compilation, + /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. + /// + /// Normally, `store_foreign_def_id_hash` can be called directly by + /// the dependency graph when we construct a `DepNode`. However, + /// when we re-use a deserialized `DepNode` from the previous compilation + /// session, we only have the `DefPathHash` available. This method is used + /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written + /// out for usage in the next compilation session. + pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { + // For reused dep nodes, we only need to store the mapping if the node + // is one whose query key we can reconstruct from the hash. We use the + // mapping to aid that reconstruction in the next session. While we also + // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, + // they're already registered during `DefId` encoding. + if dep_node.kind.can_reconstruct_query_key() { + let hash = DefPathHash(dep_node.hash.into()); + + // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to + // `latest_foreign_def_path_hashes`, since the `RawDefId` might have + // changed in the current compilation session (e.g. we've added/removed crates, + // or added/removed definitions before/after the target definition). + if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { + if !def_id.is_local() { + self.store_foreign_def_id_hash(def_id, hash); + } + } + } + } + /// Returns the cached query result if there is something in the cache for /// the given `SerializedDepNodeIndex`; otherwise returns `None`. crate fn try_load_query_result<'tcx, T>( @@ -481,11 +611,62 @@ impl<'sess> OnDiskCache<'sess> { map }) } + + /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation + /// session, if it still exists. This is used during incremental compilation to + /// turn a deserialized `DefPathHash` into its current `DefId`. + pub(crate) fn def_path_hash_to_def_id( + &self, + tcx: TyCtxt<'tcx>, + hash: DefPathHash, + ) -> Option { + let mut cache = self.def_path_hash_to_def_id_cache.lock(); + match cache.entry(hash) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + debug!("def_path_hash_to_def_id({:?})", hash); + // Check if the `DefPathHash` corresponds to a definition in the current + // crate + if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() { + let def_id = def_id.to_def_id(); + e.insert(Some(def_id)); + return Some(def_id); + } + // This `raw_def_id` represents the `DefId` of this `DefPathHash` in + // the *previous* compliation session. The `DefPathHash` includes the + // owning crate, so if the corresponding definition still exists in the + // current compilation session, the crate is guaranteed to be the same + // (otherwise, we would compute a different `DefPathHash`). + let raw_def_id = self.get_raw_def_id(&hash)?; + debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); + // If the owning crate no longer exists, the corresponding definition definitely + // no longer exists. + let krate = self.try_remap_cnum(tcx, raw_def_id.krate)?; + debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); + // If our `DefPathHash` corresponded to a definition in the local crate, + // we should have either found it in `local_def_path_hash_to_def_id`, or + // never attempted to load it in the first place. Any query result or `DepNode` + // that references a local `DefId` should depend on some HIR-related `DepNode`. + // If a local definition is removed/modified such that its old `DefPathHash` + // no longer has a corresponding definition, that HIR-related `DepNode` should + // end up red. This should prevent us from ever calling + // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any + // queries involved. + debug_assert_ne!(krate, LOCAL_CRATE); + // Try to find a definition in the current session, using the previous `DefIndex` + // as an initial guess. + let opt_def_id = tcx.cstore.def_path_hash_to_def_id(krate, raw_def_id.index, hash); + debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); + e.insert(opt_def_id); + opt_def_id + } + } + } } //- DECODING ------------------------------------------------------------------- -/// A decoder that can read from the incr. comp. cache. It is similar to the one +/// A decoder that can read from the incremental compilation cache. It is similar to the one /// we use for crate metadata decoding in that it can rebase spans and eventually /// will also handle things that contain `Ty` instances. crate struct CacheDecoder<'a, 'tcx> { @@ -713,7 +894,17 @@ impl<'a, 'tcx> Decodable> for DefId { let def_path_hash = DefPathHash::decode(d)?; // Using the `DefPathHash`, we can lookup the new `DefId`. - Ok(d.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) + // Subtle: We only encode a `DefId` as part of a query result. + // If we get to this point, then all of the query inputs were green, + // which means that the definition with this hash is guaranteed to + // still exist in the current compilation session. + Ok(d.tcx() + .queries + .on_disk_cache + .as_ref() + .unwrap() + .def_path_hash_to_def_id(d.tcx(), def_path_hash) + .unwrap()) } } @@ -763,7 +954,7 @@ impl<'a, 'tcx> Decodable> for &'tcx [Span] { //- ENCODING ------------------------------------------------------------------- -/// An encoder that can write the incr. comp. cache. +/// An encoder that can write to the incremental compilation cache. struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { tcx: TyCtxt<'tcx>, encoder: &'a mut E, @@ -773,6 +964,7 @@ struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { source_map: CachingSourceMapView<'tcx>, file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, hygiene_context: &'a HygieneEncodeContext, + latest_foreign_def_path_hashes: FxHashMap, } impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E> @@ -870,9 +1062,6 @@ where { const CLEAR_CROSS_CRATE: bool = false; - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } fn position(&self) -> usize { self.encoder.encoder_position() } @@ -895,6 +1084,15 @@ where { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { let def_path_hash = s.tcx.def_path_hash(*self); + // Store additional information when we encode a foreign `DefId`, + // so that we can map its `DefPathHash` back to a `DefId` in the next + // compilation session. + if !self.is_local() { + s.latest_foreign_def_path_hashes.insert( + def_path_hash, + RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() }, + ); + } def_path_hash.encode(s) } } diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index d038695283..d0730bd121 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -128,7 +128,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { eprintln!("query stack during panic:"); - // Be careful reyling on global state here: this code is called from + // Be careful relying on global state here: this code is called from // a panic hook, which means that the global `Handler` may be in a weird // state if it was responsible for triggering the panic. let mut i = 0; @@ -507,10 +507,11 @@ macro_rules! define_queries_struct { (tcx: $tcx:tt, input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Queries<$tcx> { - /// This provides access to the incrimental comilation on-disk cache for query results. + /// This provides access to the incremental compilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by /// `DepGraph::try_mark_green()` and the query infrastructure. - pub(crate) on_disk_cache: OnDiskCache<'tcx>, + /// This is `None` if we are not incremental compilation mode + pub(crate) on_disk_cache: Option>, providers: IndexVec, fallback_extern_providers: Box, @@ -526,7 +527,7 @@ macro_rules! define_queries_struct { pub(crate) fn new( providers: IndexVec, fallback_extern_providers: Providers, - on_disk_cache: OnDiskCache<'tcx>, + on_disk_cache: Option>, ) -> Self { Queries { providers, diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index ef5034e218..293b3c6b04 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -33,6 +33,15 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; + /// Whether we should look into the substs of unevaluated constants + /// even if `feature(const_evaluatable_checked)` is active. + /// + /// This is needed in `combine` to prevent accidentially creating + /// infinite types as we abuse `TypeRelation` to walk a type there. + fn visit_ct_substs(&self) -> bool { + false + } + fn with_cause(&mut self, _cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -579,7 +588,7 @@ pub fn super_relate_consts>( ( ty::ConstKind::Unevaluated(a_def, a_substs, None), ty::ConstKind::Unevaluated(b_def, b_substs, None), - ) if tcx.features().const_evaluatable_checked => { + ) if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() => { if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { Ok(a.val) } else { @@ -603,7 +612,7 @@ pub fn super_relate_consts>( new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty })) } -impl<'tcx> Relate<'tcx> for &'tcx ty::List> { +impl<'tcx> Relate<'tcx> for &'tcx ty::List>> { fn relate>( relation: &mut R, a: Self, @@ -616,9 +625,10 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { // in `a`. let mut a_v: Vec<_> = a.into_iter().collect(); let mut b_v: Vec<_> = b.into_iter().collect(); - a_v.sort_by(|a, b| a.stable_cmp(tcx, b)); + // `skip_binder` here is okay because `stable_cmp` doesn't look at binders + a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); a_v.dedup(); - b_v.sort_by(|a, b| a.stable_cmp(tcx, b)); + b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); b_v.dedup(); if a_v.len() != b_v.len() { return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); @@ -626,14 +636,18 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| { use crate::ty::ExistentialPredicate::*; - match (ep_a, ep_b) { - (Trait(a), Trait(b)) => Ok(Trait(relation.relate(a, b)?)), - (Projection(a), Projection(b)) => Ok(Projection(relation.relate(a, b)?)), - (AutoTrait(a), AutoTrait(b)) if a == b => Ok(AutoTrait(a)), + match (ep_a.skip_binder(), ep_b.skip_binder()) { + (Trait(a), Trait(b)) => Ok(ty::Binder::bind(Trait( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + (Projection(a), Projection(b)) => Ok(ty::Binder::bind(Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + (AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))), _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))), } }); - Ok(tcx.mk_existential_predicates(v)?) + Ok(tcx.mk_poly_existential_predicates(v)?) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 89fd803fe5..7a1ca6a6c2 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,12 +7,12 @@ use crate::mir::ProjectionKind; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::{self, InferConst, Lift, Ty, TyCtxt}; +use rustc_data_structures::functor::IdFunctor; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::CRATE_DEF_INDEX; use rustc_index::vec::{Idx, IndexVec}; -use smallvec::SmallVec; use std::fmt; use std::ops::ControlFlow; use std::rc::Rc; @@ -65,7 +65,7 @@ impl fmt::Debug for ty::adjustment::Adjustment<'tcx> { } } -impl fmt::Debug for ty::BoundRegion { +impl fmt::Debug for ty::BoundRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ty::BrAnon(n) => write!(f, "BrAnon({:?})", n), @@ -274,7 +274,7 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> { // For things that don't carry any arena-allocated data (and are // copy...), just add them to this list. -CloneTypeFoldableAndLiftImpls! { +TrivialTypeFoldableAndLiftImpls! { (), bool, usize, @@ -308,13 +308,13 @@ CloneTypeFoldableAndLiftImpls! { crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, - // Including `BoundRegion` is a *bit* dubious, but direct + // Including `BoundRegionKind` is a *bit* dubious, but direct // references to bound region appear in `ty::Error`, and aren't // really meant to be folded. In general, we can only fold a fully // general `Region`. - crate::ty::BoundRegion, + crate::ty::BoundRegionKind, crate::ty::AssocItem, - crate::ty::Placeholder, + crate::ty::Placeholder, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, @@ -725,21 +725,21 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { /// AdtDefs are basically the same as a DefId. impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { - fn super_fold_with>(&self, _folder: &mut F) -> Self { - *self + fn super_fold_with>(self, _folder: &mut F) -> Self { + self } - fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { - fn super_fold_with>(&self, folder: &mut F) -> (T, U) { + fn super_fold_with>(self, folder: &mut F) -> (T, U) { (self.0.fold_with(folder), self.1.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.0.visit_with(visitor)?; self.1.visit_with(visitor) } @@ -748,11 +748,11 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (A, B, C) { - fn super_fold_with>(&self, folder: &mut F) -> (A, B, C) { + fn super_fold_with>(self, folder: &mut F) -> (A, B, C) { (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.0.visit_with(visitor)?; self.1.visit_with(visitor)?; self.2.visit_with(visitor) @@ -774,106 +774,107 @@ EnumTypeFoldableImpl! { } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { - fn super_fold_with>(&self, folder: &mut F) -> Self { - Rc::new((**self).fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Self { + // FIXME: Reuse the `Rc` here. + Rc::new((*self).clone().fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { (**self).visit_with(visitor) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc { - fn super_fold_with>(&self, folder: &mut F) -> Self { - Arc::new((**self).fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Self { + // FIXME: Reuse the `Arc` here. + Arc::new((*self).clone().fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { (**self).visit_with(visitor) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let content: T = (**self).fold_with(folder); - box content + fn super_fold_with>(self, folder: &mut F) -> Self { + self.map_id(|value| value.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { (**self).visit_with(visitor) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() + fn super_fold_with>(self, folder: &mut F) -> Self { + self.map_id(|t| t.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect::>().into_boxed_slice() + fn super_fold_with>(self, folder: &mut F) -> Self { + self.map_id(|t| t.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.map_bound_ref(|ty| ty.fold_with(folder)) + fn super_fold_with>(self, folder: &mut F) -> Self { + self.map_bound(|ty| ty.fold_with(folder)) } - fn fold_with>(&self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Self { folder.fold_binder(self) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.as_ref().skip_binder().visit_with(visitor) } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_binder(self) } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v)) +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List>> { + fn super_fold_with>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|p| p.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v)) + fn super_fold_with>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List { - fn super_fold_with>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_projs(v)) + fn super_fold_with>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { use crate::ty::InstanceDef::*; Self { substs: self.substs.fold_with(folder), @@ -893,7 +894,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { use crate::ty::InstanceDef::*; self.substs.visit_with(visitor)?; match self.def { @@ -915,36 +916,36 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { Self { instance: self.instance.fold_with(folder), promoted: self.promoted } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.instance.visit_with(visitor) } } impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let kind = match self.kind() { + fn super_fold_with>(self, folder: &mut F) -> Self { + let kind = match *self.kind() { ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), - ty::Adt(tid, substs) => ty::Adt(*tid, substs.fold_with(folder)), - ty::Dynamic(ref trait_ty, ref region) => { + ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)), + ty::Dynamic(trait_ty, region) => { ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)) } ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), - ty::FnDef(def_id, substs) => ty::FnDef(*def_id, substs.fold_with(folder)), + ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)), ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)), - ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), *mutbl), + ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), ty::Generator(did, substs, movability) => { - ty::Generator(*did, substs.fold_with(folder), *movability) + ty::Generator(did, substs.fold_with(folder), movability) } ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)), - ty::Closure(did, substs) => ty::Closure(*did, substs.fold_with(folder)), - ty::Projection(ref data) => ty::Projection(data.fold_with(folder)), - ty::Opaque(did, substs) => ty::Opaque(*did, substs.fold_with(folder)), + ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)), + ty::Projection(data) => ty::Projection(data.fold_with(folder)), + ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), ty::Bool | ty::Char @@ -964,11 +965,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) } } - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_ty(*self) + fn fold_with>(self, folder: &mut F) -> Self { + folder.fold_ty(self) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::Array(typ, sz) => { @@ -1010,40 +1011,40 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_ty(self) } } impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { - fn super_fold_with>(&self, _folder: &mut F) -> Self { - *self + fn super_fold_with>(self, _folder: &mut F) -> Self { + self } - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_region(*self) + fn fold_with>(self, folder: &mut F) -> Self { + folder.fold_region(self) } - fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { ControlFlow::CONTINUE } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_region(*self) } } impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let new = ty::PredicateKind::super_fold_with(&self.inner.kind, folder); - folder.tcx().reuse_or_mk_predicate(*self, new) + fn super_fold_with>(self, folder: &mut F) -> Self { + let new = ty::PredicateKind::super_fold_with(self.inner.kind, folder); + folder.tcx().reuse_or_mk_predicate(self, new) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { ty::PredicateKind::super_visit_with(&self.inner.kind, visitor) } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_predicate(*self) } @@ -1057,53 +1058,53 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) + fn super_fold_with>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|p| p.visit_with(visitor)) } } impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|x| x.fold_with(folder)).collect() + fn super_fold_with>(self, folder: &mut F) -> Self { + self.map_id(|x| x.fold_with(folder)) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { let ty = self.ty.fold_with(folder); let val = self.val.fold_with(folder); if ty != self.ty || val != self.val { folder.tcx().mk_const(ty::Const { ty, val }) } else { - *self + self } } - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_const(*self) + fn fold_with>(self, folder: &mut F) -> Self { + folder.fold_const(self) } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.ty.visit_with(visitor)?; self.val.visit_with(visitor) } - fn visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_const(self) } } impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { + fn super_fold_with>(self, folder: &mut F) -> Self { + match self { ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), ty::ConstKind::Unevaluated(did, substs, promoted) => { @@ -1112,11 +1113,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) - | ty::ConstKind::Error(_) => *self, + | ty::ConstKind::Error(_) => self, } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor), @@ -1130,42 +1131,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { - fn super_fold_with>(&self, _folder: &mut F) -> Self { - *self + fn super_fold_with>(self, _folder: &mut F) -> Self { + self } - fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { ControlFlow::CONTINUE } } - -// Does the equivalent of -// ``` -// let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); -// folder.tcx().intern_*(&v) -// ``` -fn fold_list<'tcx, F, T>( - list: &'tcx ty::List, - folder: &mut F, - intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List, -) -> &'tcx ty::List -where - F: TypeFolder<'tcx>, - T: TypeFoldable<'tcx> + PartialEq + Copy, -{ - let mut iter = list.iter(); - // Look for the first element that changed - if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| { - let new_t = t.fold_with(folder); - if new_t == t { None } else { Some((i, new_t)) } - }) { - // An element changed, prepare to intern the resulting list - let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); - new_list.extend_from_slice(&list[..i]); - new_list.push(new_t); - new_list.extend(iter.map(|t| t.fold_with(folder))); - intern(folder.tcx(), &new_list) - } else { - list - } -} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 384d08f834..4ce76409c6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -40,12 +40,12 @@ pub struct TypeAndMut<'tcx> { /// at least as big as the scope `fr.scope`". pub struct FreeRegion { pub scope: DefId, - pub bound_region: BoundRegion, + pub bound_region: BoundRegionKind, } #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] #[derive(HashStable)] -pub enum BoundRegion { +pub enum BoundRegionKind { /// An anonymous region parameter for a given fn (&T) BrAnon(u32), @@ -60,26 +60,36 @@ pub enum BoundRegion { BrEnv, } -impl BoundRegion { - pub fn is_named(&self) -> bool { - match *self { - BoundRegion::BrNamed(_, name) => name != kw::UnderscoreLifetime, - _ => false, - } - } +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] +#[derive(HashStable)] +pub struct BoundRegion { + pub kind: BoundRegionKind, +} +impl BoundRegion { /// When canonicalizing, we replace unbound inference variables and free /// regions with anonymous late bound regions. This method asserts that /// we have an anonymous late bound region, which hence may refer to /// a canonical variable. pub fn assert_bound_var(&self) -> BoundVar { - match *self { - BoundRegion::BrAnon(var) => BoundVar::from_u32(var), + match self.kind { + BoundRegionKind::BrAnon(var) => BoundVar::from_u32(var), _ => bug!("bound region is not anonymous"), } } } +impl BoundRegionKind { + pub fn is_named(&self) -> bool { + match *self { + BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime, + _ => false, + } + } +} + +/// Defines the kinds of types. +/// /// N.B., if you change this, you'll probably want to change the corresponding /// AST structure in `librustc_ast/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)] @@ -102,7 +112,7 @@ pub enum TyKind<'tcx> { /// A primitive floating-point type. For example, `f64`. Float(ast::FloatTy), - /// Structures, enumerations and unions. + /// Algebraic data types (ADT). For example: structures, enumerations and unions. /// /// InternalSubsts here, possibly against intuition, *may* contain `Param`s. /// That is, even after substitution it is possible that there are type @@ -152,7 +162,7 @@ pub enum TyKind<'tcx> { FnPtr(PolyFnSig<'tcx>), /// A trait, defined with `trait`. - Dynamic(Binder<&'tcx List>>, ty::Region<'tcx>), + Dynamic(&'tcx List>>, ty::Region<'tcx>), /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. @@ -162,11 +172,11 @@ pub enum TyKind<'tcx> { /// `|a| yield a`. Generator(DefId, SubstsRef<'tcx>, hir::Movability), - /// A type representin the types stored inside a generator. + /// A type representing the types stored inside a generator. /// This should only appear in GeneratorInteriors. GeneratorWitness(Binder<&'tcx List>>), - /// The never type `!` + /// The never type `!`. Never, /// A tuple type. For example, `(i32, bool)`. @@ -205,10 +215,7 @@ pub enum TyKind<'tcx> { impl TyKind<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - match self { - Bool | Char | Int(_) | Uint(_) | Float(_) => true, - _ => false, - } + matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_)) } /// Get the article ("a" or "an") to use with this type. @@ -762,7 +769,7 @@ impl<'tcx> Binder> { } } -impl<'tcx> List> { +impl<'tcx> List>> { /// Returns the "principal `DefId`" of this set of existential predicates. /// /// A Rust trait object type consists (in addition to a lifetime bound) @@ -788,64 +795,42 @@ impl<'tcx> List> { /// is `{Send, Sync}`, while there is no principal. These trait objects /// have a "trivial" vtable consisting of just the size, alignment, /// and destructor. - pub fn principal(&self) -> Option> { - match self[0] { - ExistentialPredicate::Trait(tr) => Some(tr), - _ => None, - } + pub fn principal(&self) -> Option>> { + self[0] + .map_bound(|this| match this { + ExistentialPredicate::Trait(tr) => Some(tr), + _ => None, + }) + .transpose() } pub fn principal_def_id(&self) -> Option { - self.principal().map(|trait_ref| trait_ref.def_id) + self.principal().map(|trait_ref| trait_ref.skip_binder().def_id) } #[inline] pub fn projection_bounds<'a>( &'a self, - ) -> impl Iterator> + 'a { - self.iter().filter_map(|predicate| match predicate { - ExistentialPredicate::Projection(projection) => Some(projection), - _ => None, + ) -> impl Iterator>> + 'a { + self.iter().filter_map(|predicate| { + predicate + .map_bound(|pred| match pred { + ExistentialPredicate::Projection(projection) => Some(projection), + _ => None, + }) + .transpose() }) } #[inline] pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.iter().filter_map(|predicate| match predicate { + self.iter().filter_map(|predicate| match predicate.skip_binder() { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, }) } } -impl<'tcx> Binder<&'tcx List>> { - pub fn principal(&self) -> Option>> { - self.map_bound(|b| b.principal()).transpose() - } - - pub fn principal_def_id(&self) -> Option { - self.skip_binder().principal_def_id() - } - - #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator> + 'a { - self.skip_binder().projection_bounds().map(Binder::bind) - } - - #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.skip_binder().auto_traits() - } - - pub fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator>> + 'tcx { - self.skip_binder().iter().map(Binder::bind) - } -} - /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: /// @@ -1001,7 +986,7 @@ impl Binder { T: TypeFoldable<'tcx>, { if value.has_escaping_bound_vars() { - Binder::bind(super::fold::shift_vars(tcx, &value, 1)) + Binder::bind(super::fold::shift_vars(tcx, value, 1)) } else { Binder::dummy(value) } @@ -1106,10 +1091,7 @@ impl Binder { impl Binder> { pub fn transpose(self) -> Option> { - match self.0 { - Some(v) => Some(Binder(v)), - None => None, - } + self.0.map(Binder) } } @@ -1292,53 +1274,6 @@ impl<'tcx> ParamConst { } } -rustc_index::newtype_index! { - /// A [De Bruijn index][dbi] is a standard means of representing - /// regions (and perhaps later types) in a higher-ranked setting. In - /// particular, imagine a type like this: - /// - /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) - /// ^ ^ | | | - /// | | | | | - /// | +------------+ 0 | | - /// | | | - /// +----------------------------------+ 1 | - /// | | - /// +----------------------------------------------+ 0 - /// - /// In this type, there are two binders (the outer fn and the inner - /// fn). We need to be able to determine, for any given region, which - /// fn type it is bound by, the inner or the outer one. There are - /// various ways you can do this, but a De Bruijn index is one of the - /// more convenient and has some nice properties. The basic idea is to - /// count the number of binders, inside out. Some examples should help - /// clarify what I mean. - /// - /// Let's start with the reference type `&'b isize` that is the first - /// argument to the inner function. This region `'b` is assigned a De - /// Bruijn index of 0, meaning "the innermost binder" (in this case, a - /// fn). The region `'a` that appears in the second argument type (`&'a - /// isize`) would then be assigned a De Bruijn index of 1, meaning "the - /// second-innermost binder". (These indices are written on the arrays - /// in the diagram). - /// - /// What is interesting is that De Bruijn index attached to a particular - /// variable will vary depending on where it appears. For example, - /// the final type `&'a char` also refers to the region `'a` declared on - /// the outermost fn. But this time, this reference is not nested within - /// any other binders (i.e., it is not an argument to the inner fn, but - /// rather the outer one). Therefore, in this case, it is assigned a - /// De Bruijn index of 0, because the innermost binder in that location - /// is the outer fn. - /// - /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index - #[derive(HashStable)] - pub struct DebruijnIndex { - DEBUG_FORMAT = "DebruijnIndex({})", - const INNERMOST = 0, - } -} - pub type Region<'tcx> = &'tcx RegionKind; /// Representation of regions. Note that the NLL checker uses a distinct @@ -1453,7 +1388,7 @@ pub enum RegionKind { /// Region bound in a function scope, which will be substituted when the /// function is called. - ReLateBound(DebruijnIndex, BoundRegion), + ReLateBound(ty::DebruijnIndex, BoundRegion), /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free @@ -1617,72 +1552,13 @@ impl<'tcx> PolyExistentialProjection<'tcx> { } } -impl DebruijnIndex { - /// Returns the resulting index when this value is moved into - /// `amount` number of new binders. So, e.g., if you had - /// - /// for<'a> fn(&'a x) - /// - /// and you wanted to change it to - /// - /// for<'a> fn(for<'b> fn(&'a x)) - /// - /// you would need to shift the index for `'a` into a new binder. - #[must_use] - pub fn shifted_in(self, amount: u32) -> DebruijnIndex { - DebruijnIndex::from_u32(self.as_u32() + amount) - } - - /// Update this index in place by shifting it "in" through - /// `amount` number of binders. - pub fn shift_in(&mut self, amount: u32) { - *self = self.shifted_in(amount); - } - - /// Returns the resulting index when this value is moved out from - /// `amount` number of new binders. - #[must_use] - pub fn shifted_out(self, amount: u32) -> DebruijnIndex { - DebruijnIndex::from_u32(self.as_u32() - amount) - } - - /// Update in place by shifting out from `amount` binders. - pub fn shift_out(&mut self, amount: u32) { - *self = self.shifted_out(amount); - } - - /// Adjusts any De Bruijn indices so as to make `to_binder` the - /// innermost binder. That is, if we have something bound at `to_binder`, - /// it will now be bound at INNERMOST. This is an appropriate thing to do - /// when moving a region out from inside binders: - /// - /// ``` - /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) - /// // Binder: D3 D2 D1 ^^ - /// ``` - /// - /// Here, the region `'a` would have the De Bruijn index D3, - /// because it is the bound 3 binders out. However, if we wanted - /// to refer to that region `'a` in the second argument (the `_`), - /// those two binders would not be in scope. In that case, we - /// might invoke `shift_out_to_binder(D3)`. This would adjust the - /// De Bruijn index of `'a` to D1 (the innermost binder). - /// - /// If we invoke `shift_out_to_binder` and the region is in fact - /// bound by one of the binders we are shifting out of, that is an - /// error (and should fail an assertion failure). - pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { - self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32()) - } -} - /// Region utilities impl RegionKind { /// Is this region named by the user? pub fn has_name(&self) -> bool { match *self { RegionKind::ReEarlyBound(ebr) => ebr.has_name(), - RegionKind::ReLateBound(_, br) => br.is_named(), + RegionKind::ReLateBound(_, br) => br.kind.is_named(), RegionKind::ReFree(fr) => fr.bound_region.is_named(), RegionKind::ReStatic => true, RegionKind::ReVar(..) => false, @@ -1693,20 +1569,14 @@ impl RegionKind { } pub fn is_late_bound(&self) -> bool { - match *self { - ty::ReLateBound(..) => true, - _ => false, - } + matches!(*self, ty::ReLateBound(..)) } pub fn is_placeholder(&self) -> bool { - match *self { - ty::RePlaceholder(..) => true, - _ => false, - } + matches!(*self, ty::RePlaceholder(..)) } - pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool { + pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn >= index, _ => false, @@ -1959,27 +1829,22 @@ impl<'tcx> TyS<'tcx> { } } - pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind() { - Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs), - _ => bug!("`simd_type` called on invalid type"), - } - } - - pub fn simd_size(&self, _tcx: TyCtxt<'tcx>) -> u64 { - // Parameter currently unused, but probably needed in the future to - // allow `#[repr(simd)] struct Simd([T; N]);`. - match self.kind() { - Adt(def, _) => def.non_enum_variant().fields.len() as u64, - _ => bug!("`simd_size` called on invalid type"), - } - } - pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { match self.kind() { Adt(def, substs) => { let variant = def.non_enum_variant(); - (variant.fields.len() as u64, variant.fields[0].ty(tcx, substs)) + let f0_ty = variant.fields[0].ty(tcx, substs); + + match f0_ty.kind() { + Array(f0_elem_ty, f0_len) => { + // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 + // The way we evaluate the `N` in `[T; N]` here only works since we use + // `simd_size_and_type` post-monomorphization. It will probably start to ICE + // if we use it in generic code. See the `simd-array-trait` ui test. + (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty) + } + _ => (variant.fields.len() as u64, f0_ty), + } } _ => bug!("`simd_size_and_type` called on invalid type"), } @@ -2182,6 +2047,15 @@ impl<'tcx> TyS<'tcx> { } } + /// Get the `i`-th element of a tuple. + /// Panics when called on anything but a tuple. + pub fn tuple_element_ty(&self, i: usize) -> Option> { + match self.kind() { + Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()), + _ => bug!("tuple_fields called on non-tuple"), + } + } + /// If the type contains variants, returns the valid range of variant indices. // // FIXME: This requires the optimized MIR in the case of generators. @@ -2221,13 +2095,44 @@ impl<'tcx> TyS<'tcx> { } /// Returns the type of the discriminant of this type. - pub fn discriminant_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx), ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), - _ => { - // This can only be `0`, for now, so `u8` will suffice. - tcx.types.u8 + + ty::Param(_) | ty::Projection(_) | ty::Opaque(..) | ty::Infer(ty::TyVar(_)) => { + let assoc_items = + tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); + let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; + tcx.mk_projection(discriminant_def_id, tcx.mk_substs([self.into()].iter())) + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Foreign(_) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::GeneratorWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) + | ty::Infer(IntVar(_) | FloatVar(_)) => tcx.types.u8, + + ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("`discriminant_ty` applied to unexpected type: {:?}", self) } } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 07f775cf8b..5d1b976ae9 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -152,7 +152,7 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { } impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { match self.unpack() { GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), GenericArgKind::Type(ty) => ty.fold_with(folder).into(), @@ -160,7 +160,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { match self.unpack() { GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), GenericArgKind::Type(ty) => ty.visit_with(visitor), @@ -363,7 +363,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { // This code is hot enough that it's worth specializing for the most // common length lists, to avoid the overhead of `SmallVec` creation. // The match arms are in order of frequency. The 1, 2, and 0 cases are @@ -392,7 +392,7 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { } } - fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<()> { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -405,12 +405,12 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { // there is more information available (for better errors). pub trait Subst<'tcx>: Sized { - fn subst(&self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self { + fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self { self.subst_spanned(tcx, substs, None) } fn subst_spanned( - &self, + self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>], span: Option, @@ -419,13 +419,13 @@ pub trait Subst<'tcx>: Sized { impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T { fn subst_spanned( - &self, + self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>], span: Option, ) -> T { let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 }; - (*self).fold_with(&mut folder) + self.fold_with(&mut folder) } } @@ -448,7 +448,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { self.tcx } - fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { self.binders_passed += 1; let t = t.super_fold_with(self); self.binders_passed -= 1; @@ -634,7 +634,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { return val; } - let result = ty::fold::shift_vars(self.tcx(), &val, self.binders_passed); + let result = ty::fold::shift_vars(self.tcx(), val, self.binders_passed); debug!("shift_vars: shifted result = {:?}", result); result diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 5f117e19ec..a64580336a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -18,7 +18,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; use std::{cmp, fmt}; @@ -160,7 +160,7 @@ impl<'tcx> TyCtxt<'tcx> { // We want the type_id be independent of the types free regions, so we // erase them. The erase_regions() call will also anonymize bound // regions, which is desirable too. - let ty = self.erase_regions(&ty); + let ty = self.erase_regions(ty); hcx.while_hashing_spans(false, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -221,7 +221,13 @@ impl<'tcx> TyCtxt<'tcx> { mut ty: Ty<'tcx>, normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { - loop { + for iteration in 0.. { + if !self.sess.recursion_limit().value_within_limit(iteration) { + return self.ty_error_with_message( + DUMMY_SP, + &format!("reached the recursion limit finding the struct tail for {}", ty), + ); + } match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { @@ -497,7 +503,8 @@ impl<'tcx> TyCtxt<'tcx> { closure_substs: SubstsRef<'tcx>, ) -> Option>> { let closure_ty = self.mk_closure(closure_def_id, closure_substs); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let br = ty::BoundRegion { kind: ty::BrEnv }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { @@ -1130,6 +1137,37 @@ pub fn needs_drop_components( } } +// Does the equivalent of +// ``` +// let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); +// folder.tcx().intern_*(&v) +// ``` +pub fn fold_list<'tcx, F, T>( + list: &'tcx ty::List, + folder: &mut F, + intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List, +) -> &'tcx ty::List +where + F: TypeFolder<'tcx>, + T: TypeFoldable<'tcx> + PartialEq + Copy, +{ + let mut iter = list.iter(); + // Look for the first element that changed + if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| { + let new_t = t.fold_with(folder); + if new_t == t { None } else { Some((i, new_t)) } + }) { + // An element changed, prepare to intern the resulting list + let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); + new_list.extend_from_slice(&list[..i]); + new_list.push(new_t); + new_list.extend(iter.map(|t| t.fold_with(folder))); + intern(folder.tcx(), &new_list) + } else { + list + } +} + #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub struct AlwaysRequiresDrop; diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml index 487668cfa1..10dbf35fed 100644 --- a/compiler/rustc_mir/Cargo.toml +++ b/compiler/rustc_mir/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] either = "1.5.0" rustc_graphviz = { path = "../rustc_graphviz" } +gsgdt = "0.1.2" itertools = "0.9" tracing = "0.1" polonius-engine = "0.12.0" @@ -31,3 +32,6 @@ rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } rustc_apfloat = { path = "../rustc_apfloat" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } + +[dev-dependencies] +coverage_test_macros = { path = "src/transform/coverage/test_macros" } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 4256f6e39d..81571fd730 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -383,16 +383,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.describe_field_from_ty(&ty, field, variant_index) } ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - // `tcx.upvars_mentioned(def_id)` returns an `Option`, which is `None` in case - // the closure comes from another crate. But in that case we wouldn't - // be borrowck'ing it, so we can just unwrap: - let (&var_id, _) = self - .infcx - .tcx - .upvars_mentioned(def_id) - .unwrap() - .get_index(field.index()) - .unwrap(); + // We won't be borrowck'ing here if the closure came from another crate, + // so it's safe to call `expect_local`. + // + // We know the field exists so it's safe to call operator[] and `unwrap` here. + let (&var_id, _) = + self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id] + .get_index(field.index()) + .unwrap(); self.infcx.tcx.hir().name(var_id).to_string() } @@ -498,7 +496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // lifetimes without names with the value `'0`. match ty.kind() { ty::Ref( - ty::RegionKind::ReLateBound(_, br) + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, @@ -519,7 +517,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let region = match ty.kind() { ty::Ref(region, _, _) => { match region { - ty::RegionKind::ReLateBound(_, br) + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { printer.region_highlight_mode.highlighting_bound_region(*br, counter) } @@ -967,9 +965,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for ((upvar_hir_id, upvar), place) in - self.infcx.tcx.upvars_mentioned(def_id)?.iter().zip(places) + for (upvar_hir_id, place) in + self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id] + .keys() + .zip(places) { + let span = self.infcx.tcx.upvars_mentioned(local_did)?[upvar_hir_id].span; match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => @@ -991,7 +992,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let usage_span = match self.infcx.tcx.typeck(local_did).upvar_capture(upvar_id) { ty::UpvarCapture::ByValue(Some(span)) => span, - _ => upvar.span, + _ => span, }; return Some((*args_span, generator_kind, usage_span)); } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index e22dab0151..78da43c31c 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// Returns `true` if a closure is inferred to be an `FnMut` closure. fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) { - if let ty::BoundRegion::BrEnv = free_region.bound_region { + if let ty::BoundRegionKind::BrEnv = free_region.bound_region { if let DefiningTy::Closure(_, substs) = self.regioncx.universal_regions().defining_ty { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 2a90fb042d..cbca012824 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -281,7 +281,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } ty::ReFree(free_region) => match free_region.bound_region { - ty::BoundRegion::BrNamed(region_def_id, name) => { + ty::BoundRegionKind::BrNamed(region_def_id, name) => { // Get the span to point to, even if we don't use the name. let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP); debug!( @@ -307,7 +307,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } } - ty::BoundRegion::BrEnv => { + ty::BoundRegionKind::BrEnv => { let def_ty = self.regioncx.universal_regions().defining_ty; if let DefiningTy::Closure(_, substs) = def_ty { @@ -349,7 +349,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } } - ty::BoundRegion::BrAnon(_) => None, + ty::BoundRegionKind::BrAnon(_) => None, }, ty::ReLateBound(..) @@ -445,7 +445,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", type_name, needle_fr ); - if type_name.find(&format!("'{}", counter)).is_some() { + if type_name.contains(&format!("'{}", counter)) { // Only add a label if we can confirm that a region was labelled. RegionNameHighlight::CannotMatchHirTy(span, type_name) } else { diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index de54c5582e..44044d5553 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -9,9 +9,10 @@ use rustc_hir::{HirId, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, - PlaceRef, + PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; @@ -75,6 +76,7 @@ crate use region_infer::RegionInferenceContext; crate struct Upvar { name: Symbol, + // FIXME(project-rfc-2229#8): This should use Place or something similar var_hir_id: HirId, /// If true, the capture is behind a reference. @@ -133,19 +135,21 @@ fn do_mir_borrowck<'a, 'tcx>( let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); for var_debug_info in &input_body.var_debug_info { - if let Some(local) = var_debug_info.place.as_local() { - if let Some(prev_name) = local_names[local] { - if var_debug_info.name != prev_name { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); + if let VarDebugInfoContents::Place(place) = var_debug_info.value { + if let Some(local) = place.as_local() { + if let Some(prev_name) = local_names[local] { + if var_debug_info.name != prev_name { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); + } } + local_names[local] = Some(var_debug_info.name); } - local_names[local] = Some(var_debug_info.name); } } @@ -155,13 +159,13 @@ fn do_mir_borrowck<'a, 'tcx>( infcx.set_tainted_by_errors(); } let upvars: Vec<_> = tables - .closure_captures - .get(&def.did.to_def_id()) - .into_iter() - .flat_map(|v| v.values()) - .map(|upvar_id| { - let var_hir_id = upvar_id.var_path.hir_id; - let capture = tables.upvar_capture(*upvar_id); + .closure_min_captures_flattened(def.did.to_def_id()) + .map(|captured_place| { + let var_hir_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected upvar"), + }; + let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index a5a7012852..9d45f6fd0d 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -876,7 +876,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Type-test failed. Report the error. - let erased_generic_kind = infcx.tcx.erase_regions(&type_test.generic_kind); + let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind); // Skip duplicate-ish errors. if deduplicate_errors.insert(( @@ -1006,7 +1006,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("try_promote_type_test_subject(ty = {:?})", ty); - let ty = tcx.fold_regions(&ty, &mut false, |r, _depth| { + let ty = tcx.fold_regions(ty, &mut false, |r, _depth| { let region_vid = self.to_region_vid(r); // The challenge if this. We have some region variable `r` @@ -1145,8 +1145,24 @@ impl<'tcx> RegionInferenceContext<'tcx> { for ur in self.scc_values.universal_regions_outlived_by(r_scc) { let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub); + // The upper bound of two non-static regions is static: this + // means we know nothing about the relationship between these + // two regions. Pick a 'better' one to use when constructing + // a diagnostic if ur != static_r && lub != static_r && new_lub == static_r { - lub = std::cmp::min(ur, lub); + // Prefer the region with an `external_name` - this + // indicates that the region is early-bound, so working with + // it can produce a nicer error. + if self.region_definition(ur).external_name.is_some() { + lub = ur; + } else if self.region_definition(lub).external_name.is_some() { + // Leave lub unchanged + } else { + // If we get here, we don't have any reason to prefer + // one region over the other. Just pick the + // one with the lower index for now. + lub = std::cmp::min(ur, lub); + } } else { lub = new_lub; } @@ -1248,7 +1264,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(&value, &mut false, |r, _db| { + tcx.fold_regions(value, &mut false, |r, _db| { let vid = self.to_region_vid(r); let scc = self.constraint_sccs.scc(vid); let repr = self.scc_representatives[scc]; diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs index 325dca8c8c..f7c902355c 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs @@ -63,7 +63,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut subst_regions = vec![self.universal_regions.fr_static]; let universal_substs = - infcx.tcx.fold_regions(&substs, &mut false, |region, _| match *region { + infcx.tcx.fold_regions(substs, &mut false, |region, _| match *region { ty::ReVar(vid) => { subst_regions.push(vid); self.definitions[vid].external_name.unwrap_or_else(|| { @@ -94,7 +94,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { subst_regions.dedup(); let universal_concrete_type = - infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match *region { + infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region { ty::ReVar(vid) => subst_regions .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) @@ -139,7 +139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(&ty, &mut false, |region, _| match *region { + tcx.fold_regions(ty, &mut false, |region, _| match *region { ty::ReVar(vid) => { // Find something that we can name let upper_bound = self.approx_universal_upper_bound(vid); diff --git a/compiler/rustc_mir/src/borrow_check/renumber.rs b/compiler/rustc_mir/src/borrow_check/renumber.rs index 5df033b48c..e563e37adc 100644 --- a/compiler/rustc_mir/src/borrow_check/renumber.rs +++ b/compiler/rustc_mir/src/borrow_check/renumber.rs @@ -26,7 +26,7 @@ pub fn renumber_mir<'tcx>( /// Replaces all regions appearing in `value` with fresh inference /// variables. -pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: &T) -> T +pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -43,7 +43,7 @@ struct NLLVisitor<'a, 'tcx> { } impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { - fn renumber_regions(&mut self, value: &T) -> T + fn renumber_regions(&mut self, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -70,7 +70,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { _: Location, ) -> Option> { if let PlaceElem::Field(field, ty) = elem { - let new_ty = self.renumber_regions(&ty); + let new_ty = self.renumber_regions(ty); if new_ty != ty { return Some(PlaceElem::Field(field, new_ty)); @@ -83,7 +83,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { debug!("visit_substs(substs={:?}, location={:?})", substs, location); - *substs = self.renumber_regions(&{ *substs }); + *substs = self.renumber_regions(*substs); debug!("visit_substs: substs={:?}", substs); } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs index 444f9fe8d0..b7d22fab3d 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( body.span, LateBoundRegionConversionTime::FnCall, - &poly_sig, + poly_sig, ) .0, ) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 409399094e..42cd050abc 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -749,7 +749,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { (&adt_def.variants[VariantIdx::new(0)], substs) } ty::Closure(_, substs) => { - return match substs.as_closure().upvar_tys().nth(field.index()) { + return match substs + .as_closure() + .tupled_upvars_ty() + .tuple_element_ty(field.index()) + { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { field_count: substs.as_closure().upvar_tys().count(), @@ -784,7 +788,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }; if let Some(field) = variant.fields.get(field.index()) { - Ok(self.cx.normalize(&field.ty(tcx, substs), location)) + Ok(self.cx.normalize(field.ty(tcx, substs), location)) } else { Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) } @@ -1245,7 +1249,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_owner_def_id, dummy_body_id, param_env, - &anon_ty, + anon_ty, locations.span(body), )); debug!( @@ -1271,7 +1275,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); for (&opaque_def_id, opaque_decl) in &opaque_type_map { - let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty); + let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty); let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { *def_id == opaque_def_id } else { @@ -1296,7 +1300,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let subst_opaque_defn_ty = opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs); let renumbered_opaque_defn_ty = - renumber::renumber_regions(infcx, &subst_opaque_defn_ty); + renumber::renumber_regions(infcx, subst_opaque_defn_ty); debug!( "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", @@ -1601,7 +1605,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars( term.source_info.span, LateBoundRegionConversionTime::FnCall, - &sig, + sig, ); let sig = self.normalize(sig, term_location); self.check_call_dest(body, term, &sig, destination, term_location); @@ -1900,7 +1904,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Erase the regions from `ty` to get a global type. The // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. - let erased_ty = tcx.erase_regions(&ty); + let erased_ty = tcx.erase_regions(ty); if !erased_ty.is_sized(tcx.at(span), self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return @@ -1984,44 +1988,48 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // If the length is larger than 1, the repeat expression will need to copy the // element, so we require the `Copy` trait. if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { - if let Operand::Move(_) = operand { - // While this is located in `nll::typeck` this error is not an NLL error, it's - // a required check to make sure that repeated elements implement `Copy`. - let span = body.source_info(location).span; - let ty = operand.ty(body, tcx); - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { - let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); - // To determine if `const_in_array_repeat_expressions` feature gate should - // be mentioned, need to check if the rvalue is promotable. - let should_suggest = - should_suggest_const_in_array_repeat_expressions_attribute( - &ccx, operand, - ); - debug!("check_rvalue: should_suggest={:?}", should_suggest); - - let def_id = body.source.def_id().expect_local(); - self.infcx.report_selection_error( - &traits::Obligation::new( - ObligationCause::new( - span, - self.tcx().hir().local_def_id_to_hir_id(def_id), - traits::ObligationCauseCode::RepeatVec(should_suggest), - ), - self.param_env, - ty::Binder::bind(ty::TraitRef::new( - self.tcx().require_lang_item( - LangItem::Copy, - Some(self.last_span), + match operand { + Operand::Copy(..) | Operand::Constant(..) => { + // These are always okay: direct use of a const, or a value that can evidently be copied. + } + Operand::Move(_) => { + // Make sure that repeated elements implement `Copy`. + let span = body.source_info(location).span; + let ty = operand.ty(body, tcx); + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { + let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env); + // To determine if `const_in_array_repeat_expressions` feature gate should + // be mentioned, need to check if the rvalue is promotable. + let should_suggest = + should_suggest_const_in_array_repeat_expressions_attribute( + &ccx, operand, + ); + debug!("check_rvalue: should_suggest={:?}", should_suggest); + + let def_id = body.source.def_id().expect_local(); + self.infcx.report_selection_error( + &traits::Obligation::new( + ObligationCause::new( + span, + self.tcx().hir().local_def_id_to_hir_id(def_id), + traits::ObligationCauseCode::RepeatVec(should_suggest), ), - tcx.mk_substs_trait(ty, &[]), - )) - .without_const() - .to_predicate(self.tcx()), - ), - &traits::SelectionError::Unimplemented, - false, - false, - ); + self.param_env, + ty::Binder::bind(ty::TraitRef::new( + self.tcx().require_lang_item( + LangItem::Copy, + Some(self.last_span), + ), + tcx.mk_substs_trait(ty, &[]), + )) + .without_const() + .to_predicate(self.tcx()), + ), + &traits::SelectionError::Unimplemented, + false, + false, + ); + } } } } diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs index 4742113b1a..c1a0d9856b 100644 --- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -438,7 +438,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( FR, self.mir_def.did, - &bound_inputs_and_output, + bound_inputs_and_output, &mut indices, ); // Converse of above, if this is a function then the late-bound regions declared on its @@ -522,7 +522,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { debug!("defining_ty (pre-replacement): {:?}", defining_ty); let defining_ty = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, &defining_ty); + self.infcx.replace_free_regions_with_nll_infer_vars(FR, defining_ty); match *defining_ty.kind() { ty::Closure(def_id, substs) => DefiningTy::Closure(def_id, substs), @@ -543,7 +543,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id); let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); let substs = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs); + self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); DefiningTy::Const(self.mir_def.did.to_def_id(), substs) } } @@ -628,7 +628,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::FnDef(def_id, _) => { let sig = tcx.fn_sig(def_id); - let sig = indices.fold_to_region_vids(tcx, &sig); + let sig = indices.fold_to_region_vids(tcx, sig); sig.inputs_and_output() } @@ -637,7 +637,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // "output" (the type of the constant). assert_eq!(self.mir_def.did.to_def_id(), def_id); let ty = tcx.type_of(self.mir_def.def_id_for_type_of()); - let ty = indices.fold_to_region_vids(tcx, &ty); + let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.intern_type_list(&[ty])) } } @@ -648,7 +648,7 @@ trait InferCtxtExt<'tcx> { fn replace_free_regions_with_nll_infer_vars( &self, origin: NLLRegionVariableOrigin, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>; @@ -657,7 +657,7 @@ trait InferCtxtExt<'tcx> { &self, origin: NLLRegionVariableOrigin, all_outlive_scope: LocalDefId, - value: &ty::Binder, + value: ty::Binder, indices: &mut UniversalRegionIndices<'tcx>, ) -> T where @@ -674,7 +674,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { fn replace_free_regions_with_nll_infer_vars( &self, origin: NLLRegionVariableOrigin, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>, @@ -686,7 +686,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { &self, origin: NLLRegionVariableOrigin, all_outlive_scope: LocalDefId, - value: &ty::Binder, + value: ty::Binder, indices: &mut UniversalRegionIndices<'tcx>, ) -> T where @@ -700,7 +700,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br); let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: all_outlive_scope.to_def_id(), - bound_region: br, + bound_region: br.kind, })); let region_vid = self.next_nll_region_var(origin); indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); @@ -771,7 +771,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// Replaces all free regions in `value` with region vids, as /// returned by `to_region_vid`. - pub fn fold_to_region_vids(&self, tcx: TyCtxt<'tcx>, value: &T) -> T + pub fn fold_to_region_vids(&self, tcx: TyCtxt<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -795,7 +795,7 @@ fn for_each_late_bound_region_defined_on<'tcx>( let region_def_id = tcx.hir().local_def_id(hir_id); let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: fn_def_id, - bound_region: ty::BoundRegion::BrNamed(region_def_id.to_def_id(), name), + bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name), })); f(liberated_region); } diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 39358e03e7..0e610e3755 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -20,6 +20,7 @@ pub enum ConstEvalErrKind { ModifiedGlobal, AssertFailure(AssertKind), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Abort(String), } // The errors become `MachineStop` with plain strings when being raised. @@ -46,6 +47,7 @@ impl fmt::Display for ConstEvalErrKind { Panic { msg, line, col, file } => { write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) } + Abort(ref msg) => write!(f, "{}", msg), } } } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 0cac7c087d..df163f6562 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -6,6 +6,7 @@ use crate::interpret::{ ScalarMaybeUninit, StackPopCleanup, }; +use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; @@ -30,6 +31,19 @@ fn eval_body_using_ecx<'mir, 'tcx>( ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); let tcx = *ecx.tcx; + assert!( + cid.promoted.is_some() + || matches!( + ecx.tcx.def_kind(cid.instance.def_id()), + DefKind::Const + | DefKind::Static + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::AssocConst + ), + "Unexpected DefKind: {:?}", + ecx.tcx.def_kind(cid.instance.def_id()) + ); let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); @@ -39,15 +53,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); - // Assert all args (if any) are zero-sized types; `eval_body_using_ecx` doesn't - // make sense if the body is expecting nontrivial arguments. - // (The alternative would be to use `eval_fn_call` with an args slice.) - for arg in body.args_iter() { - let decl = body.local_decls.get(arg).expect("arg missing from local_decls"); - let layout = ecx.layout_of(decl.ty.subst(tcx, cid.instance.substs))?; - assert!(layout.is_zst()) - } - ecx.push_stack_frame( cid.instance, body, @@ -274,6 +279,16 @@ pub fn eval_to_allocation_raw_provider<'tcx>( return Err(ErrorHandled::Reported(error_reported)); } } + if !tcx.is_mir_available(def.did) { + tcx.sess.delay_span_bug( + tcx.def_span(def.did), + &format!("no MIR body is available for {:?}", def.did), + ); + return Err(ErrorHandled::Reported(ErrorReported {})); + } + if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured { + return Err(ErrorHandled::Reported(error_reported)); + } } let is_static = tcx.is_static(def.did); @@ -368,25 +383,19 @@ pub fn eval_to_allocation_raw_provider<'tcx>( Ok(mplace) => { // Since evaluation had no errors, valiate the resulting constant: let validation = try { - // FIXME do not validate promoteds until a decision on - // https://github.com/rust-lang/rust/issues/67465 and - // https://github.com/rust-lang/rust/issues/67534 is made. - // Promoteds can contain unexpected `UnsafeCell` and reference `static`s, but their - // otherwise restricted form ensures that this is still sound. We just lose the - // extra safety net of some of the dynamic checks. They can also contain invalid - // values, but since we do not usually check intermediate results of a computation - // for validity, it might be surprising to do that here. - if cid.promoted.is_none() { - let mut ref_tracking = RefTracking::new(mplace); - let mut inner = false; - while let Some((mplace, path)) = ref_tracking.todo.pop() { - let mode = match tcx.static_mutability(cid.instance.def_id()) { - Some(_) => CtfeValidationMode::Regular, // a `static` - None => CtfeValidationMode::Const { inner }, - }; - ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; - inner = true; - } + let mut ref_tracking = RefTracking::new(mplace); + let mut inner = false; + while let Some((mplace, path)) = ref_tracking.todo.pop() { + let mode = match tcx.static_mutability(cid.instance.def_id()) { + Some(_) if cid.promoted.is_some() => { + // Promoteds in statics are allowed to point to statics. + CtfeValidationMode::Const { inner, allow_static_ptrs: true } + } + Some(_) => CtfeValidationMode::Regular, // a `static` + None => CtfeValidationMode::Const { inner, allow_static_ptrs: false }, + }; + ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; + inner = true; } }; if let Err(error) = validation { diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index c72089ec55..72912dd76f 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -1,65 +1,27 @@ use rustc_middle::mir; -use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; +use std::fmt; use rustc_ast::Mutability; use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; use rustc_session::Limit; use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{Align, Size}; use crate::interpret::{ - self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, - InterpResult, Memory, OpTy, PlaceTy, Pointer, Scalar, + self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory, + OpTy, PlaceTy, Pointer, Scalar, }; use super::error::*; impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { - /// Evaluate a const function where all arguments (if any) are zero-sized types. - /// The evaluation is memoized thanks to the query system. - /// - /// Returns `true` if the call has been evaluated. - fn try_eval_const_fn_call( - &mut self, - instance: ty::Instance<'tcx>, - ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, - args: &[OpTy<'tcx>], - ) -> InterpResult<'tcx, bool> { - trace!("try_eval_const_fn_call: {:?}", instance); - // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot - // perform this optimization on items tagged with it. - if instance.def.requires_caller_location(self.tcx()) { - return Ok(false); - } - // For the moment we only do this for functions which take no arguments - // (or all arguments are ZSTs) so that we don't memoize too much. - if args.iter().any(|a| !a.layout.is_zst()) { - return Ok(false); - } - - let dest = match ret { - Some((dest, _)) => dest, - // Don't memoize diverging function calls. - None => return Ok(false), - }; - - let gid = GlobalId { instance, promoted: None }; - - let place = self.eval_to_allocation(gid)?; - - self.copy_op(place.into(), dest)?; - - self.return_to_block(ret.map(|r| r.1))?; - trace!("{:?}", self.dump_place(*dest)); - Ok(true) - } - /// "Intercept" a function call to a panic-related function /// because we have something special to do for it. /// If this returns successfully (`Ok`), the function should just be evaluated normally. @@ -169,6 +131,28 @@ impl interpret::AllocMap for FxHashMap { crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum MemoryKind { + Heap, +} + +impl fmt::Display for MemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MemoryKind::Heap => write!(f, "heap allocation"), + } + } +} + +impl interpret::MayLeak for MemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + match self { + MemoryKind::Heap => false, + } + } +} + impl interpret::MayLeak for ! { #[inline(always)] fn may_leak(self) -> bool { @@ -212,13 +196,15 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = MemoryKind; + type MemoryExtra = MemoryExtra; fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, _unwind: Option, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { debug!("find_mir_or_eval_fn: {:?}", instance); @@ -228,13 +214,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const // at all. - if ecx.tcx.is_const_fn_raw(def.did) { - // If this function is a `const fn` then under certain circumstances we - // can evaluate call via the query system, thus memoizing all future calls. - if ecx.try_eval_const_fn_call(instance, ret, args)? { - return Ok(None); - } - } else { + if !ecx.tcx.is_const_fn_raw(def.did) { // Some functions we support even if they are non-const -- but avoid testing // that for const fn! ecx.hook_panic_fn(instance, args)?; @@ -295,6 +275,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, }; ecx.write_scalar(Scalar::from_bool(cmp), dest)?; } + sym::const_allocate => { + let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?; + let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?; + + let align = match Align::from_bytes(align) { + Ok(a) => a, + Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), + }; + + let ptr = ecx.memory.allocate( + Size::from_bytes(size as u64), + align, + interpret::MemoryKind::Machine(MemoryKind::Heap), + ); + ecx.write_scalar(Scalar::Ptr(ptr), dest)?; + } _ => { return Err(ConstEvalErrKind::NeedsRfc(format!( "calling intrinsic `{}`", @@ -333,6 +329,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::AssertFailure(err).into()) } + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + Err(ConstEvalErrKind::Abort(msg).into()) + } + fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> { Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into()) } diff --git a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs index d1d507e54e..d16366fded 100644 --- a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs +++ b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs @@ -152,7 +152,7 @@ pub(crate) fn on_all_drop_children_bits<'tcx, F>( let ty = place.ty(body, tcx).ty; debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); - let erased_ty = tcx.erase_regions(&ty); + let erased_ty = tcx.erase_regions(ty); if erased_ty.needs_drop(tcx, ctxt.param_env) { each_child(child); } else { diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs index a2b0713cd7..85aaff5ab7 100644 --- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs @@ -11,7 +11,7 @@ use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis}; /// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use /// this analysis without also looking at the results of [`MaybeBorrowedLocals`]. /// -/// [`MaybeBorrowedLocals`]: ../struct.MaybeBorrowedLocals.html +/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals /// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis pub struct MaybeLiveLocals; diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 0f86a181a5..3d955576f0 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -4,7 +4,7 @@ use std::mem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::{self as hir, def::DefKind, def_id::DefId, definitions::DefPathData}; +use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_middle::ich::StableHashingContext; @@ -505,7 +505,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, value: T, ) -> T { - frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, &value) + frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) } /// The `substs` are assumed to already be in our interpreter "universe" (param_env). @@ -700,21 +700,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let mut locals = IndexVec::from_elem(dummy, &body.local_decls); // Now mark those locals as dead that we do not want to initialize - match self.tcx.def_kind(instance.def_id()) { - // statics and constants don't have `Storage*` statements, no need to look for them - // - // FIXME: The above is likely untrue. See - // . Is it - // okay to ignore `StorageDead`/`StorageLive` annotations during CTFE? - DefKind::Static | DefKind::Const | DefKind::AssocConst => {} - _ => { - // Mark locals that use `Storage*` annotations as dead on function entry. - let always_live = AlwaysLiveLocals::new(self.body()); - for local in locals.indices() { - if !always_live.contains(local) { - locals[local].value = LocalValue::Dead; - } - } + // Mark locals that use `Storage*` annotations as dead on function entry. + let always_live = AlwaysLiveLocals::new(self.body()); + for local in locals.indices() { + if !always_live.contains(local) { + locals[local].value = LocalValue::Dead; } } // done @@ -850,36 +840,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - /// Mark a storage as live, killing the previous content and returning it. - /// Remember to deallocate that! - pub fn storage_live( - &mut self, - local: mir::Local, - ) -> InterpResult<'tcx, LocalValue> { + /// Mark a storage as live, killing the previous content. + pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> { assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); trace!("{:?} is now live", local); let local_val = LocalValue::Uninitialized; - // StorageLive *always* kills the value that's currently stored. - // However, we do not error if the variable already is live; - // see . - Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val)) + // StorageLive expects the local to be dead, and marks it live. + let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); + if !matches!(old, LocalValue::Dead) { + throw_ub_format!("StorageLive on a local that was already live"); + } + Ok(()) } - /// Returns the old value of the local. - /// Remember to deallocate that! - pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue { + pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> { assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); trace!("{:?} is now dead", local); - mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead) + // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR) + let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); + self.deallocate_local(old)?; + Ok(()) } - pub(super) fn deallocate_local( - &mut self, - local: LocalValue, - ) -> InterpResult<'tcx> { - // FIXME: should we tell the user that there was a local which was never written to? + fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { // All locals have a backing allocation, even if the allocation is empty // due to the local having ZST type. diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 413be42733..01d58c47e3 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -25,19 +25,20 @@ use rustc_target::abi::Size; use rustc_ast::Mutability; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, Scalar, ValueVisitor}; +use crate::const_eval; -pub trait CompileTimeMachine<'mir, 'tcx> = Machine< +pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< 'mir, 'tcx, - MemoryKind = !, + MemoryKind = T, PointerTag = (), ExtraFnVal = !, FrameExtra = (), AllocExtra = (), - MemoryMap = FxHashMap, Allocation)>, + MemoryMap = FxHashMap, Allocation)>, >; -struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { +struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { /// The ectx from which we intern. ecx: &'rt mut InterpCx<'mir, 'tcx, M>, /// Previously encountered safe references. @@ -74,7 +75,7 @@ struct IsStaticOrFn; /// `immutable` things might become mutable if `ty` is not frozen. /// `ty` can be `None` if there is no potential interior mutability /// to account for (e.g. for vtables). -fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( +fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( ecx: &'rt mut InterpCx<'mir, 'tcx, M>, leftover_allocations: &'rt mut FxHashSet, alloc_id: AllocId, @@ -104,7 +105,10 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( // This match is just a canary for future changes to `MemoryKind`, which most likely need // changes in this function. match kind { - MemoryKind::Stack | MemoryKind::Vtable | MemoryKind::CallerLocation => {} + MemoryKind::Stack + | MemoryKind::Machine(const_eval::MemoryKind::Heap) + | MemoryKind::Vtable + | MemoryKind::CallerLocation => {} } // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that @@ -138,7 +142,9 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( None } -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> { +impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + InternVisitor<'rt, 'mir, 'tcx, M> +{ fn intern_shallow( &mut self, alloc_id: AllocId, @@ -149,8 +155,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir } } -impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for InternVisitor<'rt, 'mir, 'tcx, M> +impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M> { type V = MPlaceTy<'tcx>; @@ -287,7 +293,7 @@ pub enum InternKind { /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures /// are hard errors. #[tracing::instrument(skip(ecx))] -pub fn intern_const_alloc_recursive>( +pub fn intern_const_alloc_recursive>( ecx: &mut InterpCx<'mir, 'tcx, M>, intern_kind: InternKind, ret: MPlaceTy<'tcx>, @@ -418,7 +424,9 @@ where Ok(()) } -impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> + InterpCx<'mir, 'tcx, M> +{ /// A helper function that allocates memory for the layout given and gives you access to mutate /// it. Once your own mutation code is done, the backing `Allocation` is removed from the /// current `Memory` and returned. diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index d3b6d70633..474e1f8e57 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -61,12 +61,11 @@ crate fn eval_nullary_intrinsic<'tcx>( ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } } sym::needs_drop => ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)), - sym::size_of | sym::min_align_of | sym::pref_align_of => { + sym::min_align_of | sym::pref_align_of => { let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; let n = match name { sym::pref_align_of => layout.align.pref.bytes(), sym::min_align_of => layout.align.abi.bytes(), - sym::size_of => layout.size.bytes(), _ => bug!(), }; ConstValue::from_machine_usize(n, &tcx) @@ -75,13 +74,35 @@ crate fn eval_nullary_intrinsic<'tcx>( ensure_monomorphic_enough(tcx, tp_ty)?; ConstValue::from_u64(tcx.type_id_hash(tp_ty)) } - sym::variant_count => { - if let ty::Adt(ref adt, _) = tp_ty.kind() { - ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx) - } else { - ConstValue::from_machine_usize(0u64, &tcx) - } - } + sym::variant_count => match tp_ty.kind() { + ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx), + ty::Projection(_) + | ty::Opaque(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) + | ty::Infer(_) => throw_inval!(TooGeneric), + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx), + }, other => bug!("`{}` is not a zero arg intrinsic", other), }) } @@ -103,8 +124,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (dest, ret) = match ret { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), - sym::unreachable => throw_ub!(Unreachable), - sym::abort => M::abort(self)?, + sym::abort => M::abort(self, "the program aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), }, @@ -138,13 +158,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::min_align_of | sym::pref_align_of | sym::needs_drop - | sym::size_of | sym::type_id | sym::type_name | sym::variant_count => { let gid = GlobalId { instance, promoted: None }; let ty = match intrinsic_name { - sym::min_align_of | sym::pref_align_of | sym::size_of | sym::variant_count => { + sym::min_align_of | sym::pref_align_of | sym::variant_count => { self.tcx.types.usize } sym::needs_drop => self.tcx.types.bool, @@ -190,28 +209,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let out_val = numeric_intrinsic(intrinsic_name, bits, kind)?; self.write_scalar(out_val, dest)?; } - sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow => { + sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { let lhs = self.read_immediate(args[0])?; let rhs = self.read_immediate(args[1])?; - let (bin_op, ignore_overflow) = match intrinsic_name { - sym::wrapping_add => (BinOp::Add, true), - sym::wrapping_sub => (BinOp::Sub, true), - sym::wrapping_mul => (BinOp::Mul, true), - sym::add_with_overflow => (BinOp::Add, false), - sym::sub_with_overflow => (BinOp::Sub, false), - sym::mul_with_overflow => (BinOp::Mul, false), + let bin_op = match intrinsic_name { + sym::add_with_overflow => BinOp::Add, + sym::sub_with_overflow => BinOp::Sub, + sym::mul_with_overflow => BinOp::Mul, _ => bug!("Already checked for int ops"), }; - if ignore_overflow { - self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?; - } else { - self.binop_with_overflow(bin_op, lhs, rhs, dest)?; - } + self.binop_with_overflow(bin_op, lhs, rhs, dest)?; } sym::saturating_add | sym::saturating_sub => { let l = self.read_immediate(args[0])?; @@ -385,6 +392,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(args[0], dest)?; } + sym::assert_inhabited => { + let ty = instance.substs.type_at(0); + let layout = self.layout_of(ty)?; + + if layout.abi.is_uninhabited() { + // The run-time intrinsic panics just to get a good backtrace; here we abort + // since there is no problem showing a backtrace even for aborts. + M::abort( + self, + format!( + "aborted execution: attempted to instantiate uninhabited type `{}`", + ty + ), + )?; + } + } sym::simd_insert => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); let elem = args[2]; diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 554ada1ab2..e1ec4cc5e9 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -74,7 +74,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { let mut first = true; for p in predicates { diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 66dbacb2f9..f50cc6c16e 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -9,6 +9,7 @@ use std::hash::Hash; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefId; +use rustc_target::abi::Size; use super::{ AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, @@ -176,7 +177,7 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to evaluate `Abort` MIR terminator. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { throw_unsup_format!("aborting execution is not supported") } @@ -299,6 +300,15 @@ pub trait Machine<'mir, 'tcx>: Sized { Ok(()) } + /// Called after initializing static memory using the interpreter. + fn after_static_mem_initialized( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer, + _size: Size, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Executes a retagging operation #[inline] fn retag( @@ -366,9 +376,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type PointerTag = (); type ExtraFnVal = !; - type MemoryKind = !; - type MemoryMap = rustc_data_structures::fx::FxHashMap, Allocation)>; - const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory + type MemoryMap = + rustc_data_structures::fx::FxHashMap, Allocation)>; + const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory type AllocExtra = (); type FrameExtra = (); @@ -407,7 +417,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _memory_extra: &Self::MemoryExtra, _id: AllocId, alloc: Cow<'b, Allocation>, - _kind: Option>, + _kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { // We do not use a tag so we can just cheaply forward the allocation (alloc, ()) diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs index 156da84f29..95738db1f5 100644 --- a/compiler/rustc_mir/src/interpret/step.rs +++ b/compiler/rustc_mir/src/interpret/step.rs @@ -95,14 +95,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Mark locals as alive StorageLive(local) => { - let old_val = self.storage_live(*local)?; - self.deallocate_local(old_val)?; + self.storage_live(*local)?; } // Mark locals as dead StorageDead(local) => { - let old_val = self.storage_dead(*local); - self.deallocate_local(old_val)?; + self.storage_dead(*local)?; } // No dynamic semantics attached to `FakeRead`; MIR diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index bb11c2a23b..a2931325a2 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Abort => { - M::abort(self)?; + M::abort(self, "the program aborted execution".to_owned())?; } // When we encounter Resume, we've finished unwinding diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 77f4593fa1..09ce6bc0fb 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -21,7 +21,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, Pointer> { trace!("get_vtable(trait_ref={:?})", poly_trait_ref); - let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref)); + let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); // All vtables must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, ty)?; @@ -37,7 +37,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let methods = if let Some(poly_trait_ref) = poly_trait_ref { let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); - let trait_ref = self.tcx.erase_regions(&trait_ref); + let trait_ref = self.tcx.erase_regions(trait_ref); self.tcx.vtable_methods(trait_ref) } else { @@ -56,11 +56,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // If you touch this code, be sure to also make the corresponding changes to // `get_vtable` in `rust_codegen_llvm/meth.rs`. // ///////////////////////////////////////////////////////////////////////////////////////// - let vtable = self.memory.allocate( - ptr_size * u64::try_from(methods.len()).unwrap().checked_add(3).unwrap(), - ptr_align, - MemoryKind::Vtable, - ); + let vtable_size = ptr_size * u64::try_from(methods.len()).unwrap().checked_add(3).unwrap(); + let vtable = self.memory.allocate(vtable_size, ptr_align, MemoryKind::Vtable); let drop = Instance::resolve_drop_in_place(tcx, ty); let drop = self.memory.create_fn_alloc(FnVal::Instance(drop)); @@ -93,6 +90,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + M::after_static_mem_initialized(self, vtable, vtable_size)?; + self.memory.mark_immutable(vtable.alloc_id)?; assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none()); @@ -143,7 +142,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?; trace!("Found drop fn: {:?}", drop_instance); let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx); - let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig); + let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig); // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let args = fn_sig.inputs(); if args.len() != 1 { diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index fce5553c99..c2165db278 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -13,29 +13,32 @@ where return Ok(()); } + struct FoundParam; struct UsedParamsNeedSubstVisitor<'tcx> { tcx: TyCtxt<'tcx>, - }; + } impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + type BreakTy = FoundParam; + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if !c.needs_subst() { return ControlFlow::CONTINUE; } match c.val { - ty::ConstKind::Param(..) => ControlFlow::BREAK, + ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), _ => c.super_visit_with(self), } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.needs_subst() { return ControlFlow::CONTINUE; } match *ty.kind() { - ty::Param(_) => ControlFlow::BREAK, + ty::Param(_) => ControlFlow::Break(FoundParam), ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { @@ -74,7 +77,7 @@ where } let mut vis = UsedParamsNeedSubstVisitor { tcx }; - if ty.visit_with(&mut vis).is_break() { + if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { throw_inval!(TooGeneric); } else { Ok(()) diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 2d235d65c4..57aec0953b 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -117,11 +117,12 @@ pub enum PathElem { pub enum CtfeValidationMode { /// Regular validation, nothing special happening. Regular, - /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed - /// to the top-level const allocation). - /// Being an inner allocation makes a difference because the top-level allocation of a `const` - /// is copied for each use, but the inner allocations are implicitly shared. - Const { inner: bool }, + /// Validation of a `const`. + /// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const + /// allocation). Being an inner allocation makes a difference because the top-level allocation + /// of a `const` is copied for each use, but the inner allocations are implicitly shared. + /// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics). + Const { inner: bool, allow_static_ptrs: bool }, } /// State for tracking recursive validation of references @@ -437,7 +438,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { + if matches!( + self.ctfe_mode, + Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) + ) { // See const_eval::machine::MemoryExtra::can_access_statics for why // this check is so important. // This check is reachable when the const just referenced the static, @@ -742,9 +746,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Sanity check: `builtin_deref` does not know any pointers that are not primitive. assert!(op.layout.ty.builtin_deref(true).is_none()); - // Special check preventing `UnsafeCell` in constants + // Special check preventing `UnsafeCell` in the inner part of constants if let Some(def) = op.layout.ty.ty_adt_def() { - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true })) + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 2ed115b129..e6d822086f 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -28,6 +28,7 @@ Rust MIR: a lowered representation of Rust. #![feature(or_patterns)] #![feature(once_cell)] #![feature(control_flow_enum)] +#![feature(str_split_once)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 938181abff..6370ead97e 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -546,7 +546,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - &value, + value, ) } } @@ -993,7 +993,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { match item.kind { hir::ItemKind::ExternCrate(..) | hir::ItemKind::Use(..) - | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::TyAlias(..) | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) @@ -1066,6 +1066,8 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { self.push_if_root(def_id); } } + + fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {} } impl RootCollector<'_, 'v> { @@ -1118,7 +1120,7 @@ impl RootCollector<'_, 'v> { // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = self.tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); let start_instance = Instance::resolve( self.tcx, diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index 037b80e4bf..d5a845dd76 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -304,7 +304,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( let impl_self_ty = tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - &tcx.type_of(impl_def_id), + tcx.type_of(impl_def_id), ); if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { return Some(def_id); diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index c2ebc954a2..0ce1c5a048 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -250,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -283,7 +283,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -318,7 +318,9 @@ struct HasUsedGenericParams<'a> { } impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; @@ -336,7 +338,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { return ControlFlow::CONTINUE; diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs index b2fa4b11f3..aa5835686a 100644 --- a/compiler/rustc_mir/src/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -135,7 +135,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) // Check if this is a generator, if so, return the drop glue for it if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) { let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); - return body.subst(tcx, substs); + return body.clone().subst(tcx, substs); } let substs = if let Some(ty) = ty { @@ -144,7 +144,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) InternalSubsts::identity_for_item(tcx, def_id) }; let sig = tcx.fn_sig(def_id).subst(tcx, substs); - let sig = tcx.erase_late_bound_regions(&sig); + let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); let source_info = SourceInfo::outermost(span); @@ -308,10 +308,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - match self_ty.kind() { _ if is_copy => builder.copy_shim(), - ty::Array(ty, len) => { - let len = len.eval_usize(tcx, param_env); - builder.array_shim(dest, src, ty, len) - } + ty::Array(ty, len) => builder.array_shim(dest, src, ty, len), ty::Closure(_, substs) => { builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys()) } @@ -338,7 +335,7 @@ impl CloneShimBuilder<'tcx> { // or access fields of a Place of type TySelf. let substs = tcx.mk_substs_trait(self_ty, &[]); let sig = tcx.fn_sig(def_id).subst(tcx, substs); - let sig = tcx.erase_late_bound_regions(&sig); + let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); CloneShimBuilder { @@ -485,7 +482,13 @@ impl CloneShimBuilder<'tcx> { } } - fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) { + fn array_shim( + &mut self, + dest: Place<'tcx>, + src: Place<'tcx>, + ty: Ty<'tcx>, + len: &'tcx ty::Const<'tcx>, + ) { let tcx = self.tcx; let span = self.span; @@ -503,7 +506,11 @@ impl CloneShimBuilder<'tcx> { ))), self.make_statement(StatementKind::Assign(box ( end, - Rvalue::Use(Operand::Constant(self.make_usize(len))), + Rvalue::Use(Operand::Constant(box Constant { + span: self.span, + user_ty: None, + literal: len, + })), ))), ]; self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false); @@ -656,7 +663,7 @@ fn build_call_shim<'tcx>( // to substitute into the signature of the shim. It is not necessary for users of this // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { - let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); + let sig = tcx.erase_late_bound_regions(ty.fn_sig(tcx)); let untuple_args = sig.inputs(); @@ -671,7 +678,7 @@ fn build_call_shim<'tcx>( let def_id = instance.def_id(); let sig = tcx.fn_sig(def_id); - let mut sig = tcx.erase_late_bound_regions(&sig); + let mut sig = tcx.erase_late_bound_regions(sig); assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); if let Some(sig_substs) = sig_substs { diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index a845704327..e2d50ba034 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -66,12 +66,14 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { location: Location, decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>, ) { - // Don't lint on borrowing/assigning to a dereference - // e.g: + // Don't lint on borrowing/assigning when a dereference is involved. + // If we 'leave' the temporary via a dereference, we must + // be modifying something else // // `unsafe { *FOO = 0; *BAR.field = 1; }` // `unsafe { &mut *FOO }` - if !matches!(place.projection.last(), Some(PlaceElem::Deref)) { + // `unsafe { (*ARRAY)[0] = val; } + if !place.projection.iter().any(|p| matches!(p, PlaceElem::Deref)) { let source_info = self.body.source_info(location); let lint_root = self.body.source_scopes[source_info.scope] .local_data diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index bd51136b8d..d2e65abfbc 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -4,7 +4,6 @@ use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir; -use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -104,7 +103,7 @@ impl NonConstOp for FnCallUnstable { if ccx.is_const_stable_const_fn() { err.help("Const-stable functions can only call other const-stable functions"); - } else if nightly_options::is_nightly_build() { + } else if ccx.tcx.sess.is_nightly_build() { if let Some(feature) = feature { err.help(&format!( "add `#![feature({})]` to the crate attributes to enable", diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs index b3d9beb374..c66d3ed76d 100644 --- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -2,6 +2,7 @@ //! //! See the `Qualif` trait for more info. +use rustc_errors::ErrorReported; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; @@ -9,11 +10,16 @@ use rustc_trait_selection::traits; use super::ConstCx; -pub fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> ConstQualifs { +pub fn in_any_value_of_ty( + cx: &ConstCx<'_, 'tcx>, + ty: Ty<'tcx>, + error_occured: Option, +) -> ConstQualifs { ConstQualifs { has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), custom_eq: CustomEq::in_any_value_of_ty(cx, ty), + error_occured, } } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 4139b54499..90688ebbd0 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -1,9 +1,10 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. -use rustc_errors::{struct_span_err, Applicability, Diagnostic}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, HirId, LangItem}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; @@ -11,9 +12,10 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut, }; +use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; -use rustc_trait_selection::traits::{self, TraitEngine}; +use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine}; use std::mem; use std::ops::Deref; @@ -123,7 +125,11 @@ impl Qualifs<'mir, 'tcx> { has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location) } - fn in_return_place(&mut self, ccx: &'mir ConstCx<'mir, 'tcx>) -> ConstQualifs { + fn in_return_place( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + error_occured: Option, + ) -> ConstQualifs { // Find the `Return` terminator if one exists. // // If no `Return` terminator exists, this MIR is divergent. Just return the conservative @@ -139,7 +145,7 @@ impl Qualifs<'mir, 'tcx> { .map(|(bb, _)| bb); let return_block = match return_block { - None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty()), + None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured), Some(bb) => bb, }; @@ -170,6 +176,7 @@ impl Qualifs<'mir, 'tcx> { needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), custom_eq, + error_occured, } } } @@ -181,7 +188,7 @@ pub struct Validator<'mir, 'tcx> { /// The span of the current statement. span: Span, - error_emitted: bool, + error_emitted: Option, secondary_errors: Vec, } @@ -199,7 +206,7 @@ impl Validator<'mir, 'tcx> { span: ccx.body.span, ccx, qualifs: Default::default(), - error_emitted: false, + error_emitted: None, secondary_errors: Vec::new(), } } @@ -266,7 +273,7 @@ impl Validator<'mir, 'tcx> { // If we got through const-checking without emitting any "primary" errors, emit any // "secondary" errors if they occurred. let secondary_errors = mem::take(&mut self.secondary_errors); - if !self.error_emitted { + if self.error_emitted.is_none() { for error in secondary_errors { self.tcx.sess.diagnostic().emit_diagnostic(&error); } @@ -276,7 +283,7 @@ impl Validator<'mir, 'tcx> { } pub fn qualifs_in_return_place(&mut self) -> ConstQualifs { - self.qualifs.in_return_place(self.ccx) + self.qualifs.in_return_place(self.ccx, self.error_emitted) } /// Emits an error if an expression cannot be evaluated in the current context. @@ -318,7 +325,7 @@ impl Validator<'mir, 'tcx> { match op.importance() { ops::DiagnosticImportance::Primary => { - self.error_emitted = true; + self.error_emitted = Some(ErrorReported); err.emit(); } @@ -715,17 +722,16 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { trace!("visit_statement: statement={:?} location={:?}", statement, location); - match statement.kind { - StatementKind::Assign(..) | StatementKind::SetDiscriminant { .. } => { - self.super_statement(statement, location); - } + self.super_statement(statement, location); + match statement.kind { StatementKind::LlvmInlineAsm { .. } => { - self.super_statement(statement, location); self.check_op(ops::InlineAsm); } - StatementKind::FakeRead(..) + StatementKind::Assign(..) + | StatementKind::SetDiscriminant { .. } + | StatementKind::FakeRead(..) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Retag { .. } @@ -760,9 +766,39 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; - // Resolve a trait method call to its concrete implementation, which may be in a - // `const` trait impl. - if self.tcx.features().const_trait_impl { + // Attempting to call a trait method? + if let Some(trait_id) = tcx.trait_of_item(callee) { + if !self.tcx.features().const_trait_impl { + self.check_op(ops::FnCallNonConst(callee)); + return; + } + + let trait_ref = TraitRef::from_method(tcx, trait_id, substs); + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + Binder::bind(TraitPredicate { + trait_ref: TraitRef::from_method(tcx, trait_id, substs), + }), + ); + + let implsrc = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + selcx.select(&obligation).unwrap() + }); + + // If the method is provided via a where-clause that does not use the `?const` + // opt-out, the call is allowed. + if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc { + debug!( + "const_trait_impl: provided {:?} via where-clause in {:?}", + trait_ref, param_env + ); + return; + } + + // Resolve a trait method call to its concrete implementation, which may be in a + // `const` trait impl. let instance = Instance::resolve(tcx, param_env, callee, substs); debug!("Resolving ({:?}) -> {:?}", callee, instance); if let Ok(Some(func)) = instance { diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index acec3e8f82..e64955c498 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -181,6 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use()); } + // Check for borrows to packed fields. + // `is_disaligned` already traverses the place to consider all projections after the last + // `Deref`, so this only needs to be called once at the top level. if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { self.require_unsafe( @@ -190,87 +193,105 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } - for (i, elem) in place.projection.iter().enumerate() { - let proj_base = &place.projection[..i]; - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + // Some checks below need the extra metainfo of the local declaration. + let decl = &self.body.local_decls[place.local]; + + // Check the base local: it might be an unsafe-to-access static. We only check derefs of the + // temporary holding the static pointer to avoid duplicate errors + // . + if decl.internal && place.projection.first() == Some(&ProjectionElem::Deref) { + // If the projection root is an artifical local that we introduced when + // desugaring `static`, give a more specific error message + // (avoid the general "raw pointer" clause below, that would only be confusing). + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + if self.tcx.is_mutable_static(def_id) { self.require_unsafe( - UnsafetyViolationKind::BorrowPacked, - UnsafetyViolationDetails::BorrowOfPackedField, + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfMutableStatic, ); + return; + } else if self.tcx.is_foreign_item(def_id) { + self.require_unsafe( + UnsafetyViolationKind::General, + UnsafetyViolationDetails::UseOfExternStatic, + ); + return; } } - let source_info = self.source_info; - if let [] = proj_base { - let decl = &self.body.local_decls[place.local]; - if decl.internal { - // If the projection root is an artifical local that we introduced when - // desugaring `static`, give a more specific error message - // (avoid the general "raw pointer" clause below, that would only be confusing). - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { - if self.tcx.is_mutable_static(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfMutableStatic, - ); - return; - } else if self.tcx.is_foreign_item(def_id) { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::UseOfExternStatic, - ); - return; - } - } else { - // Internal locals are used in the `move_val_init` desugaring. - // We want to check unsafety against the source info of the - // desugaring, rather than the source info of the RHS. - self.source_info = self.body.local_decls[place.local].source_info; - } + } + + // Check for raw pointer `Deref`. + for (base, proj) in place.iter_projections() { + if proj == ProjectionElem::Deref { + let source_info = self.source_info; // Backup source_info so we can restore it later. + if base.projection.is_empty() && decl.internal { + // Internal locals are used in the `move_val_init` desugaring. + // We want to check unsafety against the source info of the + // desugaring, rather than the source info of the RHS. + self.source_info = self.body.local_decls[place.local].source_info; + } + let base_ty = base.ty(self.body, self.tcx).ty; + if base_ty.is_unsafe_ptr() { + self.require_unsafe( + UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationDetails::DerefOfRawPointer, + ) } + self.source_info = source_info; // Restore backed-up source_info. } - let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - match base_ty.kind() { - ty::RawPtr(..) => self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::DerefOfRawPointer, - ), - ty::Adt(adt, _) => { - if adt.is_union() { - if context == PlaceContext::MutatingUse(MutatingUseContext::Store) - || context == PlaceContext::MutatingUse(MutatingUseContext::Drop) - || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) - { - let elem_ty = match elem { - ProjectionElem::Field(_, ty) => ty, - _ => span_bug!( - self.source_info.span, - "non-field projection {:?} from union?", - place - ), - }; - if !elem_ty.is_copy_modulo_regions( - self.tcx.at(self.source_info.span), - self.param_env, - ) { - self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::AssignToNonCopyUnionField, - ) - } else { - // write to non-move union, safe - } - } else { - self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, - UnsafetyViolationDetails::AccessToUnionField, - ) - } + } + + // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes + // whether we *read* the union field or potentially *write* to it (if this place is being assigned to). + let mut saw_deref = false; + for (base, proj) in place.iter_projections().rev() { + if proj == ProjectionElem::Deref { + saw_deref = true; + continue; + } + + let base_ty = base.ty(self.body, self.tcx).ty; + if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) { + // If we did not hit a `Deref` yet and the overall place use is an assignment, the + // rules are different. + let assign_to_field = !saw_deref + && matches!( + context, + PlaceContext::MutatingUse( + MutatingUseContext::Store + | MutatingUseContext::Drop + | MutatingUseContext::AsmOutput + ) + ); + // If this is just an assignment, determine if the assigned type needs dropping. + if assign_to_field { + // We have to check the actual type of the assignment, as that determines if the + // old value is being dropped. + let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; + // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. + let manually_drop = assigned_ty + .ty_adt_def() + .map_or(false, |adt_def| adt_def.is_manually_drop()); + let nodrop = manually_drop + || assigned_ty.is_copy_modulo_regions( + self.tcx.at(self.source_info.span), + self.param_env, + ); + if !nodrop { + self.require_unsafe( + UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationDetails::AssignToDroppingUnionField, + ); + } else { + // write to non-drop union field, safe } + } else { + self.require_unsafe( + UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationDetails::AccessToUnionField, + ) } - _ => {} } - self.source_info = source_info; } } } diff --git a/compiler/rustc_mir/src/transform/const_debuginfo.rs b/compiler/rustc_mir/src/transform/const_debuginfo.rs new file mode 100644 index 0000000000..3cdaf4c7dc --- /dev/null +++ b/compiler/rustc_mir/src/transform/const_debuginfo.rs @@ -0,0 +1,102 @@ +//! Finds locals which are assigned once to a const and unused except for debuginfo and converts +//! their debuginfo to use the const directly, allowing the local to be removed. + +use rustc_middle::{ + mir::{ + visit::{PlaceContext, Visitor}, + Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, + }, + ty::TyCtxt, +}; + +use crate::transform::MirPass; +use rustc_index::{bit_set::BitSet, vec::IndexVec}; + +pub struct ConstDebugInfo; + +impl<'tcx> MirPass<'tcx> for ConstDebugInfo { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + + trace!("running ConstDebugInfo on {:?}", body.source); + + for (local, constant) in find_optimization_oportunities(body) { + for debuginfo in &mut body.var_debug_info { + if let VarDebugInfoContents::Place(p) = debuginfo.value { + if p.local == local && p.projection.is_empty() { + trace!( + "changing debug info for {:?} from place {:?} to constant {:?}", + debuginfo.name, + p, + constant + ); + debuginfo.value = VarDebugInfoContents::Const(constant); + } + } + } + } + } +} + +struct LocalUseVisitor { + local_mutating_uses: IndexVec, + local_assignment_locations: IndexVec>, +} + +fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { + let mut visitor = LocalUseVisitor { + local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), + local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), + }; + + visitor.visit_body(body); + + let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len()); + for debuginfo in &body.var_debug_info { + if let VarDebugInfoContents::Place(p) = debuginfo.value { + if let Some(l) = p.as_local() { + locals_to_debuginfo.insert(l); + } + } + } + + let mut eligable_locals = Vec::new(); + for (local, mutating_uses) in visitor.local_mutating_uses.drain_enumerated(..) { + if mutating_uses != 1 || !locals_to_debuginfo.contains(local) { + continue; + } + + if let Some(location) = visitor.local_assignment_locations[local] { + let bb = &body[location.block]; + + // The value is assigned as the result of a call, not a constant + if bb.statements.len() == location.statement_index { + continue; + } + + if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(box c)))) = + &bb.statements[location.statement_index].kind + { + if let Some(local) = p.as_local() { + eligable_locals.push((local, *c)); + } + } + } + } + + eligable_locals +} + +impl<'tcx> Visitor<'tcx> for LocalUseVisitor { + fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if context.is_mutating_use() { + self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1); + + if context.is_place_assignment() { + self.local_assignment_locations[*local] = Some(location); + } + } + } +} diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index aeb9920c0e..1d949e020e 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -180,6 +180,8 @@ impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = !; + type MemoryExtra = (); fn find_mir_or_eval_fn( @@ -800,7 +802,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - trace!("attepting to replace {:?} with {:?}", rval, value); + trace!("attempting to replace {:?} with {:?}", rval, value); if let Err(e) = self.ecx.const_validate_operand( value, vec![], @@ -890,6 +892,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return false; } + if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) { + return false; + } + match *op { interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => { s.is_bits() diff --git a/compiler/rustc_mir/src/transform/coverage/counters.rs b/compiler/rustc_mir/src/transform/coverage/counters.rs index d6c2f7f7aa..20f6a16e0f 100644 --- a/compiler/rustc_mir/src/transform/coverage/counters.rs +++ b/compiler/rustc_mir/src/transform/coverage/counters.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::coverage::*; /// Manages the counter and expression indexes/IDs to generate `CoverageKind` components for MIR /// `Coverage` statements. -pub(crate) struct CoverageCounters { +pub(super) struct CoverageCounters { function_source_hash: u64, next_counter_id: u32, num_expressions: u32, @@ -37,7 +37,7 @@ impl CoverageCounters { self.debug_counters.enable(); } - /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlocks` directly or + /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or /// indirectly associated with `CoverageSpans`, and returns additional `Expression`s /// representing intermediate values. pub fn make_bcb_counters( @@ -120,7 +120,6 @@ struct BcbCounters<'a> { basic_coverage_blocks: &'a mut CoverageGraph, } -// FIXME(richkadel): Add unit tests for `BcbCounters` functions/algorithms. impl<'a> BcbCounters<'a> { fn new( coverage_counters: &'a mut CoverageCounters, diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index ffa795134e..b66e37436a 100644 --- a/compiler/rustc_mir/src/transform/coverage/debug.rs +++ b/compiler/rustc_mir/src/transform/coverage/debug.rs @@ -95,18 +95,18 @@ //! //! Depending on the values and combinations, counters can be labeled by: //! -//! * `id` - counter or expression ID (ascending counter IDs, starting at 1, or descending -//! expression IDs, starting at `u32:MAX`) -//! * `block` - the `BasicCoverageBlock` label (for example, `bcb0`) or edge label (for -//! example `bcb0->bcb1`), for counters or expressions assigned to count a -//! `BasicCoverageBlock` or edge. Intermediate expressions (not directly associated with -//! a BCB or edge) will be labeled by their expression ID, unless `operation` is also -//! specified. -//! * `operation` - applied to expressions only, labels include the left-hand-side counter -//! or expression label (lhs operand), the operator (`+` or `-`), and the right-hand-side -//! counter or expression (rhs operand). Expression operand labels are generated -//! recursively, generating labels with nested operations, enclosed in parentheses -//! (for example: `bcb2 + (bcb0 - bcb1)`). +//! * `id` - counter or expression ID (ascending counter IDs, starting at 1, or descending +//! expression IDs, starting at `u32:MAX`) +//! * `block` - the `BasicCoverageBlock` label (for example, `bcb0`) or edge label (for +//! example `bcb0->bcb1`), for counters or expressions assigned to count a +//! `BasicCoverageBlock` or edge. Intermediate expressions (not directly associated with +//! a BCB or edge) will be labeled by their expression ID, unless `operation` is also +//! specified. +//! * `operation` - applied to expressions only, labels include the left-hand-side counter +//! or expression label (lhs operand), the operator (`+` or `-`), and the right-hand-side +//! counter or expression (rhs operand). Expression operand labels are generated +//! recursively, generating labels with nested operations, enclosed in parentheses +//! (for example: `bcb2 + (bcb0 - bcb1)`). use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use super::spans::CoverageSpan; @@ -127,7 +127,7 @@ pub const NESTED_INDENT: &str = " "; const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS"; -pub(crate) fn debug_options<'a>() -> &'a DebugOptions { +pub(super) fn debug_options<'a>() -> &'a DebugOptions { static DEBUG_OPTIONS: SyncOnceCell = SyncOnceCell::new(); &DEBUG_OPTIONS.get_or_init(|| DebugOptions::from_env()) @@ -136,7 +136,7 @@ pub(crate) fn debug_options<'a>() -> &'a DebugOptions { /// Parses and maintains coverage-specific debug options captured from the environment variable /// "RUSTC_COVERAGE_DEBUG_OPTIONS", if set. #[derive(Debug, Clone)] -pub(crate) struct DebugOptions { +pub(super) struct DebugOptions { pub allow_unused_expressions: bool, counter_format: ExpressionFormat, } @@ -148,40 +148,46 @@ impl DebugOptions { if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) { for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') { - let mut setting = setting_str.splitn(2, '='); - match setting.next() { - Some(option) if option == "allow_unused_expressions" => { - allow_unused_expressions = bool_option_val(option, setting.next()); + let (option, value) = match setting_str.split_once('=') { + None => (setting_str, None), + Some((k, v)) => (k, Some(v)), + }; + match option { + "allow_unused_expressions" => { + allow_unused_expressions = bool_option_val(option, value); debug!( "{} env option `allow_unused_expressions` is set to {}", RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions ); } - Some(option) if option == "counter_format" => { - if let Some(strval) = setting.next() { - counter_format = counter_format_option_val(strval); - debug!( - "{} env option `counter_format` is set to {:?}", - RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format - ); - } else { - bug!( - "`{}` option in environment variable {} requires one or more \ - plus-separated choices (a non-empty subset of \ - `id+block+operation`)", - option, - RUSTC_COVERAGE_DEBUG_OPTIONS - ); - } + "counter_format" => { + match value { + None => { + bug!( + "`{}` option in environment variable {} requires one or more \ + plus-separated choices (a non-empty subset of \ + `id+block+operation`)", + option, + RUSTC_COVERAGE_DEBUG_OPTIONS + ); + } + Some(val) => { + counter_format = counter_format_option_val(val); + debug!( + "{} env option `counter_format` is set to {:?}", + RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format + ); + } + }; } - Some("") => {} - Some(invalid) => bug!( - "Unsupported setting `{}` in environment variable {}", - invalid, - RUSTC_COVERAGE_DEBUG_OPTIONS - ), - None => {} - } + _ => { + bug!( + "Unsupported setting `{}` in environment variable {}", + option, + RUSTC_COVERAGE_DEBUG_OPTIONS + ) + } + }; } } @@ -250,7 +256,7 @@ impl Default for ExpressionFormat { /// /// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be /// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`. -pub(crate) struct DebugCounters { +pub(super) struct DebugCounters { some_counters: Option>, } @@ -279,7 +285,7 @@ impl DebugCounters { ), }; counters - .insert(id.into(), DebugCounter::new(counter_kind.clone(), some_block_label)) + .insert(id, DebugCounter::new(counter_kind.clone(), some_block_label)) .expect_none( "attempt to add the same counter_kind to DebugCounters more than once", ); @@ -334,7 +340,7 @@ impl DebugCounters { if self.some_counters.is_some() && (counter_format.block || !counter_format.id) { let counters = self.some_counters.as_ref().unwrap(); if let Some(DebugCounter { some_block_label: Some(block_label), .. }) = - counters.get(&id.into()) + counters.get(&id) { return if counter_format.id { format!("{}#{}", block_label, id.index()) @@ -386,7 +392,7 @@ impl DebugCounter { /// If enabled, this data structure captures additional debugging information used when generating /// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes. -pub(crate) struct GraphvizData { +pub(super) struct GraphvizData { some_bcb_to_coverage_spans_with_counters: Option>>, some_bcb_to_dependency_counters: Option>>, @@ -496,7 +502,7 @@ impl GraphvizData { /// directly or indirectly, to compute the coverage counts for all `CoverageSpan`s, and any that are /// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs /// and/or a `CoverageGraph` graphviz output). -pub(crate) struct UsedExpressions { +pub(super) struct UsedExpressions { some_used_expression_operands: Option>>, some_unused_expressions: @@ -626,7 +632,7 @@ impl UsedExpressions { } /// Generates the MIR pass `CoverageSpan`-specific spanview dump file. -pub(crate) fn dump_coverage_spanview( +pub(super) fn dump_coverage_spanview( tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>, basic_coverage_blocks: &CoverageGraph, @@ -666,7 +672,7 @@ fn span_viewables( } /// Generates the MIR pass coverage-specific graphviz dump file. -pub(crate) fn dump_coverage_graphviz( +pub(super) fn dump_coverage_graphviz( tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>, pass_name: &str, @@ -815,7 +821,7 @@ fn bcb_to_string_sections( /// Returns a simple string representation of a `TerminatorKind` variant, indenpendent of any /// values it might hold. -pub(crate) fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str { +pub(super) fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str { match kind { TerminatorKind::Goto { .. } => "Goto", TerminatorKind::SwitchInt { .. } => "SwitchInt", diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs index c2ed2cbb10..b1a1bb957e 100644 --- a/compiler/rustc_mir/src/transform/coverage/graph.rs +++ b/compiler/rustc_mir/src/transform/coverage/graph.rs @@ -17,7 +17,8 @@ const ID_SEPARATOR: &str = ","; /// `CoverageKind` counter (to be added by `CoverageCounters::make_bcb_counters`), and an optional /// set of additional counters--if needed--to count incoming edges, if there are more than one. /// (These "edge counters" are eventually converted into new MIR `BasicBlock`s.) -pub(crate) struct CoverageGraph { +#[derive(Debug)] +pub(super) struct CoverageGraph { bcbs: IndexVec, bb_to_bcb: IndexVec>, pub successors: IndexVec>, @@ -31,24 +32,28 @@ impl CoverageGraph { // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the - // each predecessor of a BCB leader_bb should be in a unique BCB, and each successor of a - // BCB last_bb should bin in its own unique BCB. Therefore, collecting the BCBs using - // `bb_to_bcb` should work without requiring a deduplication step. + // each predecessor of a BCB leader_bb should be in a unique BCB. It is possible for a + // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so + // de-duplication is required. This is done without reordering the successors. + let bcbs_len = bcbs.len(); + let mut seen = IndexVec::from_elem_n(false, bcbs_len); let successors = IndexVec::from_fn_n( |bcb| { + for b in seen.iter_mut() { + *b = false; + } let bcb_data = &bcbs[bcb]; - let bcb_successors = + let mut bcb_successors = Vec::new(); + for successor in bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind) .filter_map(|&successor_bb| bb_to_bcb[successor_bb]) - .collect::>(); - debug_assert!({ - let mut sorted = bcb_successors.clone(); - sorted.sort_unstable(); - let initial_len = sorted.len(); - sorted.dedup(); - sorted.len() == initial_len - }); + { + if !seen[successor] { + seen[successor] = true; + bcb_successors.push(successor); + } + } bcb_successors }, bcbs.len(), @@ -117,18 +122,8 @@ impl CoverageGraph { match term.kind { TerminatorKind::Return { .. } - // FIXME(richkadel): Add test(s) for `Abort` coverage. | TerminatorKind::Abort - // FIXME(richkadel): Add test(s) for `Assert` coverage. - // Should `Assert` be handled like `FalseUnwind` instead? Since we filter out unwind - // branches when creating the BCB CFG, aren't `Assert`s (without unwinds) just like - // `FalseUnwinds` (which are kind of like `Goto`s)? - | TerminatorKind::Assert { .. } - // FIXME(richkadel): Add test(s) for `Yield` coverage, and confirm coverage is - // sensible for code using the `yield` keyword. | TerminatorKind::Yield { .. } - // FIXME(richkadel): Also add coverage tests using async/await, and threading. - | TerminatorKind::SwitchInt { .. } => { // The `bb` has more than one _outgoing_ edge, or exits the function. Save the // current sequence of `basic_blocks` gathered to this point, as a new @@ -146,6 +141,16 @@ impl CoverageGraph { // `Terminator`s `successors()` list) checking the number of successors won't // work. } + + // The following `TerminatorKind`s are either not expected outside an unwind branch, + // or they should not (under normal circumstances) branch. Coverage graphs are + // simplified by assuring coverage results are accurate for program executions that + // don't panic. + // + // Programs that panic and unwind may record slightly inaccurate coverage results + // for a coverage region containing the `Terminator` that began the panic. This + // is as intended. (See Issue #78544 for a possible future option to support + // coverage in test programs that panic.) TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Unreachable @@ -153,6 +158,7 @@ impl CoverageGraph { | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Call { .. } | TerminatorKind::GeneratorDrop + | TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::InlineAsm { .. } => {} @@ -275,12 +281,15 @@ impl graph::WithPredecessors for CoverageGraph { rustc_index::newtype_index! { /// A node in the [control-flow graph][CFG] of CoverageGraph. - pub(crate) struct BasicCoverageBlock { + pub(super) struct BasicCoverageBlock { DEBUG_FORMAT = "bcb{}", + const START_BCB = 0, } } -/// A BasicCoverageBlockData (BCB) represents the maximal-length sequence of MIR BasicBlocks without +/// `BasicCoverageBlockData` holds the data indexed by a `BasicCoverageBlock`. +/// +/// A `BasicCoverageBlock` (BCB) represents the maximal-length sequence of MIR `BasicBlock`s without /// conditional branches, and form a new, simplified, coverage-specific Control Flow Graph, without /// altering the original MIR CFG. /// @@ -305,7 +314,7 @@ rustc_index::newtype_index! { /// queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch (control flow) /// significance. #[derive(Debug, Clone)] -pub(crate) struct BasicCoverageBlockData { +pub(super) struct BasicCoverageBlockData { pub basic_blocks: Vec, pub counter_kind: Option, edge_from_bcbs: Option>, @@ -431,7 +440,7 @@ impl BasicCoverageBlockData { /// the specific branching BCB, representing the edge between the two. The latter case /// distinguishes this incoming edge from other incoming edges to the same `target_bcb`. #[derive(Clone, Copy, PartialEq, Eq)] -pub(crate) struct BcbBranch { +pub(super) struct BcbBranch { pub edge_from_bcb: Option, pub target_bcb: BasicCoverageBlock, } @@ -498,9 +507,8 @@ fn bcb_filtered_successors<'a, 'tcx>( /// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the /// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that /// ensures a loop is completely traversed before processing Blocks after the end of the loop. -// FIXME(richkadel): Add unit tests for TraversalContext. #[derive(Debug)] -pub(crate) struct TraversalContext { +pub(super) struct TraversalContext { /// From one or more backedges returning to a loop header. pub loop_backedges: Option<(Vec, BasicCoverageBlock)>, @@ -510,7 +518,7 @@ pub(crate) struct TraversalContext { pub worklist: Vec, } -pub(crate) struct TraverseCoverageGraphWithLoops { +pub(super) struct TraverseCoverageGraphWithLoops { pub backedges: IndexVec>, pub context_stack: Vec, visited: BitSet, @@ -642,7 +650,7 @@ impl TraverseCoverageGraphWithLoops { } } -fn find_loop_backedges( +pub(super) fn find_loop_backedges( basic_coverage_blocks: &CoverageGraph, ) -> IndexVec> { let num_bcbs = basic_coverage_blocks.num_nodes(); diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index c55349239b..93133e9b7f 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -5,6 +5,9 @@ mod debug; mod graph; mod spans; +#[cfg(test)] +mod tests; + use counters::CoverageCounters; use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use spans::{CoverageSpan, CoverageSpans}; @@ -27,11 +30,12 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; +use rustc_span::source_map::SourceMap; use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol}; /// A simple error message wrapper for `coverage::Error`s. #[derive(Debug)] -pub(crate) struct Error { +struct Error { message: String, } @@ -75,6 +79,14 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { return; } + match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind { + TerminatorKind::Unreachable => { + trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`"); + return; + } + _ => {} + } + trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); @@ -85,6 +97,8 @@ struct Instrumentor<'a, 'tcx> { pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>, + source_file: Lrc, + fn_sig_span: Span, body_span: Span, basic_coverage_blocks: CoverageGraph, coverage_counters: CoverageCounters, @@ -92,14 +106,24 @@ struct Instrumentor<'a, 'tcx> { impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let hir_body = hir_body(tcx, mir_body.source.def_id()); + let source_map = tcx.sess.source_map(); + let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id()); let body_span = hir_body.value.span; + let source_file = source_map.lookup_source_file(body_span.lo()); + let fn_sig_span = match some_fn_sig.filter(|fn_sig| { + Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi())) + }) { + Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), + None => body_span.shrink_to_lo(), + }; let function_source_hash = hash_mir_source(tcx, hir_body); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); Self { pass_name, tcx, mir_body, + source_file, + fn_sig_span, body_span, basic_coverage_blocks, coverage_counters: CoverageCounters::new(function_source_hash), @@ -111,9 +135,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let source_map = tcx.sess.source_map(); let mir_source = self.mir_body.source; let def_id = mir_source.def_id(); + let fn_sig_span = self.fn_sig_span; let body_span = self.body_span; - debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span)); + debug!( + "instrumenting {:?}, fn sig span: {}, body span: {}", + def_id, + source_map.span_to_string(fn_sig_span), + source_map.span_to_string(body_span) + ); let mut graphviz_data = debug::GraphvizData::new(); let mut debug_used_expressions = debug::UsedExpressions::new(); @@ -135,6 +165,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // Compute `CoverageSpan`s from the `CoverageGraph`. let coverage_spans = CoverageSpans::generate_coverage_spans( &self.mir_body, + fn_sig_span, body_span, &self.basic_coverage_blocks, ); @@ -252,8 +283,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let tcx = self.tcx; let source_map = tcx.sess.source_map(); let body_span = self.body_span; - let source_file = source_map.lookup_source_file(body_span.lo()); - let file_name = Symbol::intern(&source_file.name.to_string()); + let file_name = Symbol::intern(&self.source_file.name.to_string()); let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes()); for covspan in coverage_spans { @@ -269,47 +299,22 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { bug!("Every BasicCoverageBlock should have a Counter or Expression"); }; graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); - // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special - // cases? - let some_code_region = if self.is_code_region_redundant(bcb, span, body_span) { - None - } else { - Some(make_code_region(file_name, &source_file, span, body_span)) - }; - inject_statement(self.mir_body, counter_kind, self.bcb_last_bb(bcb), some_code_region); - } - } - /// Returns true if the type of `BasicCoverageBlock` (specifically, it's `BasicBlock`s - /// `TerminatorKind`) with the given `Span` (relative to the `body_span`) is known to produce - /// a redundant coverage count. - /// - /// There is at least one case for this, and if it's not handled, the last line in a function - /// will be double-counted. - /// - /// If this method returns `true`, the counter (which other `Expressions` may depend on) is - /// still injected, but without an associated code region. - // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special cases? - fn is_code_region_redundant( - &self, - bcb: BasicCoverageBlock, - span: Span, - body_span: Span, - ) -> bool { - if span.hi() == body_span.hi() { - // All functions execute a `Return`-terminated `BasicBlock`, regardless of how the - // function returns; but only some functions also _can_ return after a `Goto` block - // that ends on the closing brace of the function (with the `Return`). When this - // happens, the last character is counted 2 (or possibly more) times, when we know - // the function returned only once (of course). By giving all `Goto` terminators at - // the end of a function a `non-reportable` code region, they are still counted - // if appropriate, but they don't increment the line counter, as long as their is - // also a `Return` on that last line. - if let TerminatorKind::Goto { .. } = self.bcb_terminator(bcb).kind { - return true; - } + debug!( + "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", + file_name, + self.source_file, + source_map.span_to_string(span), + source_map.span_to_string(body_span) + ); + + inject_statement( + self.mir_body, + counter_kind, + self.bcb_leader_bb(bcb), + Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), + ); } - false } /// `inject_coverage_span_counters()` looped through the `CoverageSpan`s and injected the @@ -408,11 +413,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.bcb_data(bcb).last_bb() } - #[inline] - fn bcb_terminator(&self, bcb: BasicCoverageBlock) -> &Terminator<'tcx> { - self.bcb_data(bcb).terminator(self.mir_body) - } - #[inline] fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData { &self.basic_coverage_blocks[bcb] @@ -471,7 +471,7 @@ fn inject_statement( code_region: some_code_region, }), }; - data.statements.push(statement); + data.statements.insert(0, statement); } // Non-code expressions are injected into the coverage map, without generating executable code. @@ -490,6 +490,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: Co /// Convert the Span into its file name, start line and column, and end line and column fn make_code_region( + source_map: &SourceMap, file_name: Symbol, source_file: &Lrc, span: Span, @@ -509,6 +510,8 @@ fn make_code_region( } else { source_file.lookup_file_pos(span.hi()) }; + let start_line = source_map.doctest_offset_line(&source_file.name, start_line); + let end_line = source_map.doctest_offset_line(&source_file.name, end_line); CodeRegion { file_name, start_line: start_line as u32, @@ -518,10 +521,15 @@ fn make_code_region( } } -fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { +fn fn_sig_and_body<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) { + // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back + // to HIR for it. let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - tcx.hir().body(fn_body_id) + (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id)) } fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs index e86bb96d29..aa34ae70ef 100644 --- a/compiler/rustc_mir/src/transform/coverage/query.rs +++ b/compiler/rustc_mir/src/transform/coverage/query.rs @@ -1,6 +1,8 @@ +use super::*; + use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Coverage, CoverageInfo, Location}; +use rustc_middle::mir::{self, Coverage, CoverageInfo, Location}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; @@ -9,6 +11,8 @@ use rustc_span::def_id::DefId; /// counter) and `FunctionCoverage::new()` (to extract the coverage map metadata from the MIR). pub(crate) fn provide(providers: &mut Providers) { providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); + providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id); + providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); } /// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in @@ -123,3 +127,34 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo coverage_visitor.info } + +fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { + let mir_body = tcx.optimized_mir(def_id); + for bb_data in mir_body.basic_blocks().iter() { + for statement in bb_data.statements.iter() { + if let StatementKind::Coverage(box ref coverage) = statement.kind { + if let Some(code_region) = coverage.code_region.as_ref() { + return Some(code_region.file_name); + } + } + } + } + None +} + +fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> { + let mir_body: &'tcx mir::Body<'tcx> = tcx.optimized_mir(def_id); + mir_body + .basic_blocks() + .iter() + .map(|data| { + data.statements.iter().filter_map(|statement| match statement.kind { + StatementKind::Coverage(box ref coverage) => { + coverage.code_region.as_ref() // may be None + } + _ => None, + }) + }) + .flatten() + .collect() +} diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index cda4fc1254..fd3e782f6d 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -1,10 +1,9 @@ use super::debug::term_type; -use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; use crate::util::spanview::source_range_no_file; use rustc_data_structures::graph::WithNumNodes; -use rustc_index::bit_set::BitSet; use rustc_middle::mir::{ self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, @@ -17,7 +16,7 @@ use rustc_span::{BytePos, Span, SyntaxContext}; use std::cmp::Ordering; #[derive(Debug, Copy, Clone)] -pub(crate) enum CoverageStatement { +pub(super) enum CoverageStatement { Statement(BasicBlock, Span, usize), Terminator(BasicBlock, Span), } @@ -66,7 +65,7 @@ impl CoverageStatement { /// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock` /// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`. #[derive(Debug, Clone)] -pub(crate) struct CoverageSpan { +pub(super) struct CoverageSpan { pub span: Span, pub bcb: BasicCoverageBlock, pub coverage_statements: Vec, @@ -74,6 +73,10 @@ pub(crate) struct CoverageSpan { } impl CoverageSpan { + pub fn for_fn_sig(fn_sig_span: Span) -> Self { + Self { span: fn_sig_span, bcb: START_BCB, coverage_statements: vec![], is_closure: false } + } + pub fn for_statement( statement: &Statement<'tcx>, span: Span, @@ -82,10 +85,10 @@ impl CoverageSpan { stmt_index: usize, ) -> Self { let is_closure = match statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Aggregate(box AggregateKind::Closure(_, _), _), - )) => true, + StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind { + AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true, + _ => false, + }, _ => false, }; @@ -109,9 +112,6 @@ impl CoverageSpan { pub fn merge_from(&mut self, mut other: CoverageSpan) { debug_assert!(self.is_mergeable(&other)); self.span = self.span.to(other.span); - if other.is_closure { - self.is_closure = true; - } self.coverage_statements.append(&mut other.coverage_statements); } @@ -171,6 +171,9 @@ pub struct CoverageSpans<'a, 'tcx> { /// The MIR, used to look up `BasicBlockData`. mir_body: &'a mir::Body<'tcx>, + /// A `Span` covering the signature of function for the MIR. + fn_sig_span: Span, + /// A `Span` covering the function body of the MIR (typically from left curly brace to right /// curly brace). body_span: Span, @@ -214,13 +217,36 @@ pub struct CoverageSpans<'a, 'tcx> { } impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { - pub(crate) fn generate_coverage_spans( + /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be + /// counted. + /// + /// The basic steps are: + /// + /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each + /// `BasicCoverageBlockData`. + /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position + /// are sorted with longer spans before shorter spans; and equal spans are sorted + /// (deterministically) based on "dominator" relationship (if any). + /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, + /// if another span or spans are already counting the same code region), or should be merged + /// into a broader combined span (because it represents a contiguous, non-branching, and + /// uninterrupted region of source code). + /// + /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since + /// closures have their own MIR, their `Span` in their enclosing function should be left + /// "uncovered". + /// + /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need + /// to be). + pub(super) fn generate_coverage_spans( mir_body: &'a mir::Body<'tcx>, + fn_sig_span: Span, body_span: Span, basic_coverage_blocks: &'a CoverageGraph, ) -> Vec { let mut coverage_spans = CoverageSpans { mir_body, + fn_sig_span, body_span, basic_coverage_blocks, sorted_spans_iter: None, @@ -242,27 +268,6 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { coverage_spans.to_refined_spans() } - /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be - /// counted. - /// - /// The basic steps are: - /// - /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each - /// `BasicCoverageBlockData`. - /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position - /// are sorted with longer spans before shorter spans; and equal spans are sorted - /// (deterministically) based on "dominator" relationship (if any). - /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, - /// if another span or spans are already counting the same code region), or should be merged - /// into a broader combined span (because it represents a contiguous, non-branching, and - /// uninterrupted region of source code). - /// - /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since - /// closures have their own MIR, their `Span` in their enclosing function should be left - /// "uncovered". - /// - /// Note the resulting vector of `CoverageSpan`s does may not be fully sorted (and does not need - /// to be). fn mir_to_initial_sorted_coverage_spans(&self) -> Vec { let mut initial_spans = Vec::::with_capacity(self.mir_body.num_nodes() * 2); for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { @@ -277,6 +282,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { return initial_spans; } + initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span)); + initial_spans.sort_unstable_by(|a, b| { if a.span.lo() == b.span.lo() { if a.span.hi() == b.span.hi() { @@ -331,7 +338,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { prev={:?}", self.prev() ); - self.discard_curr(); + self.take_curr(); } else if self.curr().is_closure { self.carve_out_span_for_closure(); } else if self.prev_original_span == self.curr().span { @@ -345,28 +352,28 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { debug!(" AT END, adding last prev={:?}", self.prev()); let prev = self.take_prev(); - let CoverageSpans { - mir_body, basic_coverage_blocks, pending_dups, mut refined_spans, .. - } = self; + let CoverageSpans { pending_dups, mut refined_spans, .. } = self; for dup in pending_dups { debug!(" ...adding at least one pending dup={:?}", dup); refined_spans.push(dup); } - refined_spans.push(prev); - - // Remove `CoverageSpan`s with empty spans ONLY if the empty `CoverageSpan`s BCB also has at - // least one other non-empty `CoverageSpan`. - let mut has_coverage = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - for covspan in &refined_spans { - if !covspan.span.is_empty() { - has_coverage.insert(covspan.bcb); - } + + // Async functions wrap a closure that implements the body to be executed. The enclosing + // function is called and returns an `impl Future` without initially executing any of the + // body. To avoid showing the return from the enclosing function as a "covered" return from + // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is + // excluded. The closure's `Return` is the only one that will be counted. This provides + // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace + // of the function body.) + let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() { + last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi() + } else { + false + }; + + if !body_ends_with_closure { + refined_spans.push(prev); } - refined_spans.retain(|covspan| { - !(covspan.span.is_empty() - && is_goto(&basic_coverage_blocks[covspan.bcb].terminator(mir_body).kind) - && has_coverage.contains(covspan.bcb)) - }); // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage // regions for the current function leave room for the closure's own coverage regions @@ -491,8 +498,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the /// `curr` coverage span. - fn discard_curr(&mut self) { - self.some_curr = None; + fn take_curr(&mut self) -> CoverageSpan { + self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) } /// Returns true if the curr span should be skipped because prev has already advanced beyond the @@ -508,11 +515,11 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { self.prev().span.hi() <= self.curr().span.lo() } - /// If `prev`s span extends left of the closure (`curr`), carve out the closure's - /// span from `prev`'s span. (The closure's coverage counters will be injected when - /// processing the closure's own MIR.) Add the portion of the span to the left of the - /// closure; and if the span extends to the right of the closure, update `prev` to - /// that portion of the span. For any `pending_dups`, repeat the same process. + /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from + /// `prev`'s span. (The closure's coverage counters will be injected when processing the + /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span + /// extends to the right of the closure, update `prev` to that portion of the span. For any + /// `pending_dups`, repeat the same process. fn carve_out_span_for_closure(&mut self) { let curr_span = self.curr().span; let left_cutoff = curr_span.lo(); @@ -541,7 +548,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { dup.span = dup.span.with_lo(right_cutoff); } self.pending_dups.append(&mut pending_dups); - self.discard_curr(); // since self.prev() was already updated + let closure_covspan = self.take_curr(); + self.refined_spans.push(closure_covspan); // since self.prev() was already updated } else { pending_dups.clear(); } @@ -645,7 +653,10 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } } -fn filtered_statement_span(statement: &'a Statement<'tcx>, body_span: Span) -> Option { +pub(super) fn filtered_statement_span( + statement: &'a Statement<'tcx>, + body_span: Span, +) -> Option { match statement.kind { // These statements have spans that are often outside the scope of the executed source code // for their parent `BasicBlock`. @@ -686,7 +697,10 @@ fn filtered_statement_span(statement: &'a Statement<'tcx>, body_span: Span) -> O } } -fn filtered_terminator_span(terminator: &'a Terminator<'tcx>, body_span: Span) -> Option { +pub(super) fn filtered_terminator_span( + terminator: &'a Terminator<'tcx>, + body_span: Span, +) -> Option { match terminator.kind { // These terminators have spans that don't positively contribute to computing a reasonable // span of actually executed source code. (For example, SwitchInt terminators extracted from @@ -699,30 +713,8 @@ fn filtered_terminator_span(terminator: &'a Terminator<'tcx>, body_span: Span) - | TerminatorKind::DropAndReplace { .. } | TerminatorKind::SwitchInt { .. } // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. - // FIXME(richkadel): Note that `Goto` was moved to it's own match arm, for the reasons - // described below. Add tests to confirm whether or not similar cases also apply to - // `FalseEdge`. - | TerminatorKind::FalseEdge { .. } => None, - - // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special cases? - // - // `Goto`s are often the targets of `SwitchInt` branches, and certain important - // optimizations to replace some `Counter`s with `Expression`s require a separate - // `BasicCoverageBlock` for each branch, to support the `Counter`, when needed. - // - // Also, some test cases showed that `Goto` terminators, and to some degree their `Span`s, - // provided useful context for coverage, such as to count and show when `if` blocks - // _without_ `else` blocks execute the `false` case (counting when the body of the `if` - // was _not_ taken). In these cases, the `Goto` span is ultimately given a `CoverageSpan` - // of 1 character, at the end of it's original `Span`. - // - // However, in other cases, a visible `CoverageSpan` is not wanted, but the `Goto` - // block must still be counted (for example, to contribute its count to an `Expression` - // that reports the execution count for some other block). In these cases, the code region - // is set to `None`. (See `Instrumentor::is_code_region_redundant()`.) - TerminatorKind::Goto { .. } => { - Some(function_source_span(terminator.source_info.span.shrink_to_hi(), body_span)) - } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::Goto { .. } => None, // Retain spans from all other terminators TerminatorKind::Resume @@ -743,11 +735,3 @@ fn function_source_span(span: Span, body_span: Span) -> Span { let span = original_sp(span, body_span).with_ctxt(SyntaxContext::root()); if body_span.contains(span) { span } else { body_span } } - -#[inline(always)] -fn is_goto(term_kind: &TerminatorKind<'tcx>) -> bool { - match term_kind { - TerminatorKind::Goto { .. } => true, - _ => false, - } -} diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml b/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml new file mode 100644 index 0000000000..eda1ced001 --- /dev/null +++ b/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "coverage_test_macros" +version = "0.0.0" +edition = "2018" + +[lib] +proc-macro = true +doctest = false diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs b/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs new file mode 100644 index 0000000000..3d6095d273 --- /dev/null +++ b/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs @@ -0,0 +1,6 @@ +use proc_macro::TokenStream; + +#[proc_macro] +pub fn let_bcb(item: TokenStream) -> TokenStream { + format!("let bcb{} = graph::BasicCoverageBlock::from_usize({});", item, item).parse().unwrap() +} diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs new file mode 100644 index 0000000000..d36f1b8e5f --- /dev/null +++ b/compiler/rustc_mir/src/transform/coverage/tests.rs @@ -0,0 +1,714 @@ +//! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR +//! pass. +//! +//! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage` +//! functions and algorithms. Mocked objects include instances of `mir::Body`; including +//! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on +//! real, runtime versions of these mocked-up objects have constraints (such as cross-thread +//! limitations) and deep dependencies on other elements of the full Rust compiler (which is +//! *not* constructed or mocked for these tests). +//! +//! Of particular note, attempting to simply print elements of the `mir::Body` with default +//! `Debug` formatting can fail because some `Debug` format implementations require the +//! `TyCtxt`, obtained via a static global variable that is *not* set for these tests. +//! Initializing the global type context is prohibitively complex for the scope and scale of these +//! tests (essentially requiring initializing the entire compiler). +//! +//! Also note, some basic features of `Span` also rely on the `Span`s own "session globals", which +//! are unrelated to the `TyCtxt` global. Without initializing the `Span` session globals, some +//! basic, coverage-specific features would be impossible to test, but thankfully initializing these +//! globals is comparitively simpler. The easiest way is to wrap the test in a closure argument +//! to: `rustc_span::with_default_session_globals(|| { test_here(); })`. + +use super::counters; +use super::debug; +use super::graph; +use super::spans; + +use coverage_test_macros::let_bcb; + +use rustc_data_structures::graph::WithNumNodes; +use rustc_data_structures::graph::WithSuccessors; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::coverage::CoverageKind; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, DebruijnIndex, TyS, TypeFlags}; +use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP}; + +// All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`. +const TEMP_BLOCK: BasicBlock = BasicBlock::MAX; + +fn dummy_ty() -> &'static TyS<'static> { + thread_local! { + static DUMMY_TYS: &'static TyS<'static> = Box::leak(box TyS::make_for_test( + ty::Bool, + TypeFlags::empty(), + DebruijnIndex::from_usize(0), + )); + } + + &DUMMY_TYS.with(|tys| *tys) +} + +struct MockBlocks<'tcx> { + blocks: IndexVec>, + dummy_place: Place<'tcx>, + next_local: usize, +} + +impl<'tcx> MockBlocks<'tcx> { + fn new() -> Self { + Self { + blocks: IndexVec::new(), + dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() }, + next_local: 0, + } + } + + fn new_temp(&mut self) -> Local { + let index = self.next_local; + self.next_local += 1; + Local::new(index) + } + + fn push(&mut self, kind: TerminatorKind<'tcx>) -> BasicBlock { + let next_lo = if let Some(last) = self.blocks.last() { + self.blocks[last].terminator().source_info.span.hi() + } else { + BytePos(1) + }; + let next_hi = next_lo + BytePos(1); + self.blocks.push(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)), + kind, + }), + is_cleanup: false, + }) + } + + fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) { + match self.blocks[from_block].terminator_mut().kind { + TerminatorKind::Assert { ref mut target, .. } + | TerminatorKind::Call { destination: Some((_, ref mut target)), .. } + | TerminatorKind::Drop { ref mut target, .. } + | TerminatorKind::DropAndReplace { ref mut target, .. } + | TerminatorKind::FalseEdge { real_target: ref mut target, .. } + | TerminatorKind::FalseUnwind { real_target: ref mut target, .. } + | TerminatorKind::Goto { ref mut target } + | TerminatorKind::InlineAsm { destination: Some(ref mut target), .. } + | TerminatorKind::Yield { resume: ref mut target, .. } => *target = to_block, + ref invalid => bug!("Invalid from_block: {:?}", invalid), + } + } + + fn add_block_from( + &mut self, + some_from_block: Option, + to_kind: TerminatorKind<'tcx>, + ) -> BasicBlock { + let new_block = self.push(to_kind); + if let Some(from_block) = some_from_block { + self.link(from_block, new_block); + } + new_block + } + + fn set_branch(&mut self, switchint: BasicBlock, branch_index: usize, to_block: BasicBlock) { + match self.blocks[switchint].terminator_mut().kind { + TerminatorKind::SwitchInt { ref mut targets, .. } => { + let mut branches = targets.iter().collect::>(); + let otherwise = if branch_index == branches.len() { + to_block + } else { + let old_otherwise = targets.otherwise(); + if branch_index > branches.len() { + branches.push((branches.len() as u128, old_otherwise)); + while branches.len() < branch_index { + branches.push((branches.len() as u128, TEMP_BLOCK)); + } + to_block + } else { + branches[branch_index] = (branch_index as u128, to_block); + old_otherwise + } + }; + *targets = SwitchTargets::new(branches.into_iter(), otherwise); + } + ref invalid => bug!("Invalid BasicBlock kind or no to_block: {:?}", invalid), + } + } + + fn call(&mut self, some_from_block: Option) -> BasicBlock { + self.add_block_from( + some_from_block, + TerminatorKind::Call { + func: Operand::Copy(self.dummy_place.clone()), + args: vec![], + destination: Some((self.dummy_place.clone(), TEMP_BLOCK)), + cleanup: None, + from_hir_call: false, + fn_span: DUMMY_SP, + }, + ) + } + + fn goto(&mut self, some_from_block: Option) -> BasicBlock { + self.add_block_from(some_from_block, TerminatorKind::Goto { target: TEMP_BLOCK }) + } + + fn switchint(&mut self, some_from_block: Option) -> BasicBlock { + let switchint_kind = TerminatorKind::SwitchInt { + discr: Operand::Move(Place::from(self.new_temp())), + switch_ty: dummy_ty(), + targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK), + }; + self.add_block_from(some_from_block, switchint_kind) + } + + fn return_(&mut self, some_from_block: Option) -> BasicBlock { + self.add_block_from(some_from_block, TerminatorKind::Return) + } + + fn to_body(self) -> Body<'tcx> { + Body::new_cfg_only(self.blocks) + } +} + +fn debug_basic_blocks(mir_body: &Body<'tcx>) -> String { + format!( + "{:?}", + mir_body + .basic_blocks() + .iter_enumerated() + .map(|(bb, data)| { + let term = &data.terminator(); + let kind = &term.kind; + let span = term.source_info.span; + let sp = format!("(span:{},{})", span.lo().to_u32(), span.hi().to_u32()); + match kind { + TerminatorKind::Assert { target, .. } + | TerminatorKind::Call { destination: Some((_, target)), .. } + | TerminatorKind::Drop { target, .. } + | TerminatorKind::DropAndReplace { target, .. } + | TerminatorKind::FalseEdge { real_target: target, .. } + | TerminatorKind::FalseUnwind { real_target: target, .. } + | TerminatorKind::Goto { target } + | TerminatorKind::InlineAsm { destination: Some(target), .. } + | TerminatorKind::Yield { resume: target, .. } => { + format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), target) + } + TerminatorKind::SwitchInt { targets, .. } => { + format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), targets) + } + _ => format!("{}{:?}:{}", sp, bb, debug::term_type(kind)), + } + }) + .collect::>() + ) +} + +static PRINT_GRAPHS: bool = false; + +fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { + if PRINT_GRAPHS { + println!( + "digraph {} {{\n{}\n}}", + name, + mir_body + .basic_blocks() + .iter_enumerated() + .map(|(bb, data)| { + format!( + " {:?} [label=\"{:?}: {}\"];\n{}", + bb, + bb, + debug::term_type(&data.terminator().kind), + mir_body + .successors(bb) + .map(|successor| { format!(" {:?} -> {:?};", bb, successor) }) + .collect::>() + .join("\n") + ) + }) + .collect::>() + .join("\n") + ); + } +} + +fn print_coverage_graphviz( + name: &str, + mir_body: &Body<'_>, + basic_coverage_blocks: &graph::CoverageGraph, +) { + if PRINT_GRAPHS { + println!( + "digraph {} {{\n{}\n}}", + name, + basic_coverage_blocks + .iter_enumerated() + .map(|(bcb, bcb_data)| { + format!( + " {:?} [label=\"{:?}: {}\"];\n{}", + bcb, + bcb, + debug::term_type(&bcb_data.terminator(mir_body).kind), + basic_coverage_blocks + .successors(bcb) + .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) + .collect::>() + .join("\n") + ) + }) + .collect::>() + .join("\n") + ); + } +} + +/// Create a mock `Body` with a simple flow. +fn goto_switchint() -> Body<'a> { + let mut blocks = MockBlocks::new(); + let start = blocks.call(None); + let goto = blocks.goto(Some(start)); + let switchint = blocks.switchint(Some(goto)); + let then_call = blocks.call(None); + let else_call = blocks.call(None); + blocks.set_branch(switchint, 0, then_call); + blocks.set_branch(switchint, 1, else_call); + blocks.return_(Some(then_call)); + blocks.return_(Some(else_call)); + + let mir_body = blocks.to_body(); + print_mir_graphviz("mir_goto_switchint", &mir_body); + /* Graphviz character plots created using: `graph-easy --as=boxart`: + ┌────────────────┐ + │ bb0: Call │ + └────────────────┘ + │ + │ + ▼ + ┌────────────────┐ + │ bb1: Goto │ + └────────────────┘ + │ + │ + ▼ + ┌─────────────┐ ┌────────────────┐ + │ bb4: Call │ ◀── │ bb2: SwitchInt │ + └─────────────┘ └────────────────┘ + │ │ + │ │ + ▼ ▼ + ┌─────────────┐ ┌────────────────┐ + │ bb6: Return │ │ bb3: Call │ + └─────────────┘ └────────────────┘ + │ + │ + ▼ + ┌────────────────┐ + │ bb5: Return │ + └────────────────┘ + */ + mir_body +} + +macro_rules! assert_successors { + ($basic_coverage_blocks:ident, $i:ident, [$($successor:ident),*]) => { + let mut successors = $basic_coverage_blocks.successors[$i].clone(); + successors.sort_unstable(); + assert_eq!(successors, vec![$($successor),*]); + } +} + +#[test] +fn test_covgraph_goto_switchint() { + let mir_body = goto_switchint(); + if false { + println!("basic_blocks = {}", debug_basic_blocks(&mir_body)); + } + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks); + /* + ┌──────────────┐ ┌─────────────────┐ + │ bcb2: Return │ ◀── │ bcb0: SwitchInt │ + └──────────────┘ └─────────────────┘ + │ + │ + ▼ + ┌─────────────────┐ + │ bcb1: Return │ + └─────────────────┘ + */ + assert_eq!( + basic_coverage_blocks.num_nodes(), + 3, + "basic_coverage_blocks: {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + + let_bcb!(0); + let_bcb!(1); + let_bcb!(2); + + assert_successors!(basic_coverage_blocks, bcb0, [bcb1, bcb2]); + assert_successors!(basic_coverage_blocks, bcb1, []); + assert_successors!(basic_coverage_blocks, bcb2, []); +} + +/// Create a mock `Body` with a loop. +fn switchint_then_loop_else_return() -> Body<'a> { + let mut blocks = MockBlocks::new(); + let start = blocks.call(None); + let switchint = blocks.switchint(Some(start)); + let then_call = blocks.call(None); + blocks.set_branch(switchint, 0, then_call); + let backedge_goto = blocks.goto(Some(then_call)); + blocks.link(backedge_goto, switchint); + let else_return = blocks.return_(None); + blocks.set_branch(switchint, 1, else_return); + + let mir_body = blocks.to_body(); + print_mir_graphviz("mir_switchint_then_loop_else_return", &mir_body); + /* + ┌────────────────┐ + │ bb0: Call │ + └────────────────┘ + │ + │ + ▼ + ┌─────────────┐ ┌────────────────┐ + │ bb4: Return │ ◀── │ bb1: SwitchInt │ ◀┐ + └─────────────┘ └────────────────┘ │ + │ │ + │ │ + ▼ │ + ┌────────────────┐ │ + │ bb2: Call │ │ + └────────────────┘ │ + │ │ + │ │ + ▼ │ + ┌────────────────┐ │ + │ bb3: Goto │ ─┘ + └────────────────┘ + */ + mir_body +} + +#[test] +fn test_covgraph_switchint_then_loop_else_return() { + let mir_body = switchint_then_loop_else_return(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + print_coverage_graphviz( + "covgraph_switchint_then_loop_else_return", + &mir_body, + &basic_coverage_blocks, + ); + /* + ┌─────────────────┐ + │ bcb0: Call │ + └─────────────────┘ + │ + │ + ▼ + ┌────────────┐ ┌─────────────────┐ + │ bcb3: Goto │ ◀── │ bcb1: SwitchInt │ ◀┐ + └────────────┘ └─────────────────┘ │ + │ │ │ + │ │ │ + │ ▼ │ + │ ┌─────────────────┐ │ + │ │ bcb2: Return │ │ + │ └─────────────────┘ │ + │ │ + └─────────────────────────────────────┘ + */ + assert_eq!( + basic_coverage_blocks.num_nodes(), + 4, + "basic_coverage_blocks: {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + + let_bcb!(0); + let_bcb!(1); + let_bcb!(2); + let_bcb!(3); + + assert_successors!(basic_coverage_blocks, bcb0, [bcb1]); + assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]); + assert_successors!(basic_coverage_blocks, bcb2, []); + assert_successors!(basic_coverage_blocks, bcb3, [bcb1]); +} + +/// Create a mock `Body` with nested loops. +fn switchint_loop_then_inner_loop_else_break() -> Body<'a> { + let mut blocks = MockBlocks::new(); + let start = blocks.call(None); + let switchint = blocks.switchint(Some(start)); + let then_call = blocks.call(None); + blocks.set_branch(switchint, 0, then_call); + let else_return = blocks.return_(None); + blocks.set_branch(switchint, 1, else_return); + + let inner_start = blocks.call(Some(then_call)); + let inner_switchint = blocks.switchint(Some(inner_start)); + let inner_then_call = blocks.call(None); + blocks.set_branch(inner_switchint, 0, inner_then_call); + let inner_backedge_goto = blocks.goto(Some(inner_then_call)); + blocks.link(inner_backedge_goto, inner_switchint); + let inner_else_break_goto = blocks.goto(None); + blocks.set_branch(inner_switchint, 1, inner_else_break_goto); + + let backedge_goto = blocks.goto(Some(inner_else_break_goto)); + blocks.link(backedge_goto, switchint); + + let mir_body = blocks.to_body(); + print_mir_graphviz("mir_switchint_loop_then_inner_loop_else_break", &mir_body); + /* + ┌────────────────┐ + │ bb0: Call │ + └────────────────┘ + │ + │ + ▼ + ┌─────────────┐ ┌────────────────┐ + │ bb3: Return │ ◀── │ bb1: SwitchInt │ ◀─────┐ + └─────────────┘ └────────────────┘ │ + │ │ + │ │ + ▼ │ + ┌────────────────┐ │ + │ bb2: Call │ │ + └────────────────┘ │ + │ │ + │ │ + ▼ │ + ┌────────────────┐ │ + │ bb4: Call │ │ + └────────────────┘ │ + │ │ + │ │ + ▼ │ + ┌─────────────┐ ┌────────────────┐ │ + │ bb8: Goto │ ◀── │ bb5: SwitchInt │ ◀┐ │ + └─────────────┘ └────────────────┘ │ │ + │ │ │ │ + │ │ │ │ + ▼ ▼ │ │ + ┌─────────────┐ ┌────────────────┐ │ │ + │ bb9: Goto │ ─┐ │ bb6: Call │ │ │ + └─────────────┘ │ └────────────────┘ │ │ + │ │ │ │ + │ │ │ │ + │ ▼ │ │ + │ ┌────────────────┐ │ │ + │ │ bb7: Goto │ ─┘ │ + │ └────────────────┘ │ + │ │ + └───────────────────────────┘ + */ + mir_body +} + +#[test] +fn test_covgraph_switchint_loop_then_inner_loop_else_break() { + let mir_body = switchint_loop_then_inner_loop_else_break(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + print_coverage_graphviz( + "covgraph_switchint_loop_then_inner_loop_else_break", + &mir_body, + &basic_coverage_blocks, + ); + /* + ┌─────────────────┐ + │ bcb0: Call │ + └─────────────────┘ + │ + │ + ▼ + ┌──────────────┐ ┌─────────────────┐ + │ bcb2: Return │ ◀── │ bcb1: SwitchInt │ ◀┐ + └──────────────┘ └─────────────────┘ │ + │ │ + │ │ + ▼ │ + ┌─────────────────┐ │ + │ bcb3: Call │ │ + └─────────────────┘ │ + │ │ + │ │ + ▼ │ + ┌──────────────┐ ┌─────────────────┐ │ + │ bcb6: Goto │ ◀── │ bcb4: SwitchInt │ ◀┼────┐ + └──────────────┘ └─────────────────┘ │ │ + │ │ │ │ + │ │ │ │ + │ ▼ │ │ + │ ┌─────────────────┐ │ │ + │ │ bcb5: Goto │ ─┘ │ + │ └─────────────────┘ │ + │ │ + └────────────────────────────────────────────┘ + */ + assert_eq!( + basic_coverage_blocks.num_nodes(), + 7, + "basic_coverage_blocks: {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + + let_bcb!(0); + let_bcb!(1); + let_bcb!(2); + let_bcb!(3); + let_bcb!(4); + let_bcb!(5); + let_bcb!(6); + + assert_successors!(basic_coverage_blocks, bcb0, [bcb1]); + assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]); + assert_successors!(basic_coverage_blocks, bcb2, []); + assert_successors!(basic_coverage_blocks, bcb3, [bcb4]); + assert_successors!(basic_coverage_blocks, bcb4, [bcb5, bcb6]); + assert_successors!(basic_coverage_blocks, bcb5, [bcb1]); + assert_successors!(basic_coverage_blocks, bcb6, [bcb4]); +} + +#[test] +fn test_find_loop_backedges_none() { + let mir_body = goto_switchint(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + if false { + println!( + "basic_coverage_blocks = {:?}", + basic_coverage_blocks.iter_enumerated().collect::>() + ); + println!("successors = {:?}", basic_coverage_blocks.successors); + } + let backedges = graph::find_loop_backedges(&basic_coverage_blocks); + assert_eq!( + backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), + 0, + "backedges: {:?}", + backedges + ); +} + +#[test] +fn test_find_loop_backedges_one() { + let mir_body = switchint_then_loop_else_return(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let backedges = graph::find_loop_backedges(&basic_coverage_blocks); + assert_eq!( + backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), + 1, + "backedges: {:?}", + backedges + ); + + let_bcb!(1); + let_bcb!(3); + + assert_eq!(backedges[bcb1], vec![bcb3]); +} + +#[test] +fn test_find_loop_backedges_two() { + let mir_body = switchint_loop_then_inner_loop_else_break(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let backedges = graph::find_loop_backedges(&basic_coverage_blocks); + assert_eq!( + backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), + 2, + "backedges: {:?}", + backedges + ); + + let_bcb!(1); + let_bcb!(4); + let_bcb!(5); + let_bcb!(6); + + assert_eq!(backedges[bcb1], vec![bcb5]); + assert_eq!(backedges[bcb4], vec![bcb6]); +} + +#[test] +fn test_traverse_coverage_with_loops() { + let mir_body = switchint_loop_then_inner_loop_else_break(); + let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let mut traversed_in_order = Vec::new(); + let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks); + while let Some(bcb) = traversal.next(&basic_coverage_blocks) { + traversed_in_order.push(bcb); + } + + let_bcb!(6); + + // bcb0 is visited first. Then bcb1 starts the first loop, and all remaining nodes, *except* + // bcb6 are inside the first loop. + assert_eq!( + *traversed_in_order.last().expect("should have elements"), + bcb6, + "bcb6 should not be visited until all nodes inside the first loop have been visited" + ); +} + +fn synthesize_body_span_from_terminators(mir_body: &Body<'_>) -> Span { + let mut some_span: Option = None; + for (_, data) in mir_body.basic_blocks().iter_enumerated() { + let term_span = data.terminator().source_info.span; + if let Some(span) = some_span.as_mut() { + *span = span.to(term_span); + } else { + some_span = Some(term_span) + } + } + some_span.expect("body must have at least one BasicBlock") +} + +#[test] +fn test_make_bcb_counters() { + rustc_span::with_default_session_globals(|| { + let mir_body = goto_switchint(); + let body_span = synthesize_body_span_from_terminators(&mir_body); + let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); + let mut coverage_spans = Vec::new(); + for (bcb, data) in basic_coverage_blocks.iter_enumerated() { + if let Some(span) = + spans::filtered_terminator_span(data.terminator(&mir_body), body_span) + { + coverage_spans.push(spans::CoverageSpan::for_terminator(span, bcb, data.last_bb())); + } + } + let mut coverage_counters = counters::CoverageCounters::new(0); + let intermediate_expressions = coverage_counters + .make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans) + .expect("should be Ok"); + assert_eq!(intermediate_expressions.len(), 0); + + let_bcb!(1); + assert_eq!( + 1, // coincidentally, bcb1 has a `Counter` with id = 1 + match basic_coverage_blocks[bcb1].counter().expect("should have a counter") { + CoverageKind::Counter { id, .. } => id, + _ => panic!("expected a Counter"), + } + .as_u32() + ); + + let_bcb!(2); + assert_eq!( + 2, // coincidentally, bcb2 has a `Counter` with id = 2 + match basic_coverage_blocks[bcb2].counter().expect("should have a counter") { + CoverageKind::Counter { id, .. } => id, + _ => panic!("expected a Counter"), + } + .as_u32() + ); + }); +} diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index f97dcf4852..b16a99d7f0 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -46,6 +46,10 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { let should_cleanup = !opts_to_apply.is_empty(); for opt_to_apply in opts_to_apply { + if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) { + break; + } + trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); let statements_before = @@ -212,9 +216,10 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { let discr = self.find_switch_discriminant_info(bb, switch)?; // go through each target, finding a discriminant read, and a switch - let results = discr.targets_with_values.iter().map(|(value, target)| { - self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone()) - }); + let results = discr + .targets_with_values + .iter() + .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value)); // if the optimization did not apply for one of the targets, then abort if results.clone().any(|x| x.is_none()) || results.len() == 0 { @@ -279,6 +284,33 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { return None; } + // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. + // for example, this should not be optimized: + // + // ```rust + // enum E<'a> { Empty, Some(&'a E<'a>), } + // let Some(Some(_)) = e; + // ``` + // + // ```mir + // bb0: { + // _2 = discriminant(*_1) + // switchInt(_2) -> [...] + // } + // bb1: { + // _3 = discriminant(*(((*_1) as Some).0: &E)) + // switchInt(_3) -> [...] + // } + // ``` + let discr_place = discr_info.place_of_adt_discr_read; + let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; + if discr_place.local == this_discr_place.local + && this_discr_place.projection.starts_with(discr_place.projection) + { + trace!("NO: one target is the projection of another"); + return None; + } + // if we reach this point, the optimization applies, and we should be able to optimize this case // store the info that is needed to apply the optimization diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 039d4753a8..dc413f8dd2 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -720,13 +720,13 @@ fn sanitize_witness<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, witness: Ty<'tcx>, - upvars: &Vec>, + upvars: Vec>, saved_locals: &GeneratorSavedLocals, ) { let did = body.source.def_id(); let allowed_upvars = tcx.erase_regions(upvars); let allowed = match witness.kind() { - ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), + &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s), _ => { tcx.sess.delay_span_bug( body.span, @@ -1303,7 +1303,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); - sanitize_witness(tcx, body, interior, &upvars, &liveness_info.saved_locals); + sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals); if tcx.sess.opts.debugging_opts.validate_mir { let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias { diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 7737672dbd..6e7575c1d7 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -7,6 +7,7 @@ use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; +use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_span::{hygiene::ExpnKind, ExpnData, Span}; use rustc_target::spec::abi::Abi; @@ -28,6 +29,7 @@ pub struct Inline; #[derive(Copy, Clone, Debug)] struct CallSite<'tcx> { callee: Instance<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, block: BasicBlock, target: Option, source_info: SourceInfo, @@ -39,14 +41,6 @@ impl<'tcx> MirPass<'tcx> for Inline { return; } - if tcx.sess.opts.debugging_opts.instrument_coverage { - // The current implementation of source code coverage injects code region counters - // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code- - // based function. - debug!("function inlining is disabled when compiling with `instrument_coverage`"); - return; - } - if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); @@ -120,7 +114,7 @@ impl Inliner<'tcx> { let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions( self.tcx, self.param_env, - callee_body, + callee_body.clone(), ); let old_blocks = caller_body.basic_blocks().next_index(); @@ -173,22 +167,23 @@ impl Inliner<'tcx> { // Only consider direct calls to functions let terminator = bb_data.terminator(); - if let TerminatorKind::Call { func: ref op, ref destination, .. } = terminator.kind { - if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() { - // To resolve an instance its substs have to be fully normalized, so - // we do this here. - let normalized_substs = self.tcx.normalize_erasing_regions(self.param_env, substs); + if let TerminatorKind::Call { ref func, ref destination, .. } = terminator.kind { + let func_ty = func.ty(caller_body, self.tcx); + if let ty::FnDef(def_id, substs) = *func_ty.kind() { + // To resolve an instance its substs have to be fully normalized. + let substs = self.tcx.normalize_erasing_regions(self.param_env, substs); let callee = - Instance::resolve(self.tcx, self.param_env, callee_def_id, normalized_substs) - .ok() - .flatten()?; + Instance::resolve(self.tcx, self.param_env, def_id, substs).ok().flatten()?; if let InstanceDef::Virtual(..) | InstanceDef::Intrinsic(_) = callee.def { return None; } + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); + return Some(CallSite { callee, + fn_sig, block: bb, target: destination.map(|(_, target)| target), source_info: terminator.source_info, @@ -203,9 +198,8 @@ impl Inliner<'tcx> { debug!("should_inline({:?})", callsite); let tcx = self.tcx; - // Cannot inline generators which haven't been transformed yet - if callee_body.yield_ty.is_some() { - debug!(" yield ty present - not inlining"); + if callsite.fn_sig.c_variadic() { + debug!("callee is variadic - not inlining"); return false; } @@ -218,11 +212,7 @@ impl Inliner<'tcx> { return false; } - let self_no_sanitize = - self.codegen_fn_attrs.no_sanitize & self.tcx.sess.opts.debugging_opts.sanitizer; - let callee_no_sanitize = - codegen_fn_attrs.no_sanitize & self.tcx.sess.opts.debugging_opts.sanitizer; - if self_no_sanitize != callee_no_sanitize { + if self.codegen_fn_attrs.no_sanitize != codegen_fn_attrs.no_sanitize { debug!("`callee has incompatible no_sanitize attribute - not inlining"); return false; } @@ -256,9 +246,14 @@ impl Inliner<'tcx> { self.tcx.sess.opts.debugging_opts.inline_mir_threshold }; - // Significantly lower the threshold for inlining cold functions + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + debug!("#[naked] present - not inlining"); + return false; + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { - threshold /= 5; + debug!("#[cold] present - not inlining"); + return false; } // Give a bonus functions with a small number of blocks, @@ -447,7 +442,7 @@ impl Inliner<'tcx> { }; // Copy the arguments if needed. - let args: Vec<_> = self.make_call_args(args, &callsite, caller_body); + let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body); let mut integrator = Integrator { args: &args, @@ -461,6 +456,7 @@ impl Inliner<'tcx> { tcx: self.tcx, callsite_span: callsite.source_info.span, body_span: callee_body.span, + always_live_locals: BitSet::new_filled(callee_body.local_decls.len()), }; // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones @@ -492,6 +488,34 @@ impl Inliner<'tcx> { } } + // If there are any locals without storage markers, give them storage only for the + // duration of the call. + for local in callee_body.vars_and_temps_iter() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageLive(new_local), + }); + } + } + if let Some(block) = callsite.target { + // To avoid repeated O(n) insert, push any new statements to the end and rotate + // the slice once. + let mut n = 0; + for local in callee_body.vars_and_temps_iter().rev() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(new_local), + }); + n += 1; + } + } + caller_body[block].statements.rotate_right(n); + } + // Insert all of the (mapped) parts of the callee body into the caller. caller_body.local_decls.extend( // FIXME(eddyb) make `Range` iterable so that we can use @@ -528,6 +552,7 @@ impl Inliner<'tcx> { args: Vec>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + callee_body: &Body<'tcx>, ) -> Vec { let tcx = self.tcx; @@ -554,9 +579,7 @@ impl Inliner<'tcx> { // tmp2 = tuple_tmp.2 // // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. - // FIXME(eddyb) make this check for `"rust-call"` ABI combined with - // `callee_body.spread_arg == None`, instead of special-casing closures. - if tcx.is_closure(callsite.callee.def_id()) { + if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() { let mut args = args.into_iter(); let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); @@ -673,6 +696,7 @@ struct Integrator<'a, 'tcx> { tcx: TyCtxt<'tcx>, callsite_span: Span, body_span: Span, + always_live_locals: BitSet, } impl<'a, 'tcx> Integrator<'a, 'tcx> { @@ -762,6 +786,15 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) = + statement.kind + { + self.always_live_locals.remove(local); + } + self.super_statement(statement, location); + } + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) { // Don't try to modify the implicit `_0` access on return (`return` terminators are // replaced down below anyways). diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index 59b7db2431..3eb2b500d6 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -39,13 +39,21 @@ pub struct InstCombineVisitor<'tcx> { tcx: TyCtxt<'tcx>, } +impl<'tcx> InstCombineVisitor<'tcx> { + fn should_combine(&self, rvalue: &Rvalue<'tcx>, location: Location) -> bool { + self.tcx.consider_optimizing(|| { + format!("InstCombine - Rvalue: {:?} Location: {:?}", rvalue, location) + }) + } +} + impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - if self.optimizations.and_stars.remove(&location) { + if self.optimizations.and_stars.remove(&location) && self.should_combine(rvalue, location) { debug!("replacing `&*`: {:?}", rvalue); let new_place = match rvalue { Rvalue::Ref(_, _, place) => { @@ -67,18 +75,24 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { } if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { - debug!("replacing `Len([_; N])`: {:?}", rvalue); - *rvalue = Rvalue::Use(Operand::Constant(box constant)); + if self.should_combine(rvalue, location) { + debug!("replacing `Len([_; N])`: {:?}", rvalue); + *rvalue = Rvalue::Use(Operand::Constant(box constant)); + } } if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) { - debug!("replacing {:?} with {:?}", rvalue, operand); - *rvalue = Rvalue::Use(operand); + if self.should_combine(rvalue, location) { + debug!("replacing {:?} with {:?}", rvalue, operand); + *rvalue = Rvalue::Use(operand); + } } if let Some(place) = self.optimizations.unneeded_deref.remove(&location) { - debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place); - *rvalue = Rvalue::Use(Operand::Copy(place)); + if self.should_combine(rvalue, location) { + debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place); + *rvalue = Rvalue::Use(Operand::Copy(place)); + } } self.super_rvalue(rvalue, location) diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir/src/transform/lower_intrinsics.rs new file mode 100644 index 0000000000..f5968532eb --- /dev/null +++ b/compiler/rustc_mir/src/transform/lower_intrinsics.rs @@ -0,0 +1,119 @@ +//! Lowers intrinsic calls + +use crate::transform::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_target::spec::abi::Abi; + +pub struct LowerIntrinsics; + +impl<'tcx> MirPass<'tcx> for LowerIntrinsics { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + for block in basic_blocks { + let terminator = block.terminator.as_mut().unwrap(); + if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind { + let func_ty = func.ty(local_decls, tcx); + let (intrinsic_name, substs) = match resolve_rust_intrinsic(tcx, func_ty) { + None => continue, + Some(it) => it, + }; + match intrinsic_name { + sym::unreachable => { + terminator.kind = TerminatorKind::Unreachable; + } + sym::forget => { + if let Some((destination, target)) = *destination { + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(box ( + destination, + Rvalue::Use(Operand::Constant(box Constant { + span: terminator.source_info.span, + user_ty: None, + literal: ty::Const::zero_sized(tcx, tcx.types.unit), + })), + )), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { + if let Some((destination, target)) = *destination { + let lhs; + let rhs; + { + let mut args = args.drain(..); + lhs = args.next().unwrap(); + rhs = args.next().unwrap(); + } + let bin_op = match intrinsic_name { + sym::wrapping_add => BinOp::Add, + sym::wrapping_sub => BinOp::Sub, + sym::wrapping_mul => BinOp::Mul, + _ => bug!("unexpected intrinsic"), + }; + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(box ( + destination, + Rvalue::BinaryOp(bin_op, lhs, rhs), + )), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { + // The checked binary operations are not suitable target for lowering here, + // since their semantics depend on the value of overflow-checks flag used + // during codegen. Issue #35310. + } + sym::size_of => { + if let Some((destination, target)) = *destination { + let tp_ty = substs.type_at(0); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(box ( + destination, + Rvalue::NullaryOp(NullOp::SizeOf, tp_ty), + )), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::discriminant_value => { + if let (Some((destination, target)), Some(arg)) = + (*destination, args[0].place()) + { + let arg = tcx.mk_place_deref(arg); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(box ( + destination, + Rvalue::Discriminant(arg), + )), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + _ => {} + } + } + } + } +} + +fn resolve_rust_intrinsic( + tcx: TyCtxt<'tcx>, + func_ty: Ty<'tcx>, +) -> Option<(Symbol, SubstsRef<'tcx>)> { + if let ty::FnDef(def_id, substs) = *func_ty.kind() { + let fn_sig = func_ty.fn_sig(tcx); + if fn_sig.abi() == Abi::RustIntrinsic { + return Some((tcx.item_name(def_id), substs)); + } + } + None +} diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index 82c0b924f2..53eeecc780 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -43,8 +43,13 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } let param_env = tcx.param_env(body.source.def_id()); + let def_id = body.source.def_id(); let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); 'outer: for bb_idx in bbs.indices() { + if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) { + continue; + } + let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind { TerminatorKind::SwitchInt { discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)), diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index e3fea2d270..7f3b421cf7 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -1,6 +1,7 @@ use crate::{shim, util}; use required_consts::RequiredConstsVisitor; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::steal::Steal; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -8,7 +9,6 @@ use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_span::{Span, Symbol}; use std::borrow::Cow; @@ -21,6 +21,7 @@ pub mod check_consts; pub mod check_packed_ref; pub mod check_unsafety; pub mod cleanup_post_borrowck; +pub mod const_debuginfo; pub mod const_prop; pub mod coverage; pub mod deaggregator; @@ -32,6 +33,7 @@ pub mod function_item_references; pub mod generator; pub mod inline; pub mod instcombine; +pub mod lower_intrinsics; pub mod match_branches; pub mod multiple_return_terminators; pub mod no_landing_pads; @@ -362,6 +364,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, // but before optimizations begin. &add_retag::AddRetag, + &lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops"), // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening // and it can help optimizations. @@ -406,6 +409,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("final"), &nrvo::RenameReturnPlace, + &const_debuginfo::ConstDebugInfo, &simplify::SimplifyLocals, &multiple_return_terminators::MultipleReturnTerminators, ]; diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs index c37b54a319..617086622c 100644 --- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -16,6 +16,7 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { // find basic blocks with no statement and a return terminator let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len()); + let def_id = body.source.def_id(); let bbs = body.basic_blocks_mut(); for idx in bbs.indices() { if bbs[idx].statements.is_empty() @@ -26,6 +27,10 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { } for bb in bbs { + if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {:?} ", def_id)) { + break; + } + if let TerminatorKind::Goto { target } = bb.terminator().kind { if bbs_simple_returns.contains(target) { bb.terminator_mut().kind = TerminatorKind::Return; diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs index 45b906bf54..ce02fb261d 100644 --- a/compiler/rustc_mir/src/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -38,18 +38,22 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { return; } + let def_id = body.source.def_id(); let returned_local = match local_eligible_for_nrvo(body) { Some(l) => l, None => { - debug!("`{:?}` was ineligible for NRVO", body.source.def_id()); + debug!("`{:?}` was ineligible for NRVO", def_id); return; } }; + if !tcx.consider_optimizing(|| format!("RenameReturnPlace {:?}", def_id)) { + return; + } + debug!( "`{:?}` was eligible for NRVO, making {:?} the return place", - body.source.def_id(), - returned_local + def_id, returned_local ); RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body); diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 927aae82a3..8d5ed747c3 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_index::vec::{Idx, IndexVec}; use rustc_target::spec::abi::Abi; @@ -326,41 +326,16 @@ impl<'tcx> Validator<'_, 'tcx> { if place.projection.contains(&ProjectionElem::Deref) { return Err(Unpromotable); } - - let mut has_mut_interior = - self.qualif_local::(place.local); - // HACK(eddyb) this should compute the same thing as - // `::in_projection` from - // `check_consts::qualifs` but without recursion. - if has_mut_interior { - // This allows borrowing fields which don't have - // `HasMutInterior`, from a type that does, e.g.: - // `let _: &'static _ = &(Cell::new(1), 2).1;` - let mut place_projection = &place.projection[..]; - // FIXME(eddyb) use a forward loop instead of a reverse one. - while let &[ref proj_base @ .., elem] = place_projection { - // FIXME(eddyb) this is probably excessive, with - // the exception of `union` member accesses. - let ty = - Place::ty_from(place.local, proj_base, self.body, self.tcx) - .projection_ty(self.tcx, elem) - .ty; - if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) { - has_mut_interior = false; - break; - } - - place_projection = proj_base; - } + if self.qualif_local::(place.local) { + return Err(Unpromotable); } // FIXME(eddyb) this duplicates part of `validate_rvalue`. + let has_mut_interior = + self.qualif_local::(place.local); if has_mut_interior { return Err(Unpromotable); } - if self.qualif_local::(place.local) { - return Err(Unpromotable); - } if let BorrowKind::Mut { .. } = kind { let ty = place.ty(self.body, self.tcx).ty; @@ -692,28 +667,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_place(place)?; - // HACK(eddyb) this should compute the same thing as - // `::in_projection` from - // `check_consts::qualifs` but without recursion. - let mut has_mut_interior = - self.qualif_local::(place.local); - if has_mut_interior { - let mut place_projection = place.projection; - // FIXME(eddyb) use a forward loop instead of a reverse one. - while let &[ref proj_base @ .., elem] = place_projection { - // FIXME(eddyb) this is probably excessive, with - // the exception of `union` member accesses. - let ty = Place::ty_from(place.local, proj_base, self.body, self.tcx) - .projection_ty(self.tcx, elem) - .ty; - if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) { - has_mut_interior = false; - break; - } - - place_projection = proj_base; - } - } + let has_mut_interior = self.qualif_local::(place.local); if has_mut_interior { return Err(Unpromotable); } diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index aaf3ecab4d..221114eeba 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -21,6 +21,12 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { opt_finder.visit_body(body); let should_simplify = !opt_finder.optimizations.is_empty(); for (loc, target) in opt_finder.optimizations { + if !tcx + .consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", body.source.def_id())) + { + break; + } + let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); debug!("SUCCESS: replacing `drop` with goto({:?})", target); terminator.kind = TerminatorKind::Goto { target }; diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index 27bb1def72..a3459887a9 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -246,14 +246,19 @@ fn get_arm_identity_info<'a, 'tcx>( tmp_assigned_vars.insert(*r); } - let dbg_info_to_adjust: Vec<_> = - debug_info - .iter() - .enumerate() - .filter_map(|(i, var_info)| { - if tmp_assigned_vars.contains(var_info.place.local) { Some(i) } else { None } - }) - .collect(); + let dbg_info_to_adjust: Vec<_> = debug_info + .iter() + .enumerate() + .filter_map(|(i, var_info)| { + if let VarDebugInfoContents::Place(p) = var_info.value { + if tmp_assigned_vars.contains(p.local) { + return Some(i); + } + } + + None + }) + .collect(); Some(ArmIdentityInfo { local_temp_0: local_tmp_s0, @@ -301,7 +306,7 @@ fn optimization_applies<'tcx>( return false; } - // Verify the assigment chain consists of the form b = a; c = b; d = c; etc... + // Verify the assignment chain consists of the form b = a; c = b; d = c; etc... if opt_info.field_tmp_assignments.is_empty() { trace!("NO: no assignments found"); return false; @@ -340,9 +345,11 @@ fn optimization_applies<'tcx>( // Check that debug info only points to full Locals and not projections. for dbg_idx in &opt_info.dbg_info_to_adjust { let dbg_info = &var_debug_info[*dbg_idx]; - if !dbg_info.place.projection.is_empty() { - trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, dbg_info.place); - return false; + if let VarDebugInfoContents::Place(p) = dbg_info.value { + if !p.projection.is_empty() { + trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p); + return false; + } } } @@ -423,9 +430,15 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { // Fix the debug info to point to the right local for dbg_index in opt_info.dbg_info_to_adjust { let dbg_info = &mut debug_info[dbg_index]; - assert!(dbg_info.place.projection.is_empty()); - dbg_info.place.local = opt_info.local_0; - dbg_info.place.projection = opt_info.dbg_projection; + assert!( + matches!(dbg_info.value, VarDebugInfoContents::Place(_)), + "value was not a Place" + ); + if let VarDebugInfoContents::Place(p) = &mut dbg_info.value { + assert!(p.projection.is_empty()); + p.local = opt_info.local_0; + p.projection = opt_info.dbg_projection; + } } trace!("block is now {:?}", bb.statements); diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index f6d39dae34..e39c865602 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -50,6 +50,12 @@ impl MirPass<'_> for UnreachablePropagation { let replaced = !replacements.is_empty(); for (bb, terminator_kind) in replacements { + if !tcx.consider_optimizing(|| { + format!("UnreachablePropagation {:?} ", body.source.def_id()) + }) { + break; + } + body.basic_blocks_mut()[bb].terminator_mut().kind = terminator_kind; } diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index e1e6e71acb..29b90bff21 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::traversal; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef, - Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, + Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable}; @@ -183,6 +183,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if self.body.local_decls.get(*local).is_none() { + self.fail( + location, + format!("local {:?} has no corresponding declaration in `body.local_decls`", local), + ); + } + if self.reachable_blocks.contains(location.block) && context.is_use() { // Uses of locals must occur while the local's storage is allocated. self.storage_liveness.seek_after_primary_effect(location); @@ -193,12 +200,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) { - // Debuginfo can contain field projections, which count as a use of the base local. Skip - // debuginfo so that we avoid the storage liveness assertion in that case. - self.visit_source_info(&var_debug_info.source_info); - } - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. if self.tcx.sess.opts.debugging_opts.validate_mir { diff --git a/compiler/rustc_mir/src/util/borrowck_errors.rs b/compiler/rustc_mir/src/util/borrowck_errors.rs index 83bf7584f2..56d8045813 100644 --- a/compiler/rustc_mir/src/util/borrowck_errors.rs +++ b/compiler/rustc_mir/src/util/borrowck_errors.rs @@ -68,9 +68,10 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { err.span_label( new_loan_span, format!( - "mutable borrow starts here in previous \ - iteration of loop{}", - opt_via + "{}{} was mutably borrowed here in the previous iteration of the loop{}", + desc, + via(opt_via), + opt_via, ), ); if let Some(old_load_end_span) = old_load_end_span { diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_mir/src/util/generic_graph.rs new file mode 100644 index 0000000000..6ce305a482 --- /dev/null +++ b/compiler/rustc_mir/src/util/generic_graph.rs @@ -0,0 +1,70 @@ +use gsgdt::{Edge, Graph, Node, NodeStyle}; +use rustc_hir::def_id::DefId; +use rustc_index::vec::Idx; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +/// Convert an MIR function into a gsgdt Graph +pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph { + let def_id = body.source.def_id(); + let def_name = graphviz_safe_def_name(def_id); + let graph_name = format!("Mir_{}", def_name); + let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + + // Nodes + let nodes: Vec = body + .basic_blocks() + .iter_enumerated() + .map(|(block, _)| bb_to_graph_node(block, body, dark_mode)) + .collect(); + + // Edges + let mut edges = Vec::new(); + for (source, _) in body.basic_blocks().iter_enumerated() { + let def_id = body.source.def_id(); + let terminator = body[source].terminator(); + let labels = terminator.kind.fmt_successor_labels(); + + for (&target, label) in terminator.successors().zip(labels) { + let src = node(def_id, source); + let trg = node(def_id, target); + edges.push(Edge::new(src, trg, label.to_string())); + } + } + + Graph::new(graph_name, nodes, edges) +} + +fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node { + let def_id = body.source.def_id(); + let data = &body[block]; + let label = node(def_id, block); + + let (title, bgcolor) = if data.is_cleanup { + let color = if dark_mode { "royalblue" } else { "lightblue" }; + (format!("{} (cleanup)", block.index()), color) + } else { + let color = if dark_mode { "dimgray" } else { "gray" }; + (format!("{}", block.index()), color) + }; + + let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() }; + let mut stmts: Vec = data.statements.iter().map(|x| format!("{:?}", x)).collect(); + + // add the terminator to the stmts, gsgdt can print it out seperately + let mut terminator_head = String::new(); + data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); + stmts.push(terminator_head); + + Node::new(stmts, label, title, style) +} + +// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so +// it does not have to be user friendly. +pub fn graphviz_safe_def_name(def_id: DefId) -> String { + format!("{}_{}", def_id.krate.index(), def_id.index.index(),) +} + +fn node(def_id: DefId, block: BasicBlock) -> String { + format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id)) +} diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs index 8bd4a512bb..fd55a4dfc4 100644 --- a/compiler/rustc_mir/src/util/generic_graphviz.rs +++ b/compiler/rustc_mir/src/util/generic_graphviz.rs @@ -116,9 +116,13 @@ impl< write!(w, r#""#)?; - // FIXME(richkadel): Need generic way to know if node header should have a different color + // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation, + // we need generic way to know if node header should have a different color. For example, + // for MIR: + // // let (blk, bgcolor) = if data.is_cleanup { - // (format!("{:?} (cleanup)", node), "lightblue") + // let color = if dark_mode { "royalblue" } else { "lightblue" }; + // (format!("{:?} (cleanup)", node), color) // } else { // let color = if dark_mode { "dimgray" } else { "gray" }; // (format!("{:?}", node), color) diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs index 625f1a3e68..37498e50c0 100644 --- a/compiler/rustc_mir/src/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -1,11 +1,12 @@ +use gsgdt::GraphvizSettings; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; -use rustc_index::vec::Idx; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use std::fmt::Debug; use std::io::{self, Write}; +use super::generic_graph::mir_fn_to_generic_graph; use super::pretty::dump_mir_def_ids; /// Write a graphviz DOT graph of a list of MIRs. @@ -32,12 +33,6 @@ where Ok(()) } -// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so -// it does not have to be user friendly. -pub fn graphviz_safe_def_name(def_id: DefId) -> String { - format!("{}_{}", def_id.krate.index(), def_id.index.index(),) -} - /// Write a graphviz DOT graph of the MIR. pub fn write_mir_fn_graphviz<'tcx, W>( tcx: TyCtxt<'tcx>, @@ -48,12 +43,6 @@ pub fn write_mir_fn_graphviz<'tcx, W>( where W: Write, { - let def_id = body.source.def_id(); - let kind = if subgraph { "subgraph" } else { "digraph" }; - let cluster = if subgraph { "cluster_" } else { "" }; // Prints a border around MIR - let def_name = graphviz_safe_def_name(def_id); - writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?; - // Global graph properties let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); let mut graph_attrs = vec![&font[..]]; @@ -67,131 +56,31 @@ where content_attrs.push(r#"fontcolor="white""#); } - writeln!(w, r#" graph [{}];"#, graph_attrs.join(" "))?; - let content_attrs_str = content_attrs.join(" "); - writeln!(w, r#" node [{}];"#, content_attrs_str)?; - writeln!(w, r#" edge [{}];"#, content_attrs_str)?; - // Graph label - write_graph_label(tcx, body, w)?; - - // Nodes - for (block, _) in body.basic_blocks().iter_enumerated() { - write_node(block, body, dark_mode, w)?; - } - - // Edges - for (source, _) in body.basic_blocks().iter_enumerated() { - write_edges(source, body, w)?; - } - writeln!(w, "}}") -} - -/// Write a graphviz HTML-styled label for the given basic block, with -/// all necessary escaping already performed. (This is suitable for -/// emitting directly, as is done in this module, or for use with the -/// LabelText::HtmlStr from librustc_graphviz.) -/// -/// `init` and `fini` are callbacks for emitting additional rows of -/// data (using HTML enclosed with `` in the emitted text). -pub fn write_node_label( - block: BasicBlock, - body: &Body<'_>, - dark_mode: bool, - w: &mut W, - num_cols: u32, - init: INIT, - fini: FINI, -) -> io::Result<()> -where - INIT: Fn(&mut W) -> io::Result<()>, - FINI: Fn(&mut W) -> io::Result<()>, -{ - let data = &body[block]; - - write!(w, r#"
"#)?; - - // Basic block number at the top. - let (blk, bgcolor) = if data.is_cleanup { - let color = if dark_mode { "royalblue" } else { "lightblue" }; - (format!("{} (cleanup)", block.index()), color) - } else { - let color = if dark_mode { "dimgray" } else { "gray" }; - (format!("{}", block.index()), color) + let mut label = String::from(""); + // FIXME: remove this unwrap + write_graph_label(tcx, body, &mut label).unwrap(); + let g = mir_fn_to_generic_graph(tcx, body); + let settings = GraphvizSettings { + graph_attrs: Some(graph_attrs.join(" ")), + node_attrs: Some(content_attrs.join(" ")), + edge_attrs: Some(content_attrs.join(" ")), + graph_label: Some(label), }; - write!( - w, - r#""#, - attrs = r#"align="center""#, - colspan = num_cols, - blk = blk, - bgcolor = bgcolor - )?; - - init(w)?; - - // List of statements in the middle. - if !data.statements.is_empty() { - write!(w, r#"")?; - } - - // Terminator head at the bottom, not including the list of successor blocks. Those will be - // displayed as labels on the edges between blocks. - let mut terminator_head = String::new(); - data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); - write!(w, r#""#, dot::escape_html(&terminator_head))?; - - fini(w)?; - - // Close the table - write!(w, "
{blk}
"#)?; - for statement in &data.statements { - write!(w, "{}
", escape(statement))?; - } - write!(w, "
{}
") -} - -/// Write a graphviz DOT node for the given basic block. -fn write_node( - block: BasicBlock, - body: &Body<'_>, - dark_mode: bool, - w: &mut W, -) -> io::Result<()> { - let def_id = body.source.def_id(); - // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. - write!(w, r#" {} [shape="none", label=<"#, node(def_id, block))?; - write_node_label(block, body, dark_mode, w, 1, |_| Ok(()), |_| Ok(()))?; - // Close the node label and the node itself. - writeln!(w, ">];") -} - -/// Write graphviz DOT edges with labels between the given basic block and all of its successors. -fn write_edges(source: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> { - let def_id = body.source.def_id(); - let terminator = body[source].terminator(); - let labels = terminator.kind.fmt_successor_labels(); - - for (&target, label) in terminator.successors().zip(labels) { - let src = node(def_id, source); - let trg = node(def_id, target); - writeln!(w, r#" {} -> {} [label="{}"];"#, src, trg, label)?; - } - - Ok(()) + g.to_dot(w, &settings, subgraph) } /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that /// will appear below the graph, showing the type of the `fn` this MIR represents and the types of /// all the variables and temporaries. -fn write_graph_label<'tcx, W: Write>( +fn write_graph_label<'tcx, W: std::fmt::Write>( tcx: TyCtxt<'tcx>, body: &Body<'_>, w: &mut W, -) -> io::Result<()> { +) -> std::fmt::Result { let def_id = body.source.def_id(); - write!(w, " label=( w, r#"debug {} => {};
"#, var_debug_info.name, - escape(&var_debug_info.place) + escape(&var_debug_info.value), )?; } - writeln!(w, ">;") -} - -fn node(def_id: DefId, block: BasicBlock) -> String { - format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id)) + Ok(()) } fn escape(t: &T) -> String { diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs index aaee0bc526..b7b702431b 100644 --- a/compiler/rustc_mir/src/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -7,6 +7,7 @@ pub mod storage; mod alignment; pub mod collect_writes; mod find_self_call; +mod generic_graph; pub(crate) mod generic_graphviz; mod graphviz; pub(crate) mod pretty; @@ -15,6 +16,6 @@ pub(crate) mod spanview; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; pub use self::find_self_call::find_self_call; -pub use self::graphviz::write_node_label as write_graphviz_node_label; -pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz}; +pub use self::generic_graph::graphviz_safe_def_name; +pub use self::graphviz::write_mir_graphviz; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 8bee8417c5..89ce29bd10 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::interpret::{ }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; use std::ops::ControlFlow; @@ -408,6 +408,18 @@ impl ExtraComments<'tcx> { } } +fn use_verbose(ty: &&TyS<'tcx>) -> bool { + match ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, + // Unit type + ty::Tuple(g_args) if g_args.is_empty() => false, + ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty())), + ty::Array(ty, _) => use_verbose(ty), + ty::FnDef(..) => false, + _ => true, + } +} + impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); @@ -430,16 +442,10 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); let ty::Const { ty, val, .. } = constant; - match ty.kind() { - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {} - // Unit type - ty::Tuple(tys) if tys.is_empty() => {} - ty::FnDef(..) => {} - _ => { - self.push("ty::Const"); - self.push(&format!("+ ty: {:?}", ty)); - self.push(&format!("+ val: {:?}", val)); - } + if use_verbose(ty) { + self.push("ty::Const"); + self.push(&format!("+ ty: {:?}", ty)); + self.push(&format!("+ val: {:?}", val)); } } @@ -495,7 +501,7 @@ fn write_scope_tree( let indented_debug_info = format!( "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.place, + INDENT, indent, var_debug_info.name, var_debug_info.value, ); writeln!( @@ -640,7 +646,7 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet); impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Value(val) = c.val { self.0.extend(alloc_ids_from_const(val)); } diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index cf075abc94..60f8d8c8a9 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -19,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let local_scope = self.local_scope(); - self.as_operand(block, local_scope, expr) + self.as_operand(block, Some(local_scope), expr) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -79,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let local_scope = self.local_scope(); - self.as_call_operand(block, local_scope, expr) + self.as_call_operand(block, Some(local_scope), expr) } /// Compile `expr` into a value that can be used as an operand. diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index b94346fa43..e1a3dc87c8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -4,14 +4,62 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::thir::*; +use rustc_hir::def_id::DefId; +use rustc_hir::HirId; use rustc_middle::middle::region; +use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; use rustc_span::Span; +use rustc_target::abi::VariantIdx; use rustc_index::vec::Idx; +/// The "outermost" place that holds this value. +#[derive(Copy, Clone)] +crate enum PlaceBase { + /// Denotes the start of a `Place`. + Local(Local), + + /// When building place for an expression within a closure, the place might start off a + /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture + /// index (within the desugared closure) of the captured path until most of the projections + /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the + /// captured path starts, the closure the capture belongs to and the trait the closure + /// implements. + /// + /// Once we have figured out the capture index, we can convert the place builder to start from + /// `PlaceBase::Local`. + /// + /// Consider the following example + /// ```rust + /// let t = (10, (10, (10, 10))); + /// + /// let c = || { + /// println!("{}", t.0.0.0); + /// }; + /// ``` + /// Here the THIR expression for `t.0.0.0` will be something like + /// + /// ``` + /// * Field(0) + /// * Field(0) + /// * Field(0) + /// * UpvarRef(t) + /// ``` + /// + /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to + /// figure out that it is captured until all the `Field` projections are applied. + Upvar { + /// HirId of the upvar + var_hir_id: HirId, + /// DefId of the closure + closure_def_id: DefId, + /// The trait closure implements, `Fn`, `FnMut`, `FnOnce` + closure_kind: ty::ClosureKind }, +} + /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a /// place by pushing more and more projections onto the end, and then convert the final set into a /// place using the `into_place` method. @@ -19,14 +67,240 @@ use rustc_index::vec::Idx; /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone)] -struct PlaceBuilder<'tcx> { - local: Local, +crate struct PlaceBuilder<'tcx> { + base: PlaceBase, projection: Vec>, } +/// Given a list of MIR projections, convert them to list of HIR ProjectionKind. +/// The projections are truncated to represent a path that might be captured by a +/// closure/generator. This implies the vector returned from this function doesn't contain +/// ProjectionElems `Downcast`, `ConstantIndex`, `Index`, or `Subslice` because those will never be +/// part of a path that is captued by a closure. We stop applying projections once we see the first +/// projection that isn't captured by a closure. +fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( + mir_projections: &Vec>, +) -> Vec { + + let mut hir_projections = Vec::new(); + + for mir_projection in mir_projections { + let hir_projection = match mir_projection { + ProjectionElem::Deref => HirProjectionKind::Deref, + ProjectionElem::Field(field, _) => { + // We will never encouter this for multivariant enums, + // read the comment for `Downcast`. + HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0)) + }, + ProjectionElem::Downcast(..) => { + // This projections exist only for enums that have + // multiple variants. Since such enums that are captured + // completely, we can stop here. + break + }, + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { + // We don't capture array-access projections. + // We can stop here as arrays are captured completely. + break + }, + }; + + hir_projections.push(hir_projection); + } + + hir_projections +} + +/// Return true if the `proj_possible_ancestor` represents an ancestor path +/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`, +/// assuming they both start off of the same root variable. +/// +/// **Note:** It's the caller's responsibility to ensure that both lists of projections +/// start off of the same root variable. +/// +/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of +/// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`. +/// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`. +/// 2. Since we only look at the projections here function will return `bar.x` as an a valid +/// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections +/// list are being applied to the same root variable. +fn is_ancestor_or_same_capture( + proj_possible_ancestor: &Vec, + proj_capture: &Vec, +) -> bool { + // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false. + // Therefore we can't just check if all projections are same in the zipped iterator below. + if proj_possible_ancestor.len() > proj_capture.len() { + return false; + } + + proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b) +} + +/// Computes the index of a capture within the desugared closure provided the closure's +/// `closure_min_captures` and the capture's index of the capture in the +/// `ty::MinCaptureList` of the root variable `var_hir_id`. +fn compute_capture_idx<'tcx>( + closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>, + var_hir_id: HirId, + root_var_idx: usize, +) -> usize { + let mut res = 0; + for (var_id, capture_list) in closure_min_captures { + if *var_id == var_hir_id { + res += root_var_idx; + break; + } else { + res += capture_list.len(); + } + } + + res +} + +/// Given a closure, returns the index of a capture within the desugared closure struct and the +/// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id` +/// and `projection`. +/// +/// Note there will be at most one ancestor for any given Place. +/// +/// Returns None, when the ancestor is not found. +fn find_capture_matching_projections<'a, 'tcx>( + typeck_results: &'a ty::TypeckResults<'tcx>, + var_hir_id: HirId, + closure_def_id: DefId, + projections: &Vec>, +) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> { + let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?; + let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?; + + let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections); + + // If an ancestor is found, `idx` is the index within the list of captured places + // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself. + let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| { + let possible_ancestor_proj_kinds = + capture.place.projections.iter().map(|proj| proj.kind).collect(); + is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections) + })?; + + // Convert index to be from the presepective of the entire closure_min_captures map + // instead of just the root variable capture list + Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture)) +} + +/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the +/// `PlaceBuilder` now starts from `PlaceBase::Local`. +/// +/// Returns a Result with the error being the HirId of the Upvar that was not found. +fn to_upvars_resolved_place_builder<'a, 'tcx>( + from_builder: PlaceBuilder<'tcx>, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, +) -> Result, HirId> { + match from_builder.base { + PlaceBase::Local(_) => Ok(from_builder), + PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => { + // Captures are represented using fields inside a structure. + // This represents accessing self in the closure structure + let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1)); + match closure_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { + upvar_resolved_place_builder = upvar_resolved_place_builder.deref(); + } + ty::ClosureKind::FnOnce => {} + } + + let (capture_index, capture) = + if let Some(capture_details) = find_capture_matching_projections( + typeck_results, + var_hir_id, + closure_def_id, + &from_builder.projection, + ) { + capture_details + } else { + if !tcx.features().capture_disjoint_fields { + bug!( + "No associated capture found for {:?}[{:#?}] even though \ + capture_disjoint_fields isn't enabled", + var_hir_id, + from_builder.projection + ) + } else { + // FIXME(project-rfc-2229#24): Handle this case properly + debug!( + "No associated capture found for {:?}[{:#?}]", + var_hir_id, + from_builder.projection, + ); + } + return Err(var_hir_id); + }; + + let closure_ty = + typeck_results.node_type(tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local())); + + let substs = match closure_ty.kind() { + ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), + ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), + _ => bug!("Lowering capture for non-closure type {:?}", closure_ty), + }; + + // Access the capture by accessing the field within the Closure struct. + // + // We must have inferred the capture types since we are building MIR, therefore + // it's safe to call `tuple_element_ty` and we can unwrap here because + // we know that the capture exists and is the `capture_index`-th capture. + let var_ty = substs.tupled_upvars_ty().tuple_element_ty(capture_index).unwrap(); + + upvar_resolved_place_builder = upvar_resolved_place_builder.field(Field::new(capture_index), var_ty); + + // If the variable is captured via ByRef(Immutable/Mutable) Borrow, + // we need to deref it + upvar_resolved_place_builder = match capture.info.capture_kind { + ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(), + ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder, + }; + + let next_projection = capture.place.projections.len(); + let mut curr_projections = from_builder.projection; + + // We used some of the projections to build the capture itself, + // now we apply the remaining to the upvar resolved place. + upvar_resolved_place_builder.projection.extend( + curr_projections.drain(next_projection..)); + + Ok(upvar_resolved_place_builder) + } + } +} + impl<'tcx> PlaceBuilder<'tcx> { - fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> { - Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) } + crate fn into_place<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> Place<'tcx> { + if let PlaceBase::Local(local) = self.base { + Place { local, projection: tcx.intern_place_elems(&self.projection) } + } else { + self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) + } + } + + fn expect_upvars_resolved<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> PlaceBuilder<'tcx> { + to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() + } + + crate fn base(&self) -> PlaceBase { + self.base } fn field(self, f: Field, ty: Ty<'tcx>) -> Self { @@ -49,7 +323,13 @@ impl<'tcx> PlaceBuilder<'tcx> { impl<'tcx> From for PlaceBuilder<'tcx> { fn from(local: Local) -> Self { - Self { local, projection: Vec::new() } + Self { base: PlaceBase::Local(local), projection: Vec::new() } + } +} + +impl<'tcx> From for PlaceBuilder<'tcx> { + fn from(base: PlaceBase) -> Self { + Self { base, projection: Vec::new() } } } @@ -71,12 +351,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self.hir.tcx())) + block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) } /// This is used when constructing a compound `Place`, so that we can avoid creating /// intermediate `Place` values until we know the full set of projections. - fn as_place_builder(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + crate fn as_place_builder(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>>, { @@ -98,7 +378,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self.hir.tcx())) + block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -160,7 +440,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span, source_info, ), - ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))), + ExprKind::UpvarRef { closure_def_id, var_hir_id } => { + let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local()); + this.lower_captured_upvar(block, upvar_id) + } + ExprKind::VarRef { id } => { let place_builder = if this.is_bound_var_in_guard(id) { let index = this.var_local_id(id, RefWithinGuard); @@ -185,7 +469,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this.hir.tcx()); + let place = + place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results()); this.cfg.push( block, Statement { @@ -270,6 +555,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + /// Lower a captured upvar. Note we might not know the actual capture index, + /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved + /// once all projections that allow us to indentify a capture have been applied. + fn lower_captured_upvar( + &mut self, + block: BasicBlock, + upvar_id: ty::UpvarId, + ) -> BlockAnd> { + let closure_ty = self + .hir + .typeck_results() + .node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id)); + + let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() { + self.hir.infcx().closure_kind(closure_substs).unwrap() + } else { + // Generators are considered FnOnce. + ty::ClosureKind::FnOnce + }; + + block.and(PlaceBuilder::from(PlaceBase::Upvar { + var_hir_id: upvar_id.var_path.hir_id, + closure_def_id: upvar_id.closure_expr_id.to_def_id(), + closure_kind, + })) + } + /// Lower an index expression /// /// This has two complications; @@ -295,7 +607,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let is_outermost_index = fake_borrow_temps.is_none(); let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps); - let base_place = + let mut base_place = unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),)); // Making this a *fresh* temporary means we do not have to worry about @@ -305,7 +617,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = self.bounds_check( block, - base_place.clone().into_place(self.hir.tcx()), + base_place.clone().into_place(self.hir.tcx(), self.hir.typeck_results()), idx, expr_span, source_info, @@ -314,6 +626,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { + base_place = base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results()); self.add_fake_borrows_of_base( &base_place, block, @@ -363,8 +676,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo, ) { let tcx = self.hir.tcx(); - let place_ty = - Place::ty_from(base_place.local, &base_place.projection, &self.local_decls, tcx); + let local = match base_place.base { + PlaceBase::Local(local) => local, + PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar") + }; + + let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx); if let ty::Slice(_) = place_ty.ty.kind() { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to @@ -374,7 +691,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match elem { ProjectionElem::Deref => { let fake_borrow_deref_ty = Place::ty_from( - base_place.local, + local, &base_place.projection[..idx], &self.local_decls, tcx, @@ -392,14 +709,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Shallow, - Place { local: base_place.local, projection }, + Place { local, projection }, ), ); fake_borrow_temps.push(fake_borrow_temp); } ProjectionElem::Index(_) => { let index_ty = Place::ty_from( - base_place.local, + local, &base_place.projection[..idx], &self.local_decls, tcx, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 2853bf887f..581d842142 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -4,6 +4,7 @@ use rustc_index::vec::Idx; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use crate::build::expr::as_place::PlaceBase; use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; @@ -23,7 +24,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let local_scope = self.local_scope(); - self.as_rvalue(block, local_scope, expr) + self.as_rvalue(block, Some(local_scope), expr) } /// Compile `expr`, yielding an rvalue. @@ -96,7 +97,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Box { value } => { let value = this.hir.mirror(value); // The `Box` temporary created here is not a part of the HIR, - // and therefore is not considered during generator OIBIT + // and therefore is not considered during generator auto-trait // determination. See the comment about `box` at `yield_in_scope`. let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span).internal()); this.cfg.push( @@ -250,7 +251,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Deref { .. } | ExprKind::Index { .. } | ExprKind::VarRef { .. } - | ExprKind::SelfRef + | ExprKind::UpvarRef { .. } | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } @@ -381,44 +382,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); - let arg_place = unpack!(block = this.as_place(block, arg)); - - let mutability = match arg_place.as_ref() { - PlaceRef { local, projection: &[] } => this.local_decls[local].mutability, - PlaceRef { local, projection: &[ProjectionElem::Deref] } => { - debug_assert!( - this.local_decls[local].is_ref_for_guard(), - "Unexpected capture place", - ); - this.local_decls[local].mutability - } - PlaceRef { - local, - projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], - } - | PlaceRef { - local, - projection: - &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref], - } => { - let place = PlaceRef { local, projection: proj_base }; - - // Not projected from the implicit `self` in a closure. - debug_assert!( - match place.local_or_deref_local() { - Some(local) => local == Local::new(1), - None => false, - }, - "Unexpected capture place" - ); - // Not in a closure - debug_assert!( - this.upvar_mutbls.len() > upvar_index.index(), - "Unexpected capture place" - ); - this.upvar_mutbls[upvar_index.index()] + let arg_place_builder = unpack!(block = this.as_place_builder(block, arg)); + + let mutability = match arg_place_builder.base() { + // We are capturing a path that starts off a local variable in the parent. + // The mutability of the current capture is same as the mutability + // of the local declaration in the parent. + PlaceBase::Local(local) => this.local_decls[local].mutability, + // Parent is a closure and we are capturing a path that is captured + // by the parent itself. The mutability of the current capture + // is same as that of the capture in the parent closure. + PlaceBase::Upvar { .. } => { + let enclosing_upvars_resolved = arg_place_builder.clone().into_place( + this.hir.tcx(), + this.hir.typeck_results()); + + match enclosing_upvars_resolved.as_ref() { + PlaceRef { local, projection: &[ProjectionElem::Field(upvar_index, _), ..] } + | PlaceRef { + local, + projection: &[ProjectionElem::Deref, ProjectionElem::Field(upvar_index, _), ..] } => { + // Not in a closure + debug_assert!( + local == Local::new(1), + "Expected local to be Local(1), found {:?}", + local + ); + // Not in a closure + debug_assert!( + this.upvar_mutbls.len() > upvar_index.index(), + "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}", + this.upvar_mutbls, upvar_index + ); + this.upvar_mutbls[upvar_index.index()] + } + _ => bug!("Unexpected capture place"), + } } - _ => bug!("Unexpected capture place"), }; let borrow_kind = match mutability { @@ -426,6 +426,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; + let arg_place = arg_place_builder.into_place( + this.hir.tcx(), + this.hir.typeck_results()); + this.cfg.push_assign( block, source_info, @@ -433,9 +437,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place), ); - // In constants, temp_lifetime is None. We should not need to drop - // anything because no values with a destructor can be created in - // a constant at this time, even if the type may need dropping. + // See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why + // this can be `None`. if let Some(temp_lifetime) = temp_lifetime { this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp); } diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index ac5cf187aa..8561170856 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -38,7 +38,7 @@ impl Category { ExprKind::Field { .. } | ExprKind::Deref { .. } | ExprKind::Index { .. } - | ExprKind::SelfRef + | ExprKind::UpvarRef { .. } | ExprKind::VarRef { .. } | ExprKind::PlaceTypeAscription { .. } | ExprKind::ValueTypeAscription { .. } => Some(Category::Place), diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 9dc596a345..a86e4cb99c 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -10,7 +10,6 @@ use rustc_hir as hir; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use rustc_span::symbol::sym; - use rustc_target::spec::abi::Abi; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -62,7 +61,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (#66975) Source could be a const of type `!`, so has to // exist in the generated MIR. - unpack!(block = this.as_temp(block, this.local_scope(), source, Mutability::Mut,)); + unpack!(block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,)); // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. @@ -192,7 +191,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .local_decls .push(LocalDecl::with_source_info(ptr_ty, source_info).internal()); let ptr_temp = Place::from(ptr_temp); + // No need for a scope, ptr_temp doesn't need drop let block = unpack!(this.into(ptr_temp, block, ptr)); + // Maybe we should provide a scope here so that + // `move_val_init` wouldn't leak on panic even with an + // arbitrary `val` expression, but `schedule_drop`, + // borrowck and drop elaboration all prevent us from + // dropping `ptr_temp.deref()`. this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val) } else { let args: Vec<_> = args @@ -266,12 +271,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (evaluating them in order given by user) let fields_map: FxHashMap<_, _> = fields .into_iter() - .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr)))) + .map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr)))) .collect(); let field_names = this.hir.all_fields(adt_def, variant_index); - let fields = if let Some(FruInfo { base, field_types }) = base { + let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { let base = unpack!(block = this.as_place(block, base)); // MIR does not natively support FRU, so for each @@ -400,7 +405,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Avoid creating a temporary ExprKind::VarRef { .. } - | ExprKind::SelfRef + | ExprKind::UpvarRef { .. } | ExprKind::PlaceTypeAscription { .. } | ExprKind::ValueTypeAscription { .. } => { debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); @@ -430,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Yield { value } => { let scope = this.local_scope(); - let value = unpack!(block = this.as_operand(block, scope, value)); + let value = unpack!(block = this.as_operand(block, Some(scope), value)); let resume = this.cfg.start_new_block(); this.cfg.terminate( block, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3ee15248ae..c5f9412bf0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -251,6 +251,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm.guard.as_ref(), &fake_borrow_temps, scrutinee_span, + Some(arm.span), Some(arm.scope), ); @@ -288,6 +289,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard: Option<&Guard<'tcx>>, fake_borrow_temps: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, + arm_span: Option, arm_scope: Option, ) -> BasicBlock { if candidate.subcandidates.is_empty() { @@ -299,6 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, fake_borrow_temps, scrutinee_span, + arm_span, true, ) } else { @@ -334,6 +337,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, &fake_borrow_temps, scrutinee_span, + arm_span, schedule_drops, ); if arm_scope.is_none() { @@ -495,6 +499,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &fake_borrow_temps, irrefutable_pat.span, None, + None, ) .unit() } @@ -876,11 +881,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// For an example of a case where we set `otherwise_block`, even for an /// exhaustive match consider: /// + /// ```rust /// match x { /// (true, true) => (), /// (_, false) => (), /// (false, true) => (), /// } + /// ``` /// /// For this match, we check if `x.0` matches `true` (for the first /// arm). If that's false, we check `x.1`. If it's `true` we check if @@ -994,11 +1001,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Link up matched candidates. For example, if we have something like /// this: /// + /// ```rust /// ... /// Some(x) if cond => ... /// Some(x) => ... /// Some(x) if cond => ... /// ... + /// ``` /// /// We generate real edges from: /// * `start_block` to the `prebinding_block` of the first pattern, @@ -1394,12 +1403,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match test.kind { TestKind::SwitchInt { switch_ty, ref mut options } => { for candidate in candidates.iter() { - if !self.add_cases_to_switch( - &match_place, - candidate, - switch_ty, - options, - ) { + if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) { break; } } @@ -1581,7 +1585,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Initializes each of the bindings from the candidate by /// moving/copying/ref'ing the source as appropriate. Tests the guard, if /// any, and then branches to the arm. Returns the block for the case where - /// the guard fails. + /// the guard succeeds. /// /// Note: we do not check earlier that if there is a guard, /// there cannot be move bindings. We avoid a use-after-move by only @@ -1593,6 +1597,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard: Option<&Guard<'tcx>>, fake_borrows: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, + arm_span: Option, schedule_drops: bool, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -1723,15 +1728,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow); } - // the block to branch to if the guard fails; if there is no - // guard, this block is simply unreachable - let guard = match guard { - Guard::If(e) => self.hir.mirror(e.clone()), + let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard { + Guard::If(e) => { + let e = self.hir.mirror(e.clone()); + let source_info = self.source_info(e.span); + (e.span, self.test_bool(block, e, source_info)) + }, + Guard::IfLet(pat, scrutinee) => { + let scrutinee_span = scrutinee.span(); + let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)); + let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false); + let wildcard = Pat::wildcard_from_ty(pat.ty); + let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false); + let fake_borrow_temps = + self.lower_match_tree(block, pat.span, false, &mut [&mut guard_candidate, &mut otherwise_candidate]); + self.declare_bindings( + None, + pat.span.to(arm_span.unwrap()), + pat, + ArmHasGuard(false), + Some((Some(&scrutinee_place), scrutinee.span())), + ); + let post_guard_block = self.bind_pattern( + self.source_info(pat.span), + guard_candidate, + None, + &fake_borrow_temps, + scrutinee.span(), + None, + None, + ); + let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); + (scrutinee_span, (post_guard_block, otherwise_post_guard_block)) + } }; - let source_info = self.source_info(guard.span); - let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span)); - let (post_guard_block, otherwise_post_guard_block) = - self.test_bool(block, guard, source_info); + let source_info = self.source_info(guard_span); + let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span)); let guard_frame = self.guard_context.pop().unwrap(); debug!("Exiting guard building context with locals: {:?}", guard_frame); @@ -1780,14 +1812,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = - parent_bindings - .iter() - .flat_map(|(bindings, _)| bindings) - .chain(&candidate.bindings) - .filter(|binding| { - matches!(binding.binding_mode, BindingMode::ByValue ) - }); + let by_value_bindings = parent_bindings + .iter() + .flat_map(|(bindings, _)| bindings) + .chain(&candidate.bindings) + .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { @@ -1992,7 +2021,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, - place: for_arm_body.into(), + value: VarDebugInfoContents::Place(for_arm_body.into()), }); let locals = if has_guard.0 { let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { @@ -2011,7 +2040,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, - place: ref_for_guard.into(), + value: VarDebugInfoContents::Place(ref_for_guard.into()), }); LocalsForNode::ForGuard { ref_for_guard, for_arm_body } } else { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 7bea8220ad..07173f41cd 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -671,6 +671,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (&TestKind::Range { .. }, _) => None, (&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => { + // The call to `self.test(&match_pair)` below is not actually used to generate any + // MIR. Instead, we just want to compare with `test` (the parameter of the method) + // to see if it is the same. + // + // However, at this point we can still encounter or-patterns that were extracted + // from previous calls to `sort_candidate`, so we need to manually address that + // case to avoid panicking in `self.test()`. + if let PatKind::Or { .. } = &*match_pair.pattern.kind { + return None; + } + // These are all binary tests. // // FIXME(#29623) we can be more clever here diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index f9995f43f5..a207997f57 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; @@ -24,7 +25,7 @@ use super::lints; crate fn mir_built<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, -) -> &'tcx ty::steal::Steal> { +) -> &'tcx rustc_data_structures::steal::Steal> { if let Some(def) = def.try_upgrade(tcx) { return tcx.mir_built(def); } @@ -75,7 +76,9 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ kind: hir::TraitItemKind::Const(ty, Some(body_id)), .. }) => (*body_id, ty.span, None), - Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id), None), + Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => { + (*body, tcx.hir().span(*hir_id), None) + } _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did), }; @@ -183,7 +186,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ return_ty, return_ty_span, body, - span_with_body + span_with_body, ); mir.yield_ty = yield_ty; mir @@ -240,7 +243,7 @@ fn liberated_closure_env_ty( }; let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap(); - tcx.erase_late_bound_regions(&closure_env_ty) + tcx.erase_late_bound_regions(closure_env_ty) } #[derive(Debug, PartialEq, Eq)] @@ -581,7 +584,7 @@ fn construct_fn<'a, 'tcx, A>( return_ty: Ty<'tcx>, return_ty_span: Span, body: &'tcx hir::Body<'tcx>, - span_with_body: Span + span_with_body: Span, ) -> Body<'tcx> where A: Iterator>, @@ -657,7 +660,8 @@ fn construct_const<'a, 'tcx>( let owner_id = tcx.hir().body_owner(body_id); let def_id = tcx.hir().local_def_id(owner_id); let span = tcx.hir().span(owner_id); - let mut builder = Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None); + let mut builder = + Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None); let mut block = START_BLOCK; let ast_expr = &tcx.hir().body(body_id).value; @@ -697,7 +701,8 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t hir::BodyOwnerKind::Const => 0, hir::BodyOwnerKind::Static(_) => 0, }; - let mut builder = Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None); + let mut builder = + Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None); let source_info = builder.source_info(span); // Some MIR passes will expect the number of parameters to match the // function declaration. @@ -796,7 +801,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name: ident.name, source_info, - place: arg_local.into(), + value: VarDebugInfoContents::Place(arg_local.into()), }); } } @@ -811,7 +816,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create upvar // debuginfo and to fill `self.upvar_mutbls`. - if let Some(upvars) = hir_typeck_results.closure_captures.get(&fn_def_id) { + if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { let closure_env_arg = Local::new(1); let mut closure_env_projs = vec![]; let mut closure_ty = self.local_decls[closure_env_arg].ty; @@ -824,14 +829,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), }; - let upvar_tys = upvar_substs.upvar_tys(); - let upvars_with_tys = upvars.iter().zip(upvar_tys); - self.upvar_mutbls = upvars_with_tys + let capture_tys = upvar_substs.upvar_tys(); + let captures_with_tys = hir_typeck_results + .closure_min_captures_flattened(fn_def_id) + .zip(capture_tys); + + self.upvar_mutbls = captures_with_tys .enumerate() - .map(|(i, ((&var_id, &upvar_id), ty))| { - let capture = hir_typeck_results.upvar_capture(upvar_id); + .map(|(i, (captured_place, ty))| { + let capture = captured_place.info.capture_kind; + let var_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected an upvar") + }; let mut mutability = Mutability::Not; + + // FIXME(project-rfc-2229#8): Store more precise information let mut name = kw::Invalid; if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { @@ -860,10 +874,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: SourceInfo::outermost(tcx_hir.span(var_id)), - place: Place { + value: VarDebugInfoContents::Place(Place { local: closure_env_arg, projection: tcx.intern_place_elems(&projs), - }, + }), }); mutability diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index e91227d835..e76175c045 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -84,7 +84,6 @@ that contains only loops and breakable blocks. It tracks where a `break`, use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; use crate::thir::{Expr, ExprRef, LintLevel}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::*; @@ -459,7 +458,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); let break_block = self.build_exit_tree(breakable_scope.break_drops, None); - if let Some(drops) = breakable_scope.continue_drops { self.build_exit_tree(drops, loop_block); } + if let Some(drops) = breakable_scope.continue_drops { + self.build_exit_tree(drops, loop_block); + } match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, (None, None) => self.cfg.start_new_block().unit(), @@ -733,18 +734,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// We would allocate the box but then free it on the unwinding /// path; we would also emit a free on the 'success' path from /// panic, but that will turn out to be removed as dead-code. - /// - /// When building statics/constants, returns `None` since - /// intermediate values do not have to be dropped in that case. - crate fn local_scope(&self) -> Option { - match self.hir.body_owner_kind { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => - // No need to free storage in this context. - { - None - } - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()), - } + crate fn local_scope(&self) -> region::Scope { + self.scopes.topmost() } // Scheduling drops @@ -898,19 +889,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// not the `DROP(_X)` itself, but the (spurious) unwind pathways /// that it creates. See #64391 for an example. crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) { - let scope = match self.local_scope() { - None => { - // if there is no local scope, operands won't be dropped anyway - return; - } + let local_scope = self.local_scope(); + let scope = self.scopes.scopes.last_mut().unwrap(); - Some(local_scope) => self - .scopes - .scopes - .iter_mut() - .rfind(|scope| scope.region_scope == local_scope) - .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)), - }; + assert_eq!( + scope.region_scope, local_scope, + "local scope is not the topmost scope!", + ); // look for moves of a local variable, like `MOVE(_X)` let locals_moved = operands.iter().flat_map(|operand| match operand { @@ -950,9 +935,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match cond { // Don't try to drop a constant Operand::Constant(_) => (), - // If constants and statics, we don't generate StorageLive for this - // temporary, so don't try to generate StorageDead for it either. - _ if self.local_scope().is_none() => (), Operand::Copy(place) | Operand::Move(place) => { if let Some(cond_temp) = place.as_local() { // Manually drop the condition on both branches. @@ -1387,7 +1369,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { | TerminatorKind::Yield { .. } | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdge { .. } - | TerminatorKind::InlineAsm {.. } => { + | TerminatorKind::InlineAsm { .. } => { span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind) } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 6ed7ed575f..417f9bded0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -6,6 +6,8 @@ use crate::thir::*; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_index::vec::Idx; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; +use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::BorrowKind; use rustc_middle::ty::adjustment::{ @@ -386,13 +388,12 @@ fn make_mirror_unadjusted<'a, 'tcx>( span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } }; + let upvars = cx - .tcx - .upvars_mentioned(def_id) - .iter() - .flat_map(|upvars| upvars.iter()) + .typeck_results() + .closure_min_captures_flattened(def_id) .zip(substs.upvar_tys()) - .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty)) + .map(|(captured_place, ty)| capture_upvar(cx, expr, captured_place, ty)) .collect(); ExprKind::Closure { closure_id: def_id, substs, upvars, movability } } @@ -407,7 +408,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( operands: asm .operands .iter() - .map(|op| { + .map(|(op, _op_sp)| { match *op { hir::InlineAsmOperand::In { reg, ref expr } => { InlineAsmOperand::In { reg, expr: expr.to_ref() } @@ -775,10 +776,10 @@ impl ToBorrowKind for hir::Mutability { fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> { Arm { pattern: cx.pattern_from_hir(&arm.pat), - guard: match arm.guard { - Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())), - _ => None, - }, + guard: arm.guard.as_ref().map(|g| match g { + hir::Guard::If(ref e) => Guard::If(e.to_ref()), + hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()), + }), body: arm.body.to_ref(), lint_level: LintLevel::Explicit(arm.hir_id), scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, @@ -879,130 +880,26 @@ fn convert_path_expr<'a, 'tcx>( ExprKind::Deref { arg: Expr { ty, temp_lifetime, span: expr.span, kind }.to_ref() } } - Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id), + Res::Local(var_hir_id) => convert_var(cx, var_hir_id), _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res), } } -fn convert_var<'tcx>( - cx: &mut Cx<'_, 'tcx>, - expr: &'tcx hir::Expr<'tcx>, - var_hir_id: hir::HirId, -) -> ExprKind<'tcx> { - let upvar_index = cx - .typeck_results() - .closure_captures - .get(&cx.body_owner) - .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i)); - - debug!( - "convert_var({:?}): upvar_index={:?}, body_owner={:?}", - var_hir_id, upvar_index, cx.body_owner - ); - - let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - - match upvar_index { - None => ExprKind::VarRef { id: var_hir_id }, +fn convert_var<'tcx>(cx: &mut Cx<'_, 'tcx>, var_hir_id: hir::HirId) -> ExprKind<'tcx> { + // We want upvars here not captures. + // Captures will be handled in MIR. + let is_upvar = cx + .tcx + .upvars_mentioned(cx.body_owner) + .map_or(false, |upvars| upvars.contains_key(&var_hir_id)); - Some(upvar_index) => { - let closure_def_id = cx.body_owner; - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: closure_def_id.expect_local(), - }; - let var_ty = cx.typeck_results().node_type(var_hir_id); + debug!("convert_var({:?}): is_upvar={}, body_owner={:?}", var_hir_id, is_upvar, cx.body_owner); - // FIXME free regions in closures are not right - let closure_ty = cx - .typeck_results() - .node_type(cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id)); - - // FIXME we're just hard-coding the idea that the - // signature will be &self or &mut self and hence will - // have a bound region with number 0 - let region = ty::ReFree(ty::FreeRegion { - scope: closure_def_id, - bound_region: ty::BoundRegion::BrAnon(0), - }); - let region = cx.tcx.mk_region(region); - - let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind() { - match cx.infcx.closure_kind(closure_substs).unwrap() { - ty::ClosureKind::Fn => { - let ref_closure_ty = cx.tcx.mk_ref( - region, - ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Not }, - ); - Expr { - ty: closure_ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::Deref { - arg: Expr { - ty: ref_closure_ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - } - .to_ref(), - }, - } - } - ty::ClosureKind::FnMut => { - let ref_closure_ty = cx.tcx.mk_ref( - region, - ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Mut }, - ); - Expr { - ty: closure_ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::Deref { - arg: Expr { - ty: ref_closure_ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - } - .to_ref(), - }, - } - } - ty::ClosureKind::FnOnce => Expr { - ty: closure_ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - }, - } - } else { - Expr { ty: closure_ty, temp_lifetime, span: expr.span, kind: ExprKind::SelfRef } - }; - - // at this point we have `self.n`, which loads up the upvar - let field_kind = - ExprKind::Field { lhs: self_expr.to_ref(), name: Field::new(upvar_index) }; - - // ...but the upvar might be an `&T` or `&mut T` capture, at which - // point we need an implicit deref - match cx.typeck_results().upvar_capture(upvar_id) { - ty::UpvarCapture::ByValue(_) => field_kind, - ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref { - arg: Expr { - temp_lifetime, - ty: cx.tcx.mk_ref( - borrow.region, - ty::TypeAndMut { ty: var_ty, mutbl: borrow.kind.to_mutbl_lossy() }, - ), - span: expr.span, - kind: field_kind, - } - .to_ref(), - }, - } - } + if is_upvar { + ExprKind::UpvarRef { closure_def_id: cx.body_owner, var_hir_id } + } else { + ExprKind::VarRef { id: var_hir_id } } } @@ -1084,27 +981,55 @@ fn overloaded_place<'a, 'tcx>( ExprKind::Deref { arg: ref_expr.to_ref() } } -fn capture_upvar<'tcx>( +fn capture_upvar<'a, 'tcx>( cx: &mut Cx<'_, 'tcx>, closure_expr: &'tcx hir::Expr<'tcx>, - var_hir_id: hir::HirId, + captured_place: &'a ty::CapturedPlace<'tcx>, upvar_ty: Ty<'tcx>, ) -> ExprRef<'tcx> { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id), - }; - let upvar_capture = cx.typeck_results().upvar_capture(upvar_id); + let upvar_capture = captured_place.info.capture_kind; let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); - let var_ty = cx.typeck_results().node_type(var_hir_id); - let captured_var = Expr { + let var_ty = captured_place.place.base_ty; + + // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path + // as it's seen for use within the closure and not at the time of closure creation. + // + // That is we see expect to see it start from a captured upvar and not something that is local + // to the closure's parent. + let var_hir_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + base => bug!("Expected an upvar, found {:?}", base), + }; + + let mut captured_place_expr = Expr { temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: convert_var(cx, closure_expr, var_hir_id), + kind: convert_var(cx, var_hir_id), }; + + for proj in captured_place.place.projections.iter() { + let kind = match proj.kind { + HirProjectionKind::Deref => ExprKind::Deref { arg: captured_place_expr.to_ref() }, + HirProjectionKind::Field(field, ..) => { + // Variant index will always be 0, because for multi-variant + // enums, we capture the enum entirely. + ExprKind::Field { + lhs: captured_place_expr.to_ref(), + name: Field::new(field as usize), + } + } + HirProjectionKind::Index | HirProjectionKind::Subslice => { + // We don't capture these projections, so we can ignore them here + continue; + } + }; + + captured_place_expr = Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }; + } + match upvar_capture { - ty::UpvarCapture::ByValue(_) => captured_var.to_ref(), + ty::UpvarCapture::ByValue(_) => captured_place_expr.to_ref(), ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow.kind { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, @@ -1115,7 +1040,7 @@ fn capture_upvar<'tcx>( temp_lifetime, ty: upvar_ty, span: closure_expr.span, - kind: ExprKind::Borrow { borrow_kind, arg: captured_var.to_ref() }, + kind: ExprKind::Borrow { borrow_kind, arg: captured_place_expr.to_ref() }, } .to_ref() } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index cf42fee873..465808cea9 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -186,6 +186,10 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { ty.needs_drop(self.tcx, self.param_env) } + crate fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> { + self.infcx + } + crate fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index f2a2ef0d8f..ace9cad4d2 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -211,8 +211,14 @@ crate enum ExprKind<'tcx> { VarRef { id: hir::HirId, }, - /// first argument, used for self in a closure - SelfRef, + /// Used to represent upvars mentioned in a closure/generator + UpvarRef { + /// DefId of the closure/generator + closure_def_id: DefId, + + /// HirId of the root variable + var_hir_id: hir::HirId, + }, Borrow { borrow_kind: BorrowKind, arg: ExprRef<'tcx>, @@ -338,6 +344,7 @@ crate struct Arm<'tcx> { #[derive(Clone, Debug)] crate enum Guard<'tcx> { If(ExprRef<'tcx>), + IfLet(Pat<'tcx>, ExprRef<'tcx>), } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs deleted file mode 100644 index 5e7e81eba6..0000000000 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ /dev/null @@ -1,2285 +0,0 @@ -//! Note: tests specific to this file can be found in: -//! - ui/pattern/usefulness -//! - ui/or-patterns -//! - ui/consts/const_in_pattern -//! - ui/rfc-2008-non-exhaustive -//! - probably many others -//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific -//! reason not to, for example if they depend on a particular feature like or_patterns. -//! -//! This file includes the logic for exhaustiveness and usefulness checking for -//! pattern-matching. Specifically, given a list of patterns for a type, we can -//! tell whether: -//! (a) the patterns cover every possible constructor for the type (exhaustiveness) -//! (b) each pattern is necessary (usefulness) -//! -//! The algorithm implemented here is a modified version of the one described in: -//! -//! However, to save future implementors from reading the original paper, we -//! summarise the algorithm here to hopefully save time and be a little clearer -//! (without being so rigorous). -//! -//! # Premise -//! -//! The core of the algorithm revolves about a "usefulness" check. In particular, we -//! are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as -//! a matrix). `U(P, p)` represents whether, given an existing list of patterns -//! `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously- -//! uncovered values of the type). -//! -//! If we have this predicate, then we can easily compute both exhaustiveness of an -//! entire set of patterns and the individual usefulness of each one. -//! (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard -//! match doesn't increase the number of values we're matching) -//! (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a -//! pattern to those that have come before it doesn't increase the number of values -//! we're matching). -//! -//! # Core concept -//! -//! The idea that powers everything that is done in this file is the following: a value is made -//! from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)` -//! (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the -//! constructor for the number `2`). Fields are just a (possibly empty) list of values. -//! -//! Some of the constructors listed above might feel weird: `None` and `2` don't take any -//! arguments. This is part of what makes constructors so general: we will consider plain values -//! like numbers and string literals to be constructors that take no arguments, also called "0-ary -//! constructors"; they are the simplest case of constructors. This allows us to see any value as -//! made up from a tree of constructors, each having a given number of children. For example: -//! `(None, Ok(0))` is made from 4 different constructors. -//! -//! This idea can be extended to patterns: a pattern captures a set of possible values, and we can -//! describe this set using constructors. For example, `Err(_)` captures all values of the type -//! `Result` that start with the `Err` constructor (for some choice of `T` and `E`). The -//! wildcard `_` captures all values of the given type starting with any of the constructors for -//! that type. -//! -//! We use this to compute whether different patterns might capture a same value. Do the patterns -//! `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern -//! captures only values starting with the `Ok` constructor and the second only values starting -//! with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might, -//! since they both capture values starting with `Some`. To be certain, we need to dig under the -//! `Some` constructor and continue asking the question. This is the main idea behind the -//! exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently -//! figure out if some new pattern might capture a value that hadn't been captured by previous -//! patterns. -//! -//! Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum. -//! Most of the complexity of this file resides in transforming between patterns and -//! (`Constructor`, `Fields`) pairs, handling all the special cases correctly. -//! -//! Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example -//! a value of type `Rc` doesn't fit this idea very well, nor do various other things. -//! However, this idea covers most of the cases that are relevant to exhaustiveness checking. -//! -//! -//! # Algorithm -//! -//! Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`, -//! adding a new pattern `p` will cover previously-uncovered values of the type. -//! During the course of the algorithm, the rows of the matrix won't just be individual patterns, -//! but rather partially-deconstructed patterns in the form of a list of fields. The paper -//! calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the -//! new pattern `p`. -//! -//! For example, say we have the following: -//! -//! ``` -//! // x: (Option, Result<()>) -//! match x { -//! (Some(true), _) => {} -//! (None, Err(())) => {} -//! (None, Err(_)) => {} -//! } -//! ``` -//! -//! Here, the matrix `P` starts as: -//! -//! ``` -//! [ -//! [(Some(true), _)], -//! [(None, Err(()))], -//! [(None, Err(_))], -//! ] -//! ``` -//! -//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering -//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because -//! all the values it covers are already covered by row 2. -//! -//! A list of patterns can be thought of as a stack, because we are mainly interested in the top of -//! the stack at any given point, and we can pop or apply constructors to get new pattern-stacks. -//! To match the paper, the top of the stack is at the beginning / on the left. -//! -//! There are two important operations on pattern-stacks necessary to understand the algorithm: -//! -//! 1. We can pop a given constructor off the top of a stack. This operation is called -//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or -//! `None`) and `p` a pattern-stack. -//! If the pattern on top of the stack can cover `c`, this removes the constructor and -//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. -//! Otherwise the pattern-stack is discarded. -//! This essentially filters those pattern-stacks whose top covers the constructor `c` and -//! discards the others. -//! -//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we -//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the -//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get -//! nothing back. -//! -//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` -//! on top of the stack, and we have four cases: -//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We -//! push onto the stack the arguments of this constructor, and return the result: -//! r_1, .., r_a, p_2, .., p_n -//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and -//! return nothing. -//! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has -//! arguments (its arity), and return the resulting stack: -//! _, .., _, p_2, .., p_n -//! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting -//! stack: -//! S(c, (r_1, p_2, .., p_n)) -//! S(c, (r_2, p_2, .., p_n)) -//! -//! 2. We can pop a wildcard off the top of the stack. This is called `S(_, p)`, where `p` is -//! a pattern-stack. Note: the paper calls this `D(p)`. -//! This is used when we know there are missing constructor cases, but there might be -//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check -//! all its *other* components. -//! -//! It is computed as follows. We look at the pattern `p_1` on top of the stack, -//! and we have three cases: -//! 2.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. -//! 2.2. `p_1 = _`. We return the rest of the stack: -//! p_2, .., p_n -//! 2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting -//! stack. -//! S(_, (r_1, p_2, .., p_n)) -//! S(_, (r_2, p_2, .., p_n)) -//! -//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the -//! exhaustive integer matching rules, so they're written here for posterity. -//! -//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by -//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with -//! the given constructor, and popping a wildcard keeps those rows that start with a wildcard. -//! -//! -//! The algorithm for computing `U` -//! ------------------------------- -//! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). -//! That means we're going to check the components from left-to-right, so the algorithm -//! operates principally on the first component of the matrix and new pattern-stack `p`. -//! This algorithm is realised in the `is_useful` function. -//! -//! Base case. (`n = 0`, i.e., an empty tuple pattern) -//! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), -//! then `U(P, p)` is false. -//! - Otherwise, `P` must be empty, so `U(P, p)` is true. -//! -//! Inductive step. (`n > 0`, i.e., whether there's at least one column -//! [which may then be expanded into further columns later]) -//! We're going to match on the top of the new pattern-stack, `p_1`. -//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. -//! Then, the usefulness of `p_1` can be reduced to whether it is useful when -//! we ignore all the patterns in the first column of `P` that involve other constructors. -//! This is where `S(c, P)` comes in: -//! `U(P, p) := U(S(c, P), S(c, p))` -//! -//! For example, if `P` is: -//! -//! ``` -//! [ -//! [Some(true), _], -//! [None, 0], -//! ] -//! ``` -//! -//! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only -//! matches values that row 2 doesn't. For row 1 however, we need to dig into the -//! arguments of `Some` to know whether some new value is covered. So we compute -//! `U([[true, _]], [false, 0])`. -//! -//! - If `p_1 == _`, then we look at the list of constructors that appear in the first -//! component of the rows of `P`: -//! + If there are some constructors that aren't present, then we might think that the -//! wildcard `_` is useful, since it covers those constructors that weren't covered -//! before. -//! That's almost correct, but only works if there were no wildcards in those first -//! components. So we need to check that `p` is useful with respect to the rows that -//! start with a wildcard, if there are any. This is where `S(_, x)` comes in: -//! `U(P, p) := U(S(_, P), S(_, p))` -//! -//! For example, if `P` is: -//! -//! ``` -//! [ -//! [_, true, _], -//! [None, false, 1], -//! ] -//! ``` -//! -//! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we -//! only had row 2, we'd know that `p` is useful. However row 1 starts with a -//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. -//! -//! + Otherwise, all possible constructors (for the relevant type) are present. In this -//! case we must check whether the wildcard pattern covers any unmatched value. For -//! that, we can think of the `_` pattern as a big OR-pattern that covers all -//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for -//! example. The wildcard pattern is useful in this case if it is useful when -//! specialized to one of the possible constructors. So we compute: -//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` -//! -//! For example, if `P` is: -//! -//! ``` -//! [ -//! [Some(true), _], -//! [None, false], -//! ] -//! ``` -//! -//! and `p` is [_, false], both `None` and `Some` constructors appear in the first -//! components of `P`. We will therefore try popping both constructors in turn: we -//! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]], -//! [false])` for the `None` constructor. The first case returns true, so we know that -//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched -//! before. -//! -//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: -//! `U(P, p) := U(P, (r_1, p_2, .., p_n)) -//! || U(P, (r_2, p_2, .., p_n))` -//! -//! Modifications to the algorithm -//! ------------------------------ -//! The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for -//! example uninhabited types and variable-length slice patterns. These are drawn attention to -//! throughout the code below. I'll make a quick note here about how exhaustive integer matching is -//! accounted for, though. -//! -//! Exhaustive integer matching -//! --------------------------- -//! An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ... -//! So to support exhaustive integer matching, we can make use of the logic in the paper for -//! OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because -//! they are likely gigantic. So we instead treat ranges as constructors of the integers. This means -//! that we have a constructor *of* constructors (the integers themselves). We then need to work -//! through all the inductive step rules above, deriving how the ranges would be treated as -//! OR-patterns, and making sure that they're treated in the same way even when they're ranges. -//! There are really only four special cases here: -//! - When we match on a constructor that's actually a range, we have to treat it as if we would -//! an OR-pattern. -//! + It turns out that we can simply extend the case for single-value patterns in -//! `specialize` to either be *equal* to a value constructor, or *contained within* a range -//! constructor. -//! + When the pattern itself is a range, you just want to tell whether any of the values in -//! the pattern range coincide with values in the constructor range, which is precisely -//! intersection. -//! Since when encountering a range pattern for a value constructor, we also use inclusion, it -//! means that whenever the constructor is a value/range and the pattern is also a value/range, -//! we can simply use intersection to test usefulness. -//! - When we're testing for usefulness of a pattern and the pattern's first component is a -//! wildcard. -//! + If all the constructors appear in the matrix, we have a slight complication. By default, -//! the behaviour (i.e., a disjunction over specialised matrices for each constructor) is -//! invalid, because we want a disjunction over every *integer* in each range, not just a -//! disjunction over every range. This is a bit more tricky to deal with: essentially we need -//! to form equivalence classes of subranges of the constructor range for which the behaviour -//! of the matrix `P` and new pattern `p` are the same. This is described in more -//! detail in `Constructor::split`. -//! + If some constructors are missing from the matrix, it turns out we don't need to do -//! anything special (because we know none of the integers are actually wildcards: i.e., we -//! can't span wildcards using ranges). -use self::Constructor::*; -use self::SliceKind::*; -use self::Usefulness::*; -use self::WitnessPreference::*; - -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::OnceCell; -use rustc_index::vec::Idx; - -use super::{compare_const_vals, PatternFoldable, PatternFolder}; -use super::{FieldPat, Pat, PatKind, PatRange}; - -use rustc_arena::TypedArena; -use rustc_attr::{SignedInt, UnsignedInt}; -use rustc_hir::def_id::DefId; -use rustc_hir::{HirId, RangeEnd}; -use rustc_middle::mir::interpret::ConstValue; -use rustc_middle::mir::Field; -use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; -use rustc_session::lint; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{Integer, Size, VariantIdx}; - -use smallvec::{smallvec, SmallVec}; -use std::cmp::{self, max, min, Ordering}; -use std::fmt; -use std::iter::{FromIterator, IntoIterator}; -use std::ops::RangeInclusive; - -crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> { - LiteralExpander.fold_pattern(&pat) -} - -struct LiteralExpander; - -impl<'tcx> PatternFolder<'tcx> for LiteralExpander { - fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { - debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); - match (pat.ty.kind(), pat.kind.as_ref()) { - (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self), - (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self), - (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => { - // Treat string literal patterns as deref patterns to a `str` constant, i.e. - // `&CONST`. This expands them like other const patterns. This could have been done - // in `const_to_pat`, but that causes issues with the rest of the matching code. - let mut new_pat = pat.super_fold_with(self); - // Make a fake const pattern of type `str` (instead of `&str`). That the carried - // constant value still knows it is of type `&str`. - new_pat.ty = t; - Pat { - kind: Box::new(PatKind::Deref { subpattern: new_pat }), - span: pat.span, - ty: pat.ty, - } - } - _ => pat.super_fold_with(self), - } - } -} - -impl<'tcx> Pat<'tcx> { - pub(super) fn is_wildcard(&self) -> bool { - matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) - } -} - -/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` -/// works well. -#[derive(Debug, Clone)] -crate struct PatStack<'p, 'tcx> { - pats: SmallVec<[&'p Pat<'tcx>; 2]>, - /// Cache for the constructor of the head - head_ctor: OnceCell>, -} - -impl<'p, 'tcx> PatStack<'p, 'tcx> { - crate fn from_pattern(pat: &'p Pat<'tcx>) -> Self { - Self::from_vec(smallvec![pat]) - } - - fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self { - PatStack { pats: vec, head_ctor: OnceCell::new() } - } - - fn is_empty(&self) -> bool { - self.pats.is_empty() - } - - fn len(&self) -> usize { - self.pats.len() - } - - fn head(&self) -> &'p Pat<'tcx> { - self.pats[0] - } - - fn head_ctor<'a>(&'a self, cx: &MatchCheckCtxt<'p, 'tcx>) -> &'a Constructor<'tcx> { - self.head_ctor.get_or_init(|| pat_constructor(cx, self.head())) - } - - fn iter(&self) -> impl Iterator> { - self.pats.iter().copied() - } - - // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`. - fn expand_or_pat(&self) -> Option> { - if self.is_empty() { - None - } else if let PatKind::Or { pats } = &*self.head().kind { - Some( - pats.iter() - .map(|pat| { - let mut new_patstack = PatStack::from_pattern(pat); - new_patstack.pats.extend_from_slice(&self.pats[1..]); - new_patstack - }) - .collect(), - ) - } else { - None - } - } - - /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations. - /// - /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing - /// fields filled with wild patterns. - /// - /// This is roughly the inverse of `Constructor::apply`. - fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> { - // We pop the head pattern and push the new fields extracted from the arguments of - // `self.head()`. - let new_fields = ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()); - new_fields.push_on_patstack(&self.pats[1..]) - } -} - -impl<'p, 'tcx> Default for PatStack<'p, 'tcx> { - fn default() -> Self { - Self::from_vec(smallvec![]) - } -} - -impl<'p, 'tcx> PartialEq for PatStack<'p, 'tcx> { - fn eq(&self, other: &Self) -> bool { - self.pats == other.pats - } -} - -impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { - fn from_iter(iter: T) -> Self - where - T: IntoIterator>, - { - Self::from_vec(iter.into_iter().collect()) - } -} - -/// A 2D matrix. -#[derive(Clone, PartialEq)] -crate struct Matrix<'p, 'tcx> { - patterns: Vec>, -} - -impl<'p, 'tcx> Matrix<'p, 'tcx> { - crate fn empty() -> Self { - Matrix { patterns: vec![] } - } - - /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. - crate fn push(&mut self, row: PatStack<'p, 'tcx>) { - if let Some(rows) = row.expand_or_pat() { - for row in rows { - // We recursively expand the or-patterns of the new rows. - // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`. - self.push(row) - } - } else { - self.patterns.push(row); - } - } - - /// Iterate over the first component of each row - fn heads<'a>(&'a self) -> impl Iterator> + Captures<'p> { - self.patterns.iter().map(|r| r.head()) - } - - /// Iterate over the first constructor of each row - fn head_ctors<'a>( - &'a self, - cx: &'a MatchCheckCtxt<'p, 'tcx>, - ) -> impl Iterator> + Captures<'a> + Captures<'p> { - self.patterns.iter().map(move |r| r.head_ctor(cx)) - } - - /// This computes `S(constructor, self)`. See top of the file for explanations. - fn specialize_constructor( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, - ) -> Matrix<'p, 'tcx> { - self.patterns - .iter() - .filter(|r| ctor.is_covered_by(pcx, r.head_ctor(pcx.cx))) - .map(|r| r.pop_head_constructor(ctor_wild_subpatterns)) - .collect() - } -} - -/// Pretty-printer for matrices of patterns, example: -/// -/// ```text -/// +++++++++++++++++++++++++++++ -/// + _ + [] + -/// +++++++++++++++++++++++++++++ -/// + true + [First] + -/// +++++++++++++++++++++++++++++ -/// + true + [Second(true)] + -/// +++++++++++++++++++++++++++++ -/// + false + [_] + -/// +++++++++++++++++++++++++++++ -/// + _ + [_, _, tail @ ..] + -/// +++++++++++++++++++++++++++++ -/// ``` -impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\n")?; - - let Matrix { patterns: m, .. } = self; - let pretty_printed_matrix: Vec> = - m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); - - let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0); - assert!(m.iter().all(|row| row.len() == column_count)); - let column_widths: Vec = (0..column_count) - .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)) - .collect(); - - let total_width = column_widths.iter().cloned().sum::() + column_count * 3 + 1; - let br = "+".repeat(total_width); - write!(f, "{}\n", br)?; - for row in pretty_printed_matrix { - write!(f, "+")?; - for (column, pat_str) in row.into_iter().enumerate() { - write!(f, " ")?; - write!(f, "{:1$}", pat_str, column_widths[column])?; - write!(f, " +")?; - } - write!(f, "\n")?; - write!(f, "{}\n", br)?; - } - Ok(()) - } -} - -impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { - fn from_iter(iter: T) -> Self - where - T: IntoIterator>, - { - let mut matrix = Matrix::empty(); - for x in iter { - // Using `push` ensures we correctly expand or-patterns. - matrix.push(x); - } - matrix - } -} - -crate struct MatchCheckCtxt<'a, 'tcx> { - crate tcx: TyCtxt<'tcx>, - /// The module in which the match occurs. This is necessary for - /// checking inhabited-ness of types because whether a type is (visibly) - /// inhabited can depend on whether it was defined in the current module or - /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty - /// outside it's module and should not be matchable with an empty match - /// statement. - crate module: DefId, - crate param_env: ty::ParamEnv<'tcx>, - crate pattern_arena: &'a TypedArena>, -} - -impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { - fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.features().exhaustive_patterns { - self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env) - } else { - false - } - } - - /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. - crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::Adt(def, ..) => { - def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local() - } - _ => false, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum SliceKind { - /// Patterns of length `n` (`[x, y]`). - FixedLen(u64), - /// Patterns using the `..` notation (`[x, .., y]`). - /// Captures any array constructor of `length >= i + j`. - /// In the case where `array_len` is `Some(_)`, - /// this indicates that we only care about the first `i` and the last `j` values of the array, - /// and everything in between is a wildcard `_`. - VarLen(u64, u64), -} - -impl SliceKind { - fn arity(self) -> u64 { - match self { - FixedLen(length) => length, - VarLen(prefix, suffix) => prefix + suffix, - } - } - - /// Whether this pattern includes patterns of length `other_len`. - fn covers_length(self, other_len: u64) -> bool { - match self { - FixedLen(len) => len == other_len, - VarLen(prefix, suffix) => prefix + suffix <= other_len, - } - } -} - -/// A constructor for array and slice patterns. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -struct Slice { - /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`. - array_len: Option, - /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`. - kind: SliceKind, -} - -impl Slice { - fn new(array_len: Option, kind: SliceKind) -> Self { - let kind = match (array_len, kind) { - // If the middle `..` is empty, we effectively have a fixed-length pattern. - (Some(len), VarLen(prefix, suffix)) if prefix + suffix >= len => FixedLen(len), - _ => kind, - }; - Slice { array_len, kind } - } - - fn arity(self) -> u64 { - self.kind.arity() - } - - /// The exhaustiveness-checking paper does not include any details on - /// checking variable-length slice patterns. However, they may be - /// matched by an infinite collection of fixed-length array patterns. - /// - /// Checking the infinite set directly would take an infinite amount - /// of time. However, it turns out that for each finite set of - /// patterns `P`, all sufficiently large array lengths are equivalent: - /// - /// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies - /// to exactly the subset `Pₜ` of `P` can be transformed to a slice - /// `sₘ` for each sufficiently-large length `m` that applies to exactly - /// the same subset of `P`. - /// - /// Because of that, each witness for reachability-checking of one - /// of the sufficiently-large lengths can be transformed to an - /// equally-valid witness of any other length, so we only have - /// to check slices of the "minimal sufficiently-large length" - /// and less. - /// - /// Note that the fact that there is a *single* `sₘ` for each `m` - /// not depending on the specific pattern in `P` is important: if - /// you look at the pair of patterns - /// `[true, ..]` - /// `[.., false]` - /// Then any slice of length ≥1 that matches one of these two - /// patterns can be trivially turned to a slice of any - /// other length ≥1 that matches them and vice-versa, - /// but the slice of length 2 `[false, true]` that matches neither - /// of these patterns can't be turned to a slice from length 1 that - /// matches neither of these patterns, so we have to consider - /// slices from length 2 there. - /// - /// Now, to see that that length exists and find it, observe that slice - /// patterns are either "fixed-length" patterns (`[_, _, _]`) or - /// "variable-length" patterns (`[_, .., _]`). - /// - /// For fixed-length patterns, all slices with lengths *longer* than - /// the pattern's length have the same outcome (of not matching), so - /// as long as `L` is greater than the pattern's length we can pick - /// any `sₘ` from that length and get the same result. - /// - /// For variable-length patterns, the situation is more complicated, - /// because as seen above the precise value of `sₘ` matters. - /// - /// However, for each variable-length pattern `p` with a prefix of length - /// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last - /// `slₚ` elements are examined. - /// - /// Therefore, as long as `L` is positive (to avoid concerns about empty - /// types), all elements after the maximum prefix length and before - /// the maximum suffix length are not examined by any variable-length - /// pattern, and therefore can be added/removed without affecting - /// them - creating equivalent patterns from any sufficiently-large - /// length. - /// - /// Of course, if fixed-length patterns exist, we must be sure - /// that our length is large enough to miss them all, so - /// we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))` - /// - /// for example, with the above pair of patterns, all elements - /// but the first and last can be added/removed, so any - /// witness of length ≥2 (say, `[false, false, true]`) can be - /// turned to a witness from any other length ≥2. - fn split<'p, 'tcx>(self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { - let (self_prefix, self_suffix) = match self.kind { - VarLen(self_prefix, self_suffix) => (self_prefix, self_suffix), - _ => return smallvec![Slice(self)], - }; - - let head_ctors = pcx.matrix.head_ctors(pcx.cx).filter(|c| !c.is_wildcard()); - - let mut max_prefix_len = self_prefix; - let mut max_suffix_len = self_suffix; - let mut max_fixed_len = 0; - - for ctor in head_ctors { - if let Slice(slice) = ctor { - match slice.kind { - FixedLen(len) => { - max_fixed_len = cmp::max(max_fixed_len, len); - } - VarLen(prefix, suffix) => { - max_prefix_len = cmp::max(max_prefix_len, prefix); - max_suffix_len = cmp::max(max_suffix_len, suffix); - } - } - } else { - bug!("unexpected ctor for slice type: {:?}", ctor); - } - } - - // For diagnostics, we keep the prefix and suffix lengths separate, so in the case - // where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly, - // so that `L = max_prefix_len + max_suffix_len`. - if max_fixed_len + 1 >= max_prefix_len + max_suffix_len { - // The subtraction can't overflow thanks to the above check. - // The new `max_prefix_len` is also guaranteed to be larger than its previous - // value. - max_prefix_len = max_fixed_len + 1 - max_suffix_len; - } - - let final_slice = VarLen(max_prefix_len, max_suffix_len); - let final_slice = Slice::new(self.array_len, final_slice); - match self.array_len { - Some(_) => smallvec![Slice(final_slice)], - None => { - // `self` originally covered the range `(self.arity()..infinity)`. We split that - // range into two: lengths smaller than `final_slice.arity()` are treated - // independently as fixed-lengths slices, and lengths above are captured by - // `final_slice`. - let smaller_lengths = (self.arity()..final_slice.arity()).map(FixedLen); - smaller_lengths - .map(|kind| Slice::new(self.array_len, kind)) - .chain(Some(final_slice)) - .map(Slice) - .collect() - } - } - } - - /// See `Constructor::is_covered_by` - fn is_covered_by(self, other: Self) -> bool { - other.kind.covers_length(self.arity()) - } -} - -/// A value can be decomposed into a constructor applied to some fields. This struct represents -/// the constructor. See also `Fields`. -/// -/// `pat_constructor` retrieves the constructor corresponding to a pattern. -/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a -/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and -/// `Fields`. -#[derive(Clone, Debug, PartialEq)] -enum Constructor<'tcx> { - /// The constructor for patterns that have a single constructor, like tuples, struct patterns - /// and fixed-length arrays. - Single, - /// Enum variants. - Variant(DefId), - /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). - IntRange(IntRange<'tcx>), - /// Ranges of floating-point literal values (`2.0..=5.2`). - FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), - /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. - Str(&'tcx ty::Const<'tcx>), - /// Array and slice patterns. - Slice(Slice), - /// Constants that must not be matched structurally. They are treated as black - /// boxes for the purposes of exhaustiveness: we must not inspect them, and they - /// don't count towards making a match exhaustive. - Opaque, - /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used - /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. - NonExhaustive, - /// Wildcard pattern. - Wildcard, -} - -impl<'tcx> Constructor<'tcx> { - fn is_wildcard(&self) -> bool { - matches!(self, Wildcard) - } - - fn as_int_range(&self) -> Option<&IntRange<'tcx>> { - match self { - IntRange(range) => Some(range), - _ => None, - } - } - - fn as_slice(&self) -> Option { - match self { - Slice(slice) => Some(*slice), - _ => None, - } - } - - fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx { - match *self { - Variant(id) => adt.variant_index_with_id(id), - Single => { - assert!(!adt.is_enum()); - VariantIdx::new(0) - } - _ => bug!("bad constructor {:?} for adt {:?}", self, adt), - } - } - - /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual - /// constructors (like variants, integers or fixed-sized slices). When specializing for these - /// constructors, we want to be specialising for the actual underlying constructors. - /// Naively, we would simply return the list of constructors they correspond to. We instead are - /// more clever: if there are constructors that we know will behave the same wrt the current - /// matrix, we keep them grouped. For example, all slices of a sufficiently large length - /// will either be all useful or all non-useful with a given matrix. - /// - /// See the branches for details on how the splitting is done. - /// - /// This function may discard some irrelevant constructors if this preserves behavior and - /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the - /// matrix, unless all of them are. - /// - /// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want - /// to lint for overlapping ranges. - fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, hir_id: Option) -> SmallVec<[Self; 1]> { - debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix); - - match self { - Wildcard => Constructor::split_wildcard(pcx), - // Fast-track if the range is trivial. In particular, we don't do the overlapping - // ranges check. - IntRange(ctor_range) - if ctor_range.treat_exhaustively(pcx.cx.tcx) && !ctor_range.is_singleton() => - { - ctor_range.split(pcx, hir_id) - } - Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx), - // Any other constructor can be used unchanged. - _ => smallvec![self.clone()], - } - } - - /// For wildcards, there are two groups of constructors: there are the constructors actually - /// present in the matrix (`head_ctors`), and the constructors not present (`missing_ctors`). - /// Two constructors that are not in the matrix will either both be caught (by a wildcard), or - /// both not be caught. Therefore we can keep the missing constructors grouped together. - fn split_wildcard<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> { - // Missing constructors are those that are not matched by any non-wildcard patterns in the - // current column. We only fully construct them on-demand, because they're rarely used and - // can be big. - let missing_ctors = MissingConstructors::new(pcx); - if missing_ctors.is_empty(pcx) { - // All the constructors are present in the matrix, so we just go through them all. - // We must also split them first. - missing_ctors.all_ctors - } else { - // Some constructors are missing, thus we can specialize with the wildcard constructor, - // which will stand for those constructors that are missing, and behaves like any of - // them. - smallvec![Wildcard] - } - } - - /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. - /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, - /// this checks for inclusion. - fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { - // This must be kept in sync with `is_covered_by_any`. - match (self, other) { - // Wildcards cover anything - (_, Wildcard) => true, - // Wildcards are only covered by wildcards - (Wildcard, _) => false, - - (Single, Single) => true, - (Variant(self_id), Variant(other_id)) => self_id == other_id, - - (IntRange(self_range), IntRange(other_range)) => { - self_range.is_covered_by(pcx, other_range) - } - ( - FloatRange(self_from, self_to, self_end), - FloatRange(other_from, other_to, other_end), - ) => { - match ( - compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty), - compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty), - ) { - (Some(to), Some(from)) => { - (from == Ordering::Greater || from == Ordering::Equal) - && (to == Ordering::Less - || (other_end == self_end && to == Ordering::Equal)) - } - _ => false, - } - } - (Str(self_val), Str(other_val)) => { - // FIXME: there's probably a more direct way of comparing for equality - match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty) - { - Some(comparison) => comparison == Ordering::Equal, - None => false, - } - } - (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice), - - // We are trying to inspect an opaque constant. Thus we skip the row. - (Opaque, _) | (_, Opaque) => false, - // Only a wildcard pattern can match the special extra constructor. - (NonExhaustive, _) => false, - - _ => span_bug!( - pcx.span, - "trying to compare incompatible constructors {:?} and {:?}", - self, - other - ), - } - } - - /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is - /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is - /// assumed to have been split from a wildcard. - fn is_covered_by_any<'p>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - used_ctors: &[Constructor<'tcx>], - ) -> bool { - if used_ctors.is_empty() { - return false; - } - - // This must be kept in sync with `is_covered_by`. - match self { - // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. - Single => !used_ctors.is_empty(), - Variant(_) => used_ctors.iter().any(|c| c == self), - IntRange(range) => used_ctors - .iter() - .filter_map(|c| c.as_int_range()) - .any(|other| range.is_covered_by(pcx, other)), - Slice(slice) => used_ctors - .iter() - .filter_map(|c| c.as_slice()) - .any(|other| slice.is_covered_by(other)), - // This constructor is never covered by anything else - NonExhaustive => false, - Str(..) | FloatRange(..) | Opaque | Wildcard => { - bug!("found unexpected ctor in all_ctors: {:?}", self) - } - } - } - - /// Apply a constructor to a list of patterns, yielding a new pattern. `pats` - /// must have as many elements as this constructor's arity. - /// - /// This is roughly the inverse of `specialize_constructor`. - /// - /// Examples: - /// `self`: `Constructor::Single` - /// `ty`: `(u32, u32, u32)` - /// `pats`: `[10, 20, _]` - /// returns `(10, 20, _)` - /// - /// `self`: `Constructor::Variant(Option::Some)` - /// `ty`: `Option` - /// `pats`: `[false]` - /// returns `Some(false)` - fn apply<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, fields: Fields<'p, 'tcx>) -> Pat<'tcx> { - let mut subpatterns = fields.all_patterns(); - - let pat = match self { - Single | Variant(_) => match pcx.ty.kind() { - ty::Adt(..) | ty::Tuple(..) => { - let subpatterns = subpatterns - .enumerate() - .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) - .collect(); - - if let ty::Adt(adt, substs) = pcx.ty.kind() { - if adt.is_enum() { - PatKind::Variant { - adt_def: adt, - substs, - variant_index: self.variant_index_for_adt(adt), - subpatterns, - } - } else { - PatKind::Leaf { subpatterns } - } - } else { - PatKind::Leaf { subpatterns } - } - } - // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should - // be careful to reconstruct the correct constant pattern here. However a string - // literal pattern will never be reported as a non-exhaustiveness witness, so we - // can ignore this issue. - ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, - ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, pcx.ty), - _ => PatKind::Wild, - }, - Slice(slice) => match slice.kind { - FixedLen(_) => { - PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] } - } - VarLen(prefix, _) => { - let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect(); - if slice.array_len.is_some() { - // Improves diagnostics a bit: if the type is a known-size array, instead - // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. - // This is incorrect if the size is not known, since `[_, ..]` captures - // arrays of lengths `>= 1` whereas `[..]` captures any length. - while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() { - prefix.pop(); - } - } - let suffix: Vec<_> = if slice.array_len.is_some() { - // Same as above. - subpatterns.skip_while(Pat::is_wildcard).collect() - } else { - subpatterns.collect() - }; - let wild = Pat::wildcard_from_ty(pcx.ty); - PatKind::Slice { prefix, slice: Some(wild), suffix } - } - }, - &Str(value) => PatKind::Constant { value }, - &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), - IntRange(range) => return range.to_pat(pcx.cx.tcx), - NonExhaustive => PatKind::Wild, - Opaque => bug!("we should not try to apply an opaque constructor"), - Wildcard => bug!( - "trying to apply a wildcard constructor; this should have been done in `apply_constructors`" - ), - }; - - Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) } - } -} - -/// Some fields need to be explicitly hidden away in certain cases; see the comment above the -/// `Fields` struct. This struct represents such a potentially-hidden field. When a field is hidden -/// we still keep its type around. -#[derive(Debug, Copy, Clone)] -enum FilteredField<'p, 'tcx> { - Kept(&'p Pat<'tcx>), - Hidden(Ty<'tcx>), -} - -impl<'p, 'tcx> FilteredField<'p, 'tcx> { - fn kept(self) -> Option<&'p Pat<'tcx>> { - match self { - FilteredField::Kept(p) => Some(p), - FilteredField::Hidden(_) => None, - } - } - - fn to_pattern(self) -> Pat<'tcx> { - match self { - FilteredField::Kept(p) => p.clone(), - FilteredField::Hidden(ty) => Pat::wildcard_from_ty(ty), - } - } -} - -/// A value can be decomposed into a constructor applied to some fields. This struct represents -/// those fields, generalized to allow patterns in each field. See also `Constructor`. -/// -/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is -/// uninhabited. For that, we filter these fields out of the matrix. This is subtle because we -/// still need to have those fields back when going to/from a `Pat`. Most of this is handled -/// automatically in `Fields`, but when constructing or deconstructing `Fields` you need to be -/// careful. As a rule, when going to/from the matrix, use the filtered field list; when going -/// to/from `Pat`, use the full field list. -/// This filtering is uncommon in practice, because uninhabited fields are rarely used, so we avoid -/// it when possible to preserve performance. -#[derive(Debug, Clone)] -enum Fields<'p, 'tcx> { - /// Lists of patterns that don't contain any filtered fields. - /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and - /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril) - /// have not measured if it really made a difference. - Slice(&'p [Pat<'tcx>]), - Vec(SmallVec<[&'p Pat<'tcx>; 2]>), - /// Patterns where some of the fields need to be hidden. `kept_count` caches the number of - /// non-hidden fields. - Filtered { - fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>, - kept_count: usize, - }, -} - -impl<'p, 'tcx> Fields<'p, 'tcx> { - fn empty() -> Self { - Fields::Slice(&[]) - } - - /// Construct a new `Fields` from the given pattern. Must not be used if the pattern is a field - /// of a struct/tuple/variant. - fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self { - Fields::Slice(std::slice::from_ref(pat)) - } - - /// Convenience; internal use. - fn wildcards_from_tys( - cx: &MatchCheckCtxt<'p, 'tcx>, - tys: impl IntoIterator>, - ) -> Self { - let wilds = tys.into_iter().map(Pat::wildcard_from_ty); - let pats = cx.pattern_arena.alloc_from_iter(wilds); - Fields::Slice(pats) - } - - /// Creates a new list of wildcard fields for a given constructor. - fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { - let ty = pcx.ty; - let cx = pcx.cx; - let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); - - let ret = match constructor { - Single | Variant(_) => match ty.kind() { - ty::Tuple(ref fs) => { - Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty())) - } - ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)), - ty::Adt(adt, substs) => { - if adt.is_box() { - // Use T as the sub pattern type of Box. - Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0))) - } else { - let variant = &adt.variants[constructor.variant_index_for_adt(adt)]; - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = - variant.is_field_list_non_exhaustive() && !adt.did.is_local(); - let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs)); - // In the following cases, we don't need to filter out any fields. This is - // the vast majority of real cases, since uninhabited fields are uncommon. - let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive) - || !field_tys.clone().any(|ty| cx.is_uninhabited(ty)); - - if has_no_hidden_fields { - Fields::wildcards_from_tys(cx, field_tys) - } else { - let mut kept_count = 0; - let fields = variant - .fields - .iter() - .map(|field| { - let ty = field.ty(cx.tcx, substs); - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(ty); - - // In the cases of either a `#[non_exhaustive]` field list - // or a non-public field, we hide uninhabited fields in - // order not to reveal the uninhabitedness of the whole - // variant. - if is_uninhabited && (!is_visible || is_non_exhaustive) { - FilteredField::Hidden(ty) - } else { - kept_count += 1; - FilteredField::Kept(wildcard_from_ty(ty)) - } - }) - .collect(); - Fields::Filtered { fields, kept_count } - } - } - } - _ => bug!("Unexpected type for `Single` constructor: {:?}", ty), - }, - Slice(slice) => match *ty.kind() { - ty::Slice(ty) | ty::Array(ty, _) => { - let arity = slice.arity(); - Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty)) - } - _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), - }, - Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => { - Fields::empty() - } - }; - debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); - ret - } - - /// Returns the number of patterns from the viewpoint of match-checking, i.e. excluding hidden - /// fields. This is what we want in most cases in this file, the only exception being - /// conversion to/from `Pat`. - fn len(&self) -> usize { - match self { - Fields::Slice(pats) => pats.len(), - Fields::Vec(pats) => pats.len(), - Fields::Filtered { kept_count, .. } => *kept_count, - } - } - - /// Returns the complete list of patterns, including hidden fields. - fn all_patterns(self) -> impl Iterator> { - let pats: SmallVec<[_; 2]> = match self { - Fields::Slice(pats) => pats.iter().cloned().collect(), - Fields::Vec(pats) => pats.into_iter().cloned().collect(), - Fields::Filtered { fields, .. } => { - // We don't skip any fields here. - fields.into_iter().map(|p| p.to_pattern()).collect() - } - }; - pats.into_iter() - } - - /// Overrides some of the fields with the provided patterns. Exactly like - /// `replace_fields_indexed`, except that it takes `FieldPat`s as input. - fn replace_with_fieldpats( - &self, - new_pats: impl IntoIterator>, - ) -> Self { - self.replace_fields_indexed( - new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)), - ) - } - - /// Overrides some of the fields with the provided patterns. This is used when a pattern - /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start with a - /// `Fields` that is just one wildcard per field of the `Foo` struct, and override the entry - /// corresponding to `field1` with the pattern `Some(_)`. This is also used for slice patterns - /// for the same reason. - fn replace_fields_indexed( - &self, - new_pats: impl IntoIterator)>, - ) -> Self { - let mut fields = self.clone(); - if let Fields::Slice(pats) = fields { - fields = Fields::Vec(pats.iter().collect()); - } - - match &mut fields { - Fields::Vec(pats) => { - for (i, pat) in new_pats { - pats[i] = pat - } - } - Fields::Filtered { fields, .. } => { - for (i, pat) in new_pats { - if let FilteredField::Kept(p) = &mut fields[i] { - *p = pat - } - } - } - Fields::Slice(_) => unreachable!(), - } - fields - } - - /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the - /// matrix. There must be `len()` patterns in `pats`. - fn replace_fields( - &self, - cx: &MatchCheckCtxt<'p, 'tcx>, - pats: impl IntoIterator>, - ) -> Self { - let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); - - match self { - Fields::Filtered { fields, kept_count } => { - let mut pats = pats.iter(); - let mut fields = fields.clone(); - for f in &mut fields { - if let FilteredField::Kept(p) = f { - // We take one input pattern for each `Kept` field, in order. - *p = pats.next().unwrap(); - } - } - Fields::Filtered { fields, kept_count: *kept_count } - } - _ => Fields::Slice(pats), - } - } - - /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern - /// that is compatible with the constructor used to build `self`. - /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that - /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern - /// provided to this function fills some of the fields with non-wildcards. - /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call - /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _, - /// _, _]`. - /// ```rust - /// let x: [Option; 4] = foo(); - /// match x { - /// [Some(0), ..] => {} - /// } - /// ``` - /// This is guaranteed to preserve the number of patterns in `self`. - fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self { - match pat.kind.as_ref() { - PatKind::Deref { subpattern } => { - assert_eq!(self.len(), 1); - Fields::from_single_pattern(subpattern) - } - PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { - self.replace_with_fieldpats(subpatterns) - } - PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => { - // Number of subpatterns for the constructor - let ctor_arity = self.len(); - - // Replace the prefix and the suffix with the given patterns, leaving wildcards in - // the middle if there was a subslice pattern `..`. - let prefix = prefix.iter().enumerate(); - let suffix = - suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p)); - self.replace_fields_indexed(prefix.chain(suffix)) - } - _ => self.clone(), - } - } - - fn push_on_patstack(self, stack: &[&'p Pat<'tcx>]) -> PatStack<'p, 'tcx> { - let pats: SmallVec<_> = match self { - Fields::Slice(pats) => pats.iter().chain(stack.iter().copied()).collect(), - Fields::Vec(mut pats) => { - pats.extend_from_slice(stack); - pats - } - Fields::Filtered { fields, .. } => { - // We skip hidden fields here - fields.into_iter().filter_map(|p| p.kept()).chain(stack.iter().copied()).collect() - } - }; - PatStack::from_vec(pats) - } -} - -#[derive(Clone, Debug)] -crate enum Usefulness<'tcx> { - /// Carries, for each column in the matrix, a set of sub-branches that have been found to be - /// unreachable. Used only in the presence of or-patterns, otherwise it stays empty. - Useful(Vec>), - /// Carries a list of witnesses of non-exhaustiveness. - UsefulWithWitness(Vec>), - NotUseful, -} - -impl<'tcx> Usefulness<'tcx> { - fn new_useful(preference: WitnessPreference) -> Self { - match preference { - ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]), - LeaveOutWitness => Useful(vec![]), - } - } - - fn is_useful(&self) -> bool { - !matches!(*self, NotUseful) - } - - fn apply_constructor<'p>( - self, - pcx: PatCtxt<'_, 'p, 'tcx>, - ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, - is_top_level: bool, - ) -> Self { - match self { - UsefulWithWitness(witnesses) => { - let new_witnesses = if ctor.is_wildcard() { - let missing_ctors = MissingConstructors::new(pcx); - let new_patterns = missing_ctors.report_patterns(pcx, is_top_level); - witnesses - .into_iter() - .flat_map(|witness| { - new_patterns.iter().map(move |pat| { - let mut witness = witness.clone(); - witness.0.push(pat.clone()); - witness - }) - }) - .collect() - } else { - witnesses - .into_iter() - .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns)) - .collect() - }; - UsefulWithWitness(new_witnesses) - } - Useful(mut unreachables) => { - if !unreachables.is_empty() { - // When we apply a constructor, there are `arity` columns of the matrix that - // corresponded to its arguments. All the unreachables found in these columns - // will, after `apply`, come from the first column. So we take the union of all - // the corresponding sets and put them in the first column. - // Note that `arity` may be 0, in which case we just push a new empty set. - let len = unreachables.len(); - let arity = ctor_wild_subpatterns.len(); - let mut unioned = FxHashSet::default(); - for set in unreachables.drain((len - arity)..) { - unioned.extend(set) - } - unreachables.push(unioned); - } - Useful(unreachables) - } - x => x, - } - } -} - -#[derive(Copy, Clone, Debug)] -crate enum WitnessPreference { - ConstructWitness, - LeaveOutWitness, -} - -#[derive(Copy, Clone)] -struct PatCtxt<'a, 'p, 'tcx> { - cx: &'a MatchCheckCtxt<'p, 'tcx>, - /// Current state of the matrix. - matrix: &'a Matrix<'p, 'tcx>, - /// Type of the current column under investigation. - ty: Ty<'tcx>, - /// Span of the current pattern under investigation. - span: Span, -} - -/// A witness of non-exhaustiveness for error reporting, represented -/// as a list of patterns (in reverse order of construction) with -/// wildcards inside to represent elements that can take any inhabitant -/// of the type as a value. -/// -/// A witness against a list of patterns should have the same types -/// and length as the pattern matched against. Because Rust `match` -/// is always against a single pattern, at the end the witness will -/// have length 1, but in the middle of the algorithm, it can contain -/// multiple patterns. -/// -/// For example, if we are constructing a witness for the match against -/// -/// ``` -/// struct Pair(Option<(u32, u32)>, bool); -/// -/// match (p: Pair) { -/// Pair(None, _) => {} -/// Pair(_, false) => {} -/// } -/// ``` -/// -/// We'll perform the following steps: -/// 1. Start with an empty witness -/// `Witness(vec![])` -/// 2. Push a witness `Some(_)` against the `None` -/// `Witness(vec![Some(_)])` -/// 3. Push a witness `true` against the `false` -/// `Witness(vec![Some(_), true])` -/// 4. Apply the `Pair` constructor to the witnesses -/// `Witness(vec![Pair(Some(_), true)])` -/// -/// The final `Pair(Some(_), true)` is then the resulting witness. -#[derive(Clone, Debug)] -crate struct Witness<'tcx>(Vec>); - -impl<'tcx> Witness<'tcx> { - crate fn single_pattern(self) -> Pat<'tcx> { - assert_eq!(self.0.len(), 1); - self.0.into_iter().next().unwrap() - } - - /// Constructs a partial witness for a pattern given a list of - /// patterns expanded by the specialization step. - /// - /// When a pattern P is discovered to be useful, this function is used bottom-up - /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset - /// of values, V, where each value in that set is not covered by any previously - /// used patterns and is covered by the pattern P'. Examples: - /// - /// left_ty: tuple of 3 elements - /// pats: [10, 20, _] => (10, 20, _) - /// - /// left_ty: struct X { a: (bool, &'static str), b: usize} - /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor<'p>( - mut self, - pcx: PatCtxt<'_, 'p, 'tcx>, - ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, - ) -> Self { - let pat = { - let len = self.0.len(); - let arity = ctor_wild_subpatterns.len(); - let pats = self.0.drain((len - arity)..).rev(); - let fields = ctor_wild_subpatterns.replace_fields(pcx.cx, pats); - ctor.apply(pcx, fields) - }; - - self.0.push(pat); - - self - } -} - -/// This determines the set of all possible constructors of a pattern matching -/// values of type `left_ty`. For vectors, this would normally be an infinite set -/// but is instead bounded by the maximum fixed length of slice patterns in -/// the column of patterns being analyzed. -/// -/// We make sure to omit constructors that are statically impossible. E.g., for -/// `Option`, we do not include `Some(_)` in the returned list of constructors. -/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by -/// `cx.is_uninhabited()`). -fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec> { - debug!("all_constructors({:?})", pcx.ty); - let cx = pcx.cx; - let make_range = |start, end| { - IntRange( - // `unwrap()` is ok because we know the type is an integer. - IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included, pcx.span) - .unwrap(), - ) - }; - match pcx.ty.kind() { - ty::Bool => vec![make_range(0, 1)], - ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { - let len = len.eval_usize(cx.tcx, cx.param_env); - if len != 0 && cx.is_uninhabited(sub_ty) { - vec![] - } else { - vec![Slice(Slice::new(Some(len), VarLen(0, 0)))] - } - } - // Treat arrays of a constant but unknown length like slices. - ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { - let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; - vec![Slice(Slice::new(None, kind))] - } - ty::Adt(def, substs) if def.is_enum() => { - // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an - // additional "unknown" constructor. - // There is no point in enumerating all possible variants, because the user can't - // actually match against them all themselves. So we always return only the fictitious - // constructor. - // E.g., in an example like: - // - // ``` - // let err: io::ErrorKind = ...; - // match err { - // io::ErrorKind::NotFound => {}, - // } - // ``` - // - // we don't want to show every possible IO error, but instead have only `_` as the - // witness. - let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); - - // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it - // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that - // an empty match will still be considered exhaustive because that case is handled - // separately in `check_match`. - let is_secretly_empty = - def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns; - - if is_secretly_empty || is_declared_nonexhaustive { - vec![NonExhaustive] - } else if cx.tcx.features().exhaustive_patterns { - // If `exhaustive_patterns` is enabled, we exclude variants known to be - // uninhabited. - def.variants - .iter() - .filter(|v| { - !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) - .contains(cx.tcx, cx.module) - }) - .map(|v| Variant(v.def_id)) - .collect() - } else { - def.variants.iter().map(|v| Variant(v.def_id)).collect() - } - } - ty::Char => { - vec![ - // The valid Unicode Scalar Value ranges. - make_range('\u{0000}' as u128, '\u{D7FF}' as u128), - make_range('\u{E000}' as u128, '\u{10FFFF}' as u128), - ] - } - ty::Int(_) | ty::Uint(_) - if pcx.ty.is_ptr_sized_integral() - && !cx.tcx.features().precise_pointer_size_matching => - { - // `usize`/`isize` are not allowed to be matched exhaustively unless the - // `precise_pointer_size_matching` feature is enabled. So we treat those types like - // `#[non_exhaustive]` enums by returning a special unmatcheable constructor. - vec![NonExhaustive] - } - &ty::Int(ity) => { - let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128; - let min = 1u128 << (bits - 1); - let max = min - 1; - vec![make_range(min, max)] - } - &ty::Uint(uty) => { - let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); - let max = size.truncate(u128::MAX); - vec![make_range(0, max)] - } - _ if cx.is_uninhabited(pcx.ty) => vec![], - ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single], - // This type is one for which we cannot list constructors, like `str` or `f64`. - _ => vec![NonExhaustive], - } -} - -/// An inclusive interval, used for precise integer exhaustiveness checking. -/// `IntRange`s always store a contiguous range. This means that values are -/// encoded such that `0` encodes the minimum value for the integer, -/// regardless of the signedness. -/// For example, the pattern `-128..=127i8` is encoded as `0..=255`. -/// This makes comparisons and arithmetic on interval endpoints much more -/// straightforward. See `signed_bias` for details. -/// -/// `IntRange` is never used to encode an empty range or a "range" that wraps -/// around the (offset) space: i.e., `range.lo <= range.hi`. -#[derive(Clone, Debug)] -struct IntRange<'tcx> { - range: RangeInclusive, - ty: Ty<'tcx>, - span: Span, -} - -impl<'tcx> IntRange<'tcx> { - #[inline] - fn is_integral(ty: Ty<'_>) -> bool { - matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool) - } - - fn is_singleton(&self) -> bool { - self.range.start() == self.range.end() - } - - fn boundaries(&self) -> (u128, u128) { - (*self.range.start(), *self.range.end()) - } - - /// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching` feature - /// is enabled. - fn treat_exhaustively(&self, tcx: TyCtxt<'tcx>) -> bool { - !self.ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching - } - - #[inline] - fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> { - match *ty.kind() { - ty::Bool => Some((Size::from_bytes(1), 0)), - ty::Char => Some((Size::from_bytes(4), 0)), - ty::Int(ity) => { - let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); - Some((size, 1u128 << (size.bits() as u128 - 1))) - } - ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)), - _ => None, - } - } - - #[inline] - fn from_const( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &Const<'tcx>, - span: Span, - ) -> Option> { - if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) { - let ty = value.ty; - let val = (|| { - if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val { - // For this specific pattern we can skip a lot of effort and go - // straight to the result, after doing a bit of checking. (We - // could remove this branch and just fall through, which - // is more general but much slower.) - if let Ok(bits) = scalar.to_bits_or_ptr(target_size, &tcx) { - return Some(bits); - } - } - // This is a more general form of the previous case. - value.try_eval_bits(tcx, param_env, ty) - })()?; - let val = val ^ bias; - Some(IntRange { range: val..=val, ty, span }) - } else { - None - } - } - - #[inline] - fn from_range( - tcx: TyCtxt<'tcx>, - lo: u128, - hi: u128, - ty: Ty<'tcx>, - end: &RangeEnd, - span: Span, - ) -> Option> { - if Self::is_integral(ty) { - // Perform a shift if the underlying types are signed, - // which makes the interval arithmetic simpler. - let bias = IntRange::signed_bias(tcx, ty); - let (lo, hi) = (lo ^ bias, hi ^ bias); - let offset = (*end == RangeEnd::Excluded) as u128; - if lo > hi || (lo == hi && *end == RangeEnd::Excluded) { - // This should have been caught earlier by E0030. - bug!("malformed range pattern: {}..={}", lo, (hi - offset)); - } - Some(IntRange { range: lo..=(hi - offset), ty, span }) - } else { - None - } - } - - // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it. - fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 { - match *ty.kind() { - ty::Int(ity) => { - let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; - 1u128 << (bits - 1) - } - _ => 0, - } - } - - fn is_subrange(&self, other: &Self) -> bool { - other.range.start() <= self.range.start() && self.range.end() <= other.range.end() - } - - fn intersection(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Option { - let ty = self.ty; - let (lo, hi) = self.boundaries(); - let (other_lo, other_hi) = other.boundaries(); - if self.treat_exhaustively(tcx) { - if lo <= other_hi && other_lo <= hi { - let span = other.span; - Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span }) - } else { - None - } - } else { - // If the range should not be treated exhaustively, fallback to checking for inclusion. - if self.is_subrange(other) { Some(self.clone()) } else { None } - } - } - - fn suspicious_intersection(&self, other: &Self) -> bool { - // `false` in the following cases: - // 1 ---- // 1 ---------- // 1 ---- // 1 ---- - // 2 ---------- // 2 ---- // 2 ---- // 2 ---- - // - // The following are currently `false`, but could be `true` in the future (#64007): - // 1 --------- // 1 --------- - // 2 ---------- // 2 ---------- - // - // `true` in the following cases: - // 1 ------- // 1 ------- - // 2 -------- // 2 ------- - let (lo, hi) = self.boundaries(); - let (other_lo, other_hi) = other.boundaries(); - lo == other_hi || hi == other_lo - } - - fn to_pat(&self, tcx: TyCtxt<'tcx>) -> Pat<'tcx> { - let (lo, hi) = self.boundaries(); - - let bias = IntRange::signed_bias(tcx, self.ty); - let (lo, hi) = (lo ^ bias, hi ^ bias); - - let ty = ty::ParamEnv::empty().and(self.ty); - let lo_const = ty::Const::from_bits(tcx, lo, ty); - let hi_const = ty::Const::from_bits(tcx, hi, ty); - - let kind = if lo == hi { - PatKind::Constant { value: lo_const } - } else { - PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included }) - }; - - // This is a brand new pattern, so we don't reuse `self.span`. - Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(kind) } - } - - /// For exhaustive integer matching, some constructors are grouped within other constructors - /// (namely integer typed values are grouped within ranges). However, when specialising these - /// constructors, we want to be specialising for the underlying constructors (the integers), not - /// the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would - /// mean creating a separate constructor for every single value in the range, which is clearly - /// impractical. However, observe that for some ranges of integers, the specialisation will be - /// identical across all values in that range (i.e., there are equivalence classes of ranges of - /// constructors based on their `U(S(c, P), S(c, p))` outcome). These classes are grouped by - /// the patterns that apply to them (in the matrix `P`). We can split the range whenever the - /// patterns that apply to that range (specifically: the patterns that *intersect* with that range) - /// change. - /// Our solution, therefore, is to split the range constructor into subranges at every single point - /// the group of intersecting patterns changes (using the method described below). - /// And voilà! We're testing precisely those ranges that we need to, without any exhaustive matching - /// on actual integers. The nice thing about this is that the number of subranges is linear in the - /// number of rows in the matrix (i.e., the number of cases in the `match` statement), so we don't - /// need to be worried about matching over gargantuan ranges. - /// - /// Essentially, given the first column of a matrix representing ranges, looking like the following: - /// - /// |------| |----------| |-------| || - /// |-------| |-------| |----| || - /// |---------| - /// - /// We split the ranges up into equivalence classes so the ranges are no longer overlapping: - /// - /// |--|--|||-||||--||---|||-------| |-|||| || - /// - /// The logic for determining how to split the ranges is fairly straightforward: we calculate - /// boundaries for each interval range, sort them, then create constructors for each new interval - /// between every pair of boundary points. (This essentially sums up to performing the intuitive - /// merging operation depicted above.) - fn split<'p>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - hir_id: Option, - ) -> SmallVec<[Constructor<'tcx>; 1]> { - let ty = pcx.ty; - - /// Represents a border between 2 integers. Because the intervals spanning borders - /// must be able to cover every integer, we need to be able to represent - /// 2^128 + 1 such borders. - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] - enum Border { - JustBefore(u128), - AfterMax, - } - - // A function for extracting the borders of an integer interval. - fn range_borders(r: IntRange<'_>) -> impl Iterator { - let (lo, hi) = r.range.into_inner(); - let from = Border::JustBefore(lo); - let to = match hi.checked_add(1) { - Some(m) => Border::JustBefore(m), - None => Border::AfterMax, - }; - vec![from, to].into_iter() - } - - // Collect the span and range of all the intersecting ranges to lint on likely - // incorrect range patterns. (#63987) - let mut overlaps = vec![]; - let row_len = pcx.matrix.patterns.get(0).map(|r| r.len()).unwrap_or(0); - // `borders` is the set of borders between equivalence classes: each equivalence - // class lies between 2 borders. - let row_borders = pcx - .matrix - .head_ctors(pcx.cx) - .filter_map(|ctor| ctor.as_int_range()) - .filter_map(|range| { - let intersection = self.intersection(pcx.cx.tcx, &range); - let should_lint = self.suspicious_intersection(&range); - if let (Some(range), 1, true) = (&intersection, row_len, should_lint) { - // FIXME: for now, only check for overlapping ranges on simple range - // patterns. Otherwise with the current logic the following is detected - // as overlapping: - // match (10u8, true) { - // (0 ..= 125, false) => {} - // (126 ..= 255, false) => {} - // (0 ..= 255, true) => {} - // } - overlaps.push(range.clone()); - } - intersection - }) - .flat_map(range_borders); - let self_borders = range_borders(self.clone()); - let mut borders: Vec<_> = row_borders.chain(self_borders).collect(); - borders.sort_unstable(); - - self.lint_overlapping_patterns(pcx.cx.tcx, hir_id, ty, overlaps); - - // We're going to iterate through every adjacent pair of borders, making sure that - // each represents an interval of nonnegative length, and convert each such - // interval into a constructor. - borders - .array_windows() - .filter_map(|&pair| match pair { - [Border::JustBefore(n), Border::JustBefore(m)] => { - if n < m { - Some(n..=(m - 1)) - } else { - None - } - } - [Border::JustBefore(n), Border::AfterMax] => Some(n..=u128::MAX), - [Border::AfterMax, _] => None, - }) - .map(|range| IntRange { range, ty, span: pcx.span }) - .map(IntRange) - .collect() - } - - fn lint_overlapping_patterns( - &self, - tcx: TyCtxt<'tcx>, - hir_id: Option, - ty: Ty<'tcx>, - overlaps: Vec>, - ) { - if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { - tcx.struct_span_lint_hir( - lint::builtin::OVERLAPPING_PATTERNS, - hir_id, - self.span, - |lint| { - let mut err = lint.build("multiple patterns covering the same range"); - err.span_label(self.span, "overlapping patterns"); - for int_range in overlaps { - // Use the real type for user display of the ranges: - err.span_label( - int_range.span, - &format!( - "this range overlaps on `{}`", - IntRange { range: int_range.range, ty, span: DUMMY_SP }.to_pat(tcx), - ), - ); - } - err.emit(); - }, - ); - } - } - - /// See `Constructor::is_covered_by` - fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { - if self.intersection(pcx.cx.tcx, other).is_some() { - // Constructor splitting should ensure that all intersections we encounter are actually - // inclusions. - assert!(self.is_subrange(other)); - true - } else { - false - } - } -} - -/// Ignore spans when comparing, they don't carry semantic information as they are only for lints. -impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> { - fn eq(&self, other: &Self) -> bool { - self.range == other.range && self.ty == other.ty - } -} - -// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`. -#[derive(Debug)] -struct MissingConstructors<'tcx> { - all_ctors: SmallVec<[Constructor<'tcx>; 1]>, - used_ctors: Vec>, -} - -impl<'tcx> MissingConstructors<'tcx> { - fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self { - let used_ctors: Vec> = - pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect(); - // Since `all_ctors` never contains wildcards, this won't recurse further. - let all_ctors = - all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx, None)).collect(); - - MissingConstructors { all_ctors, used_ctors } - } - - fn is_empty<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> bool { - self.iter(pcx).next().is_none() - } - - /// Iterate over all_ctors \ used_ctors - fn iter<'a, 'p>( - &'a self, - pcx: PatCtxt<'a, 'p, 'tcx>, - ) -> impl Iterator> + Captures<'p> { - self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.used_ctors)) - } - - /// List the patterns corresponding to the missing constructors. In some cases, instead of - /// listing all constructors of a given type, we prefer to simply report a wildcard. - fn report_patterns<'p>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - is_top_level: bool, - ) -> SmallVec<[Pat<'tcx>; 1]> { - // There are 2 ways we can report a witness here. - // Commonly, we can report all the "free" - // constructors as witnesses, e.g., if we have: - // - // ``` - // enum Direction { N, S, E, W } - // let Direction::N = ...; - // ``` - // - // we can report 3 witnesses: `S`, `E`, and `W`. - // - // However, there is a case where we don't want - // to do this and instead report a single `_` witness: - // if the user didn't actually specify a constructor - // in this arm, e.g., in - // - // ``` - // let x: (Direction, Direction, bool) = ...; - // let (_, _, false) = x; - // ``` - // - // we don't want to show all 16 possible witnesses - // `(, , true)` - we are - // satisfied with `(_, _, true)`. In this case, - // `used_ctors` is empty. - // The exception is: if we are at the top-level, for example in an empty match, we - // sometimes prefer reporting the list of constructors instead of just `_`. - let report_when_all_missing = is_top_level && !IntRange::is_integral(pcx.ty); - if self.used_ctors.is_empty() && !report_when_all_missing { - // All constructors are unused. Report only a wildcard - // rather than each individual constructor. - smallvec![Pat::wildcard_from_ty(pcx.ty)] - } else { - // Construct for each missing constructor a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, we get the pattern `Some(_)`. - self.iter(pcx) - .map(|missing_ctor| { - let fields = Fields::wildcards(pcx, &missing_ctor); - missing_ctor.apply(pcx, fields) - }) - .collect() - } - } -} - -/// Algorithm from . -/// The algorithm from the paper has been modified to correctly handle empty -/// types. The changes are: -/// (0) We don't exit early if the pattern matrix has zero rows. We just -/// continue to recurse over columns. -/// (1) all_constructors will only return constructors that are statically -/// possible. E.g., it will only return `Ok` for `Result`. -/// -/// This finds whether a (row) vector `v` of patterns is 'useful' in relation -/// to a set of such vectors `m` - this is defined as there being a set of -/// inputs that will match `v` but not any of the sets in `m`. -/// -/// All the patterns at each column of the `matrix ++ v` matrix must have the same type. -/// -/// This is used both for reachability checking (if a pattern isn't useful in -/// relation to preceding patterns, it is not reachable) and exhaustiveness -/// checking (if a wildcard pattern is useful in relation to a matrix, the -/// matrix isn't exhaustive). -/// -/// `is_under_guard` is used to inform if the pattern has a guard. If it -/// has one it must not be inserted into the matrix. This shouldn't be -/// relied on for soundness. -crate fn is_useful<'p, 'tcx>( - cx: &MatchCheckCtxt<'p, 'tcx>, - matrix: &Matrix<'p, 'tcx>, - v: &PatStack<'p, 'tcx>, - witness_preference: WitnessPreference, - hir_id: HirId, - is_under_guard: bool, - is_top_level: bool, -) -> Usefulness<'tcx> { - let Matrix { patterns: rows, .. } = matrix; - debug!("is_useful({:#?}, {:#?})", matrix, v); - - // The base case. We are pattern-matching on () and the return value is - // based on whether our matrix has a row or not. - // NOTE: This could potentially be optimized by checking rows.is_empty() - // first and then, if v is non-empty, the return value is based on whether - // the type of the tuple we're checking is inhabited or not. - if v.is_empty() { - return if rows.is_empty() { - Usefulness::new_useful(witness_preference) - } else { - NotUseful - }; - }; - - assert!(rows.iter().all(|r| r.len() == v.len())); - - // If the first pattern is an or-pattern, expand it. - if let Some(vs) = v.expand_or_pat() { - // We expand the or pattern, trying each of its branches in turn and keeping careful track - // of possible unreachable sub-branches. - // - // If two branches have detected some unreachable sub-branches, we need to be careful. If - // they were detected in columns that are not the current one, we want to keep only the - // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last - // `true` is unreachable in the second branch of the first or-pattern, but not otherwise. - // Therefore we don't want to lint that it is unreachable. - // - // ``` - // match (true, true) { - // (true, true) => {} - // (false | true, false | true) => {} - // } - // ``` - // If however the sub-branches come from the current column, they come from the inside of - // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want - // to lint that the last `false` is unreachable. - // ``` - // match None { - // Some(false) => {} - // None | Some(true | false) => {} - // } - // ``` - - let mut matrix = matrix.clone(); - // We keep track of sub-branches separately depending on whether they come from this column - // or from others. - let mut unreachables_this_column: FxHashSet = FxHashSet::default(); - let mut unreachables_other_columns: Vec> = Vec::default(); - // Whether at least one branch is reachable. - let mut any_is_useful = false; - - for v in vs { - let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); - match res { - Useful(unreachables) => { - if let Some((this_column, other_columns)) = unreachables.split_last() { - // We keep the union of unreachables found in the first column. - unreachables_this_column.extend(this_column); - // We keep the intersection of unreachables found in other columns. - if unreachables_other_columns.is_empty() { - unreachables_other_columns = other_columns.to_vec(); - } else { - unreachables_other_columns = unreachables_other_columns - .into_iter() - .zip(other_columns) - .map(|(x, y)| x.intersection(&y).copied().collect()) - .collect(); - } - } - any_is_useful = true; - } - NotUseful => { - unreachables_this_column.insert(v.head().span); - } - UsefulWithWitness(_) => bug!( - "encountered or-pat in the expansion of `_` during exhaustiveness checking" - ), - } - - // If pattern has a guard don't add it to the matrix. - if !is_under_guard { - // We push the already-seen patterns into the matrix in order to detect redundant - // branches like `Some(_) | Some(0)`. - matrix.push(v); - } - } - - return if any_is_useful { - let mut unreachables = if unreachables_other_columns.is_empty() { - let n_columns = v.len(); - (0..n_columns - 1).map(|_| FxHashSet::default()).collect() - } else { - unreachables_other_columns - }; - unreachables.push(unreachables_this_column); - Useful(unreachables) - } else { - NotUseful - }; - } - - // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). - let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); - let pcx = PatCtxt { cx, matrix, ty, span: v.head().span }; - - debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); - - let ret = v - .head_ctor(cx) - .split(pcx, Some(hir_id)) - .into_iter() - .map(|ctor| { - // We cache the result of `Fields::wildcards` because it is used a lot. - let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); - let v = v.pop_head_constructor(&ctor_wild_subpatterns); - let usefulness = - is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); - usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns, is_top_level) - }) - .find(|result| result.is_useful()) - .unwrap_or(NotUseful); - debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); - ret -} - -/// Determines the constructor that the given pattern can be specialized to. -/// Returns `None` in case of a catch-all, which can't be specialized. -fn pat_constructor<'p, 'tcx>( - cx: &MatchCheckCtxt<'p, 'tcx>, - pat: &'p Pat<'tcx>, -) -> Constructor<'tcx> { - match pat.kind.as_ref() { - PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` - PatKind::Binding { .. } | PatKind::Wild => Wildcard, - PatKind::Leaf { .. } | PatKind::Deref { .. } => Single, - &PatKind::Variant { adt_def, variant_index, .. } => { - Variant(adt_def.variants[variant_index].def_id) - } - PatKind::Constant { value } => { - if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value, pat.span) { - IntRange(int_range) - } else { - match pat.ty.kind() { - ty::Float(_) => FloatRange(value, value, RangeEnd::Included), - // In `expand_pattern`, we convert string literals to `&CONST` patterns with - // `CONST` a pattern of type `str`. In truth this contains a constant of type - // `&str`. - ty::Str => Str(value), - // All constants that can be structurally matched have already been expanded - // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are - // opaque. - _ => Opaque, - } - } - } - &PatKind::Range(PatRange { lo, hi, end }) => { - let ty = lo.ty; - if let Some(int_range) = IntRange::from_range( - cx.tcx, - lo.eval_bits(cx.tcx, cx.param_env, lo.ty), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty), - ty, - &end, - pat.span, - ) { - IntRange(int_range) - } else { - FloatRange(lo, hi, end) - } - } - PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { - let array_len = match pat.ty.kind() { - ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)), - ty::Slice(_) => None, - _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), - }; - let prefix = prefix.len() as u64; - let suffix = suffix.len() as u64; - let kind = - if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) }; - Slice(Slice::new(array_len, kind)) - } - PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), - } -} diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 14ed93f112..db817b378f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,6 +1,7 @@ -use super::_match::Usefulness::*; -use super::_match::WitnessPreference::*; -use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}; +use super::usefulness::Usefulness::*; +use super::usefulness::{ + compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, UsefulnessReport, +}; use super::{PatCtxt, PatKind, PatternError}; use rustc_arena::TypedArena; @@ -12,7 +13,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{HirId, Pat}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::config::nightly_options; use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME; use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; use rustc_session::parse::feature_err; @@ -164,45 +164,66 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. self.check_patterns(&arm.pat); + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + self.check_patterns(pat); + } } let mut cx = self.new_cx(scrut.hir_id); + for arm in arms { + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; + check_if_let_guard(&mut cx, &tpat, pat.hir_id); + } + } + let mut have_errors = false; - let inlined_arms: Vec<_> = arms + let arms: Vec<_> = arms .iter() - .map(|hir::Arm { pat, guard, .. }| { - (self.lower_pattern(&mut cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some()) + .map(|hir::Arm { pat, guard, .. }| MatchArm { + pat: self.lower_pattern(&mut cx, pat, &mut have_errors).0, + hir_id: pat.hir_id, + has_guard: guard.is_some(), }) .collect(); - // Bail out early if inlining failed. + // Bail out early if lowering failed. if have_errors { return; } - // Fourth, check for unreachable arms. - let matrix = check_arms(&mut cx, &inlined_arms, source); + let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); + let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); + + // Report unreachable arms. + report_arm_reachability(&cx, &report, source); - // Fifth, check if the match is exhaustive. + // Check if the match is exhaustive. // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, // since an empty matrix can occur when there are arms, if those arms all have guards. - let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); - let is_empty_match = inlined_arms.is_empty(); - check_exhaustive(&mut cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match); + let is_empty_match = arms.is_empty(); + let witnesses = report.non_exhaustiveness_witnesses; + if !witnesses.is_empty() { + non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match); + } } fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option) { let mut cx = self.new_cx(pat.hir_id); let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false); - let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect(); - - let witnesses = match check_not_useful(&mut cx, pattern_ty, &pats, pat.hir_id) { - Ok(_) => return, - Err(err) => err, - }; + let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }]; + let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty); + + // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We + // only care about exhaustiveness here. + let witnesses = report.non_exhaustiveness_witnesses; + if witnesses.is_empty() { + // The pattern is irrefutable. + return; + } let joined_patterns = joined_uncovered_patterns(&witnesses); let mut err = struct_span_err!( @@ -349,23 +370,37 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir:: let msg = match source { hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern", hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern", + hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard", _ => bug!(), }; lint.build(msg).emit() }); } -/// Check for unreachable patterns. -fn check_arms<'p, 'tcx>( +fn check_if_let_guard<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, - arms: &[(&'p super::Pat<'tcx>, HirId, bool)], + pat: &'p super::Pat<'tcx>, + pat_id: HirId, +) { + let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; + let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty); + report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar); + + if report.non_exhaustiveness_witnesses.is_empty() { + // The match is exhaustive, i.e. the if let pattern is irrefutable. + irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar) + } +} + +/// Report unreachable arms, if any. +fn report_arm_reachability<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + report: &UsefulnessReport<'p, 'tcx>, source: hir::MatchSource, -) -> Matrix<'p, 'tcx> { - let mut seen = Matrix::empty(); +) { let mut catchall = None; - for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() { - let v = PatStack::from_pattern(pat); - match is_useful(cx, &seen, &v, LeaveOutWitness, id, has_guard, true) { + for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() { + match is_useful { NotUseful => { match source { hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(), @@ -374,15 +409,20 @@ fn check_arms<'p, 'tcx>( // Check which arm we're on. match arm_index { // The arm with the user-specified pattern. - 0 => unreachable_pattern(cx.tcx, pat.span, id, None), + 0 => unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None), // The arm with the wildcard pattern. - 1 => irrefutable_let_pattern(cx.tcx, pat.span, id, source), + 1 => irrefutable_let_pattern(cx.tcx, arm.pat.span, arm.hir_id, source), _ => bug!(), } } + hir::MatchSource::IfLetGuardDesugar => { + assert_eq!(arm_index, 0); + unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None); + } + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - unreachable_pattern(cx.tcx, pat.span, id, catchall); + unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall); } // Unreachable patterns in try and await expressions occur when one of @@ -390,79 +430,32 @@ fn check_arms<'p, 'tcx>( hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} } } + Useful(unreachables) if unreachables.is_empty() => {} + // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Useful(unreachables) => { - let mut unreachables: Vec<_> = unreachables.into_iter().flatten().collect(); + let mut unreachables: Vec<_> = unreachables.iter().collect(); // Emit lints in the order in which they occur in the file. unreachables.sort_unstable(); for span in unreachables { - unreachable_pattern(cx.tcx, span, id, None); + unreachable_pattern(cx.tcx, span, arm.hir_id, None); } } UsefulWithWitness(_) => bug!(), } - if !has_guard { - seen.push(v); - if catchall.is_none() && pat_is_catchall(pat) { - catchall = Some(pat.span); - } + if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { + catchall = Some(arm.pat.span); } } - seen } -fn check_not_useful<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, - ty: Ty<'tcx>, - matrix: &Matrix<'p, 'tcx>, - hir_id: HirId, -) -> Result<(), Vec>> { - let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty)); - let v = PatStack::from_pattern(wild_pattern); - - // false is given for `is_under_guard` argument due to the wildcard - // pattern not having a guard - match is_useful(cx, matrix, &v, ConstructWitness, hir_id, false, true) { - NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable. - UsefulWithWitness(pats) => Err(if pats.is_empty() { - bug!("Exhaustiveness check returned no witnesses") - } else { - pats.into_iter().map(|w| w.single_pattern()).collect() - }), - Useful(_) => bug!(), - } -} - -fn check_exhaustive<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, +/// Report that a match is not exhaustive. +fn non_exhaustive_match<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, scrut_ty: Ty<'tcx>, sp: Span, - matrix: &Matrix<'p, 'tcx>, - hir_id: HirId, + witnesses: Vec>, is_empty_match: bool, ) { - // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by - // `is_useful` to exhaustively match uninhabited types, so we manually check here. - if is_empty_match && !cx.tcx.features().exhaustive_patterns { - let scrutinee_is_visibly_uninhabited = match scrut_ty.kind() { - ty::Never => true, - ty::Adt(def, _) => { - def.is_enum() - && def.variants.is_empty() - && !cx.is_foreign_non_exhaustive_enum(scrut_ty) - } - _ => false, - }; - if scrutinee_is_visibly_uninhabited { - // If the type *is* uninhabited, an empty match is vacuously exhaustive. - return; - } - } - - let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) { - Ok(_) => return, - Err(err) => err, - }; - let non_empty_enum = match scrut_ty.kind() { ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(), _ => false, @@ -502,7 +495,7 @@ fn check_exhaustive<'p, 'tcx>( so a wildcard `_` is necessary to match exhaustively", scrut_ty, )); - if nightly_options::is_nightly_build() { + if cx.tcx.sess.is_nightly_build() { err.help(&format!( "add `#![feature(precise_pointer_size_matching)]` \ to the crate attributes to enable precise `{}` matching", diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs new file mode 100644 index 0000000000..d79dd97a69 --- /dev/null +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -0,0 +1,1427 @@ +//! [`super::usefulness`] explains most of what is happening in this file. As explained there, +//! values and patterns are made from constructors applied to fields. This file defines a +//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert +//! them from/to patterns. +//! +//! There's one idea that is not detailed in [`super::usefulness`] because the details are not +//! needed there: _constructor splitting_. +//! +//! # Constructor splitting +//! +//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn +//! with all the value constructors that are covered by `c`, and compute usefulness for each. +//! Instead of listing all those constructors (which is intractable), we group those value +//! constructors together as much as possible. Example: +//! +//! ``` +//! match (0, false) { +//! (0 ..=100, true) => {} // `p_1` +//! (50..=150, false) => {} // `p_2` +//! (0 ..=200, _) => {} // `q` +//! } +//! ``` +//! +//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more +//! clever: `0` and `1` for example will match the exact same rows, and return equivalent +//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4 +//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely +//! more tractable. +//! +//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors +//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'` +//! return an equivalent set of witnesses after specializing and computing usefulness. +//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ +//! in their first element. +//! +//! We usually also ask that the `c'` together cover all of the original `c`. However we allow +//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses +//! is empty of not. We use this in the wildcard `_` case. +//! +//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for +//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting +//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]; for slices, see +//! [`SplitVarLenSlice`]. + +use self::Constructor::*; +use self::SliceKind::*; + +use super::compare_const_vals; +use super::usefulness::{MatchCheckCtxt, PatCtxt}; +use super::{FieldPat, Pat, PatKind, PatRange}; + +use rustc_data_structures::captures::Captures; +use rustc_index::vec::Idx; + +use rustc_attr::{SignedInt, UnsignedInt}; +use rustc_hir::def_id::DefId; +use rustc_hir::{HirId, RangeEnd}; +use rustc_middle::mir::interpret::ConstValue; +use rustc_middle::mir::Field; +use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_session::lint; +use rustc_span::{Span, DUMMY_SP}; +use rustc_target::abi::{Integer, Size, VariantIdx}; + +use smallvec::{smallvec, SmallVec}; +use std::cmp::{self, max, min, Ordering}; +use std::iter::{once, IntoIterator}; +use std::ops::RangeInclusive; + +/// An inclusive interval, used for precise integer exhaustiveness checking. +/// `IntRange`s always store a contiguous range. This means that values are +/// encoded such that `0` encodes the minimum value for the integer, +/// regardless of the signedness. +/// For example, the pattern `-128..=127i8` is encoded as `0..=255`. +/// This makes comparisons and arithmetic on interval endpoints much more +/// straightforward. See `signed_bias` for details. +/// +/// `IntRange` is never used to encode an empty range or a "range" that wraps +/// around the (offset) space: i.e., `range.lo <= range.hi`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub(super) struct IntRange { + range: RangeInclusive, +} + +impl IntRange { + #[inline] + fn is_integral(ty: Ty<'_>) -> bool { + matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool) + } + + fn is_singleton(&self) -> bool { + self.range.start() == self.range.end() + } + + fn boundaries(&self) -> (u128, u128) { + (*self.range.start(), *self.range.end()) + } + + #[inline] + fn integral_size_and_signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Size, u128)> { + match *ty.kind() { + ty::Bool => Some((Size::from_bytes(1), 0)), + ty::Char => Some((Size::from_bytes(4), 0)), + ty::Int(ity) => { + let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); + Some((size, 1u128 << (size.bits() as u128 - 1))) + } + ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)), + _ => None, + } + } + + #[inline] + fn from_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &Const<'tcx>, + ) -> Option { + if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) { + let ty = value.ty; + let val = (|| { + if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val { + // For this specific pattern we can skip a lot of effort and go + // straight to the result, after doing a bit of checking. (We + // could remove this branch and just fall through, which + // is more general but much slower.) + if let Ok(bits) = scalar.to_bits_or_ptr(target_size, &tcx) { + return Some(bits); + } + } + // This is a more general form of the previous case. + value.try_eval_bits(tcx, param_env, ty) + })()?; + let val = val ^ bias; + Some(IntRange { range: val..=val }) + } else { + None + } + } + + #[inline] + fn from_range<'tcx>( + tcx: TyCtxt<'tcx>, + lo: u128, + hi: u128, + ty: Ty<'tcx>, + end: &RangeEnd, + ) -> Option { + if Self::is_integral(ty) { + // Perform a shift if the underlying types are signed, + // which makes the interval arithmetic simpler. + let bias = IntRange::signed_bias(tcx, ty); + let (lo, hi) = (lo ^ bias, hi ^ bias); + let offset = (*end == RangeEnd::Excluded) as u128; + if lo > hi || (lo == hi && *end == RangeEnd::Excluded) { + // This should have been caught earlier by E0030. + bug!("malformed range pattern: {}..={}", lo, (hi - offset)); + } + Some(IntRange { range: lo..=(hi - offset) }) + } else { + None + } + } + + // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it. + fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 { + match *ty.kind() { + ty::Int(ity) => { + let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; + 1u128 << (bits - 1) + } + _ => 0, + } + } + + fn is_subrange(&self, other: &Self) -> bool { + other.range.start() <= self.range.start() && self.range.end() <= other.range.end() + } + + fn intersection(&self, other: &Self) -> Option { + let (lo, hi) = self.boundaries(); + let (other_lo, other_hi) = other.boundaries(); + if lo <= other_hi && other_lo <= hi { + Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) }) + } else { + None + } + } + + fn suspicious_intersection(&self, other: &Self) -> bool { + // `false` in the following cases: + // 1 ---- // 1 ---------- // 1 ---- // 1 ---- + // 2 ---------- // 2 ---- // 2 ---- // 2 ---- + // + // The following are currently `false`, but could be `true` in the future (#64007): + // 1 --------- // 1 --------- + // 2 ---------- // 2 ---------- + // + // `true` in the following cases: + // 1 ------- // 1 ------- + // 2 -------- // 2 ------- + let (lo, hi) = self.boundaries(); + let (other_lo, other_hi) = other.boundaries(); + (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() + } + + fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { + let (lo, hi) = self.boundaries(); + + let bias = IntRange::signed_bias(tcx, ty); + let (lo, hi) = (lo ^ bias, hi ^ bias); + + let env = ty::ParamEnv::empty().and(ty); + let lo_const = ty::Const::from_bits(tcx, lo, env); + let hi_const = ty::Const::from_bits(tcx, hi, env); + + let kind = if lo == hi { + PatKind::Constant { value: lo_const } + } else { + PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included }) + }; + + Pat { ty, span: DUMMY_SP, kind: Box::new(kind) } + } + + /// Lint on likely incorrect range patterns (#63987) + pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>( + &self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator, Span)>, + column_count: usize, + hir_id: HirId, + ) { + if self.is_singleton() { + return; + } + + if column_count != 1 { + // FIXME: for now, only check for overlapping ranges on simple range + // patterns. Otherwise with the current logic the following is detected + // as overlapping: + // ``` + // match (0u8, true) { + // (0 ..= 125, false) => {} + // (125 ..= 255, true) => {} + // _ => {} + // } + // ``` + return; + } + + let overlaps: Vec<_> = ctors + .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) + .filter(|(range, _)| self.suspicious_intersection(range)) + .map(|(range, span)| (self.intersection(&range).unwrap(), span)) + .collect(); + + if !overlaps.is_empty() { + pcx.cx.tcx.struct_span_lint_hir( + lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, + hir_id, + pcx.span, + |lint| { + let mut err = lint.build("multiple patterns overlap on their endpoints"); + for (int_range, span) in overlaps { + err.span_label( + span, + &format!( + "this range overlaps on `{}`...", + int_range.to_pat(pcx.cx.tcx, pcx.ty) + ), + ); + } + err.span_label(pcx.span, "... with this range"); + err.note("you likely meant to write mutually exclusive ranges"); + err.emit(); + }, + ); + } + } + + /// See `Constructor::is_covered_by` + fn is_covered_by(&self, other: &Self) -> bool { + if self.intersection(other).is_some() { + // Constructor splitting should ensure that all intersections we encounter are actually + // inclusions. + assert!(self.is_subrange(other)); + true + } else { + false + } + } +} + +/// Represents a border between 2 integers. Because the intervals spanning borders must be able to +/// cover every integer, we need to be able to represent 2^128 + 1 such borders. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum IntBorder { + JustBefore(u128), + AfterMax, +} + +/// A range of integers that is partitioned into disjoint subranges. This does constructor +/// splitting for integer ranges as explained at the top of the file. +/// +/// This is fed multiple ranges, and returns an output that covers the input, but is split so that +/// the only intersections between an output range and a seen range are inclusions. No output range +/// straddles the boundary of one of the inputs. +/// +/// The following input: +/// ``` +/// |-------------------------| // `self` +/// |------| |----------| |----| +/// |-------| |-------| +/// ``` +/// would be iterated over as follows: +/// ``` +/// ||---|--||-|---|---|---|--| +/// ``` +#[derive(Debug, Clone)] +struct SplitIntRange { + /// The range we are splitting + range: IntRange, + /// The borders of ranges we have seen. They are all contained within `range`. This is kept + /// sorted. + borders: Vec, +} + +impl SplitIntRange { + fn new(r: IntRange) -> Self { + SplitIntRange { range: r.clone(), borders: Vec::new() } + } + + /// Internal use + fn to_borders(r: IntRange) -> [IntBorder; 2] { + use IntBorder::*; + let (lo, hi) = r.boundaries(); + let lo = JustBefore(lo); + let hi = match hi.checked_add(1) { + Some(m) => JustBefore(m), + None => AfterMax, + }; + [lo, hi] + } + + /// Add ranges relative to which we split. + fn split(&mut self, ranges: impl Iterator) { + let this_range = &self.range; + let included_ranges = ranges.filter_map(|r| this_range.intersection(&r)); + let included_borders = included_ranges.flat_map(|r| { + let borders = Self::to_borders(r); + once(borders[0]).chain(once(borders[1])) + }); + self.borders.extend(included_borders); + self.borders.sort_unstable(); + } + + /// Iterate over the contained ranges. + fn iter<'a>(&'a self) -> impl Iterator + Captures<'a> { + use IntBorder::*; + + let self_range = Self::to_borders(self.range.clone()); + // Start with the start of the range. + let mut prev_border = self_range[0]; + self.borders + .iter() + .copied() + // End with the end of the range. + .chain(once(self_range[1])) + // List pairs of adjacent borders. + .map(move |border| { + let ret = (prev_border, border); + prev_border = border; + ret + }) + // Skip duplicates. + .filter(|(prev_border, border)| prev_border != border) + // Finally, convert to ranges. + .map(|(prev_border, border)| { + let range = match (prev_border, border) { + (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), + (JustBefore(n), AfterMax) => n..=u128::MAX, + _ => unreachable!(), // Ruled out by the sorting and filtering we did + }; + IntRange { range } + }) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum SliceKind { + /// Patterns of length `n` (`[x, y]`). + FixedLen(u64), + /// Patterns using the `..` notation (`[x, .., y]`). + /// Captures any array constructor of `length >= i + j`. + /// In the case where `array_len` is `Some(_)`, + /// this indicates that we only care about the first `i` and the last `j` values of the array, + /// and everything in between is a wildcard `_`. + VarLen(u64, u64), +} + +impl SliceKind { + fn arity(self) -> u64 { + match self { + FixedLen(length) => length, + VarLen(prefix, suffix) => prefix + suffix, + } + } + + /// Whether this pattern includes patterns of length `other_len`. + fn covers_length(self, other_len: u64) -> bool { + match self { + FixedLen(len) => len == other_len, + VarLen(prefix, suffix) => prefix + suffix <= other_len, + } + } +} + +/// A constructor for array and slice patterns. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(super) struct Slice { + /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`. + array_len: Option, + /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`. + kind: SliceKind, +} + +impl Slice { + fn new(array_len: Option, kind: SliceKind) -> Self { + let kind = match (array_len, kind) { + // If the middle `..` is empty, we effectively have a fixed-length pattern. + (Some(len), VarLen(prefix, suffix)) if prefix + suffix >= len => FixedLen(len), + _ => kind, + }; + Slice { array_len, kind } + } + + fn arity(self) -> u64 { + self.kind.arity() + } + + /// See `Constructor::is_covered_by` + fn is_covered_by(self, other: Self) -> bool { + other.kind.covers_length(self.arity()) + } +} + +/// This computes constructor splitting for variable-length slices, as explained at the top of the +/// file. +/// +/// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, _, +/// _, y] | ...`. The corresponding value constructors are fixed-length array constructors above a +/// given minimum length. We obviously can't list this infinitude of constructors. Thankfully, +/// it turns out that for each finite set of slice patterns, all sufficiently large array lengths +/// are equivalent. +/// +/// Let's look at an example, where we are trying to split the last pattern: +/// ``` +/// match x { +/// [true, true, ..] => {} +/// [.., false, false] => {} +/// [..] => {} +/// } +/// ``` +/// Here are the results of specialization for the first few lengths: +/// ``` +/// // length 0 +/// [] => {} +/// // length 1 +/// [_] => {} +/// // length 2 +/// [true, true] => {} +/// [false, false] => {} +/// [_, _] => {} +/// // length 3 +/// [true, true, _ ] => {} +/// [_, false, false] => {} +/// [_, _, _ ] => {} +/// // length 4 +/// [true, true, _, _ ] => {} +/// [_, _, false, false] => {} +/// [_, _, _, _ ] => {} +/// // length 5 +/// [true, true, _, _, _ ] => {} +/// [_, _, _, false, false] => {} +/// [_, _, _, _, _ ] => {} +/// ``` +/// +/// If we went above length 5, we would simply be inserting more columns full of wildcards in the +/// middle. This means that the set of witnesses for length `l >= 5` if equivalent to the set for +/// any other `l' >= 5`: simply add or remove wildcards in the middle to convert between them. +/// +/// This applies to any set of slice patterns: there will be a length `L` above which all lengths +/// behave the same. This is exactly what we need for constructor splitting. Therefore a +/// variable-length slice can be split into a variable-length slice of minimal length `L`, and many +/// fixed-length slices of lengths `< L`. +/// +/// For each variable-length pattern `p` with a prefix of length `plₚ` and suffix of length `slₚ`, +/// only the first `plₚ` and the last `slₚ` elements are examined. Therefore, as long as `L` is +/// positive (to avoid concerns about empty types), all elements after the maximum prefix length +/// and before the maximum suffix length are not examined by any variable-length pattern, and +/// therefore can be added/removed without affecting them - creating equivalent patterns from any +/// sufficiently-large length. +/// +/// Of course, if fixed-length patterns exist, we must be sure that our length is large enough to +/// miss them all, so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))` +/// +/// `max_slice` below will be made to have arity `L`. +#[derive(Debug)] +struct SplitVarLenSlice { + /// If the type is an array, this is its size. + array_len: Option, + /// The arity of the input slice. + arity: u64, + /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L` + /// described above. + max_slice: SliceKind, +} + +impl SplitVarLenSlice { + fn new(prefix: u64, suffix: u64, array_len: Option) -> Self { + SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) } + } + + /// Pass a set of slices relative to which to split this one. + fn split(&mut self, slices: impl Iterator) { + let (max_prefix_len, max_suffix_len) = match &mut self.max_slice { + VarLen(prefix, suffix) => (prefix, suffix), + FixedLen(_) => return, // No need to split + }; + // We grow `self.max_slice` to be larger than all slices encountered, as described above. + // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that + // `L = max_prefix_len + max_suffix_len`. + let mut max_fixed_len = 0; + for slice in slices { + match slice { + FixedLen(len) => { + max_fixed_len = cmp::max(max_fixed_len, len); + } + VarLen(prefix, suffix) => { + *max_prefix_len = cmp::max(*max_prefix_len, prefix); + *max_suffix_len = cmp::max(*max_suffix_len, suffix); + } + } + } + // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and + // suffix separate. + if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len { + // The subtraction can't overflow thanks to the above check. + // The new `max_prefix_len` is larger than its previous value. + *max_prefix_len = max_fixed_len + 1 - *max_suffix_len; + } + + // We cap the arity of `max_slice` at the array size. + match self.array_len { + Some(len) if self.max_slice.arity() >= len => self.max_slice = FixedLen(len), + _ => {} + } + } + + /// Iterate over the partition of this slice. + fn iter<'a>(&'a self) -> impl Iterator + Captures<'a> { + let smaller_lengths = match self.array_len { + // The only admissible fixed-length slice is one of the array size. Whether `max_slice` + // is fixed-length or variable-length, it will be the only relevant slice to output + // here. + Some(_) => (0..0), // empty range + // We cover all arities in the range `(self.arity..infinity)`. We split that range into + // two: lengths smaller than `max_slice.arity()` are treated independently as + // fixed-lengths slices, and lengths above are captured by `max_slice`. + None => self.arity..self.max_slice.arity(), + }; + smaller_lengths + .map(FixedLen) + .chain(once(self.max_slice)) + .map(move |kind| Slice::new(self.array_len, kind)) + } +} + +/// A value can be decomposed into a constructor applied to some fields. This struct represents +/// the constructor. See also `Fields`. +/// +/// `pat_constructor` retrieves the constructor corresponding to a pattern. +/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a +/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and +/// `Fields`. +#[derive(Clone, Debug, PartialEq)] +pub(super) enum Constructor<'tcx> { + /// The constructor for patterns that have a single constructor, like tuples, struct patterns + /// and fixed-length arrays. + Single, + /// Enum variants. + Variant(DefId), + /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). + IntRange(IntRange), + /// Ranges of floating-point literal values (`2.0..=5.2`). + FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), + /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. + Str(&'tcx ty::Const<'tcx>), + /// Array and slice patterns. + Slice(Slice), + /// Constants that must not be matched structurally. They are treated as black + /// boxes for the purposes of exhaustiveness: we must not inspect them, and they + /// don't count towards making a match exhaustive. + Opaque, + /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used + /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. + NonExhaustive, + /// Stands for constructors that are not seen in the matrix, as explained in the documentation + /// for [`SplitWildcard`]. + Missing, + /// Wildcard pattern. + Wildcard, +} + +impl<'tcx> Constructor<'tcx> { + pub(super) fn is_wildcard(&self) -> bool { + matches!(self, Wildcard) + } + + fn as_int_range(&self) -> Option<&IntRange> { + match self { + IntRange(range) => Some(range), + _ => None, + } + } + + fn as_slice(&self) -> Option { + match self { + Slice(slice) => Some(*slice), + _ => None, + } + } + + fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx { + match *self { + Variant(id) => adt.variant_index_with_id(id), + Single => { + assert!(!adt.is_enum()); + VariantIdx::new(0) + } + _ => bug!("bad constructor {:?} for adt {:?}", self, adt), + } + } + + /// Determines the constructor that the given pattern can be specialized to. + pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>) -> Self { + match pat.kind.as_ref() { + PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` + PatKind::Binding { .. } | PatKind::Wild => Wildcard, + PatKind::Leaf { .. } | PatKind::Deref { .. } => Single, + &PatKind::Variant { adt_def, variant_index, .. } => { + Variant(adt_def.variants[variant_index].def_id) + } + PatKind::Constant { value } => { + if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) { + IntRange(int_range) + } else { + match pat.ty.kind() { + ty::Float(_) => FloatRange(value, value, RangeEnd::Included), + // In `expand_pattern`, we convert string literals to `&CONST` patterns with + // `CONST` a pattern of type `str`. In truth this contains a constant of type + // `&str`. + ty::Str => Str(value), + // All constants that can be structurally matched have already been expanded + // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are + // opaque. + _ => Opaque, + } + } + } + &PatKind::Range(PatRange { lo, hi, end }) => { + let ty = lo.ty; + if let Some(int_range) = IntRange::from_range( + cx.tcx, + lo.eval_bits(cx.tcx, cx.param_env, lo.ty), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + ty, + &end, + ) { + IntRange(int_range) + } else { + FloatRange(lo, hi, end) + } + } + PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { + let array_len = match pat.ty.kind() { + ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)), + ty::Slice(_) => None, + _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), + }; + let prefix = prefix.len() as u64; + let suffix = suffix.len() as u64; + let kind = if slice.is_some() { + VarLen(prefix, suffix) + } else { + FixedLen(prefix + suffix) + }; + Slice(Slice::new(array_len, kind)) + } + PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), + } + } + + /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual + /// constructors (like variants, integers or fixed-sized slices). When specializing for these + /// constructors, we want to be specialising for the actual underlying constructors. + /// Naively, we would simply return the list of constructors they correspond to. We instead are + /// more clever: if there are constructors that we know will behave the same wrt the current + /// matrix, we keep them grouped. For example, all slices of a sufficiently large length + /// will either be all useful or all non-useful with a given matrix. + /// + /// See the branches for details on how the splitting is done. + /// + /// This function may discard some irrelevant constructors if this preserves behavior and + /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the + /// matrix, unless all of them are. + pub(super) fn split<'a>( + &self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator> + Clone, + ) -> SmallVec<[Self; 1]> + where + 'tcx: 'a, + { + debug!("Constructor::split({:#?})", self); + + match self { + Wildcard => { + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx, ctors); + split_wildcard.into_ctors(pcx) + } + // Fast-track if the range is trivial. In particular, we don't do the overlapping + // ranges check. + IntRange(ctor_range) if !ctor_range.is_singleton() => { + let mut split_range = SplitIntRange::new(ctor_range.clone()); + let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()); + split_range.split(int_ranges.cloned()); + split_range.iter().map(IntRange).collect() + } + &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { + let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len); + let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind); + split_self.split(slices); + split_self.iter().map(Slice).collect() + } + // Any other constructor can be used unchanged. + _ => smallvec![self.clone()], + } + } + + /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. + /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, + /// this checks for inclusion. + // We inline because this has a single call site in `Matrix::specialize_constructor`. + #[inline] + pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { + // This must be kept in sync with `is_covered_by_any`. + match (self, other) { + // Wildcards cover anything + (_, Wildcard) => true, + // The missing ctors are not covered by anything in the matrix except wildcards. + (Missing | Wildcard, _) => false, + + (Single, Single) => true, + (Variant(self_id), Variant(other_id)) => self_id == other_id, + + (IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range), + ( + FloatRange(self_from, self_to, self_end), + FloatRange(other_from, other_to, other_end), + ) => { + match ( + compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty), + compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty), + ) { + (Some(to), Some(from)) => { + (from == Ordering::Greater || from == Ordering::Equal) + && (to == Ordering::Less + || (other_end == self_end && to == Ordering::Equal)) + } + _ => false, + } + } + (Str(self_val), Str(other_val)) => { + // FIXME: there's probably a more direct way of comparing for equality + match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty) + { + Some(comparison) => comparison == Ordering::Equal, + None => false, + } + } + (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice), + + // We are trying to inspect an opaque constant. Thus we skip the row. + (Opaque, _) | (_, Opaque) => false, + // Only a wildcard pattern can match the special extra constructor. + (NonExhaustive, _) => false, + + _ => span_bug!( + pcx.span, + "trying to compare incompatible constructors {:?} and {:?}", + self, + other + ), + } + } + + /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is + /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is + /// assumed to have been split from a wildcard. + fn is_covered_by_any<'p>( + &self, + pcx: PatCtxt<'_, 'p, 'tcx>, + used_ctors: &[Constructor<'tcx>], + ) -> bool { + if used_ctors.is_empty() { + return false; + } + + // This must be kept in sync with `is_covered_by`. + match self { + // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. + Single => !used_ctors.is_empty(), + Variant(_) => used_ctors.iter().any(|c| c == self), + IntRange(range) => used_ctors + .iter() + .filter_map(|c| c.as_int_range()) + .any(|other| range.is_covered_by(other)), + Slice(slice) => used_ctors + .iter() + .filter_map(|c| c.as_slice()) + .any(|other| slice.is_covered_by(other)), + // This constructor is never covered by anything else + NonExhaustive => false, + Str(..) | FloatRange(..) | Opaque | Missing | Wildcard => { + span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self) + } + } + } +} + +/// A wildcard constructor that we split relative to the constructors in the matrix, as explained +/// at the top of the file. +/// +/// A constructor that is not present in the matrix rows will only be covered by the rows that have +/// wildcards. Thus we can group all of those constructors together; we call them "missing +/// constructors". Splitting a wildcard would therefore list all present constructors individually +/// (or grouped if they are integers or slices), and then all missing constructors together as a +/// group. +/// +/// However we can go further: since any constructor will match the wildcard rows, and having more +/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors +/// and only try the missing ones. +/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty +/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done +/// in `to_ctors`: in some cases we only return `Missing`. +#[derive(Debug)] +pub(super) struct SplitWildcard<'tcx> { + /// Constructors seen in the matrix. + matrix_ctors: Vec>, + /// All the constructors for this type + all_ctors: SmallVec<[Constructor<'tcx>; 1]>, +} + +impl<'tcx> SplitWildcard<'tcx> { + pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self { + debug!("SplitWildcard::new({:?})", pcx.ty); + let cx = pcx.cx; + let make_range = |start, end| { + IntRange( + // `unwrap()` is ok because we know the type is an integer. + IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(), + ) + }; + // This determines the set of all possible constructors for the type `pcx.ty`. For numbers, + // arrays and slices we use ranges and variable-length slices when appropriate. + // + // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that + // are statically impossible. E.g., for `Option`, we do not include `Some(_)` in the + // returned list of constructors. + // Invariant: this is empty if and only if the type is uninhabited (as determined by + // `cx.is_uninhabited()`). + let all_ctors = match pcx.ty.kind() { + ty::Bool => smallvec![make_range(0, 1)], + ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { + let len = len.eval_usize(cx.tcx, cx.param_env); + if len != 0 && cx.is_uninhabited(sub_ty) { + smallvec![] + } else { + smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))] + } + } + // Treat arrays of a constant but unknown length like slices. + ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { + let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; + smallvec![Slice(Slice::new(None, kind))] + } + ty::Adt(def, substs) if def.is_enum() => { + // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an + // additional "unknown" constructor. + // There is no point in enumerating all possible variants, because the user can't + // actually match against them all themselves. So we always return only the fictitious + // constructor. + // E.g., in an example like: + // + // ``` + // let err: io::ErrorKind = ...; + // match err { + // io::ErrorKind::NotFound => {}, + // } + // ``` + // + // we don't want to show every possible IO error, but instead have only `_` as the + // witness. + let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); + + // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it + // as though it had an "unknown" constructor to avoid exposing its emptiness. The + // exception is if the pattern is at the top level, because we want empty matches to be + // considered exhaustive. + let is_secretly_empty = def.variants.is_empty() + && !cx.tcx.features().exhaustive_patterns + && !pcx.is_top_level; + + if is_secretly_empty || is_declared_nonexhaustive { + smallvec![NonExhaustive] + } else if cx.tcx.features().exhaustive_patterns { + // If `exhaustive_patterns` is enabled, we exclude variants known to be + // uninhabited. + def.variants + .iter() + .filter(|v| { + !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) + .contains(cx.tcx, cx.module) + }) + .map(|v| Variant(v.def_id)) + .collect() + } else { + def.variants.iter().map(|v| Variant(v.def_id)).collect() + } + } + ty::Char => { + smallvec![ + // The valid Unicode Scalar Value ranges. + make_range('\u{0000}' as u128, '\u{D7FF}' as u128), + make_range('\u{E000}' as u128, '\u{10FFFF}' as u128), + ] + } + ty::Int(_) | ty::Uint(_) + if pcx.ty.is_ptr_sized_integral() + && !cx.tcx.features().precise_pointer_size_matching => + { + // `usize`/`isize` are not allowed to be matched exhaustively unless the + // `precise_pointer_size_matching` feature is enabled. So we treat those types like + // `#[non_exhaustive]` enums by returning a special unmatcheable constructor. + smallvec![NonExhaustive] + } + &ty::Int(ity) => { + let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128; + let min = 1u128 << (bits - 1); + let max = min - 1; + smallvec![make_range(min, max)] + } + &ty::Uint(uty) => { + let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); + let max = size.truncate(u128::MAX); + smallvec![make_range(0, max)] + } + // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot + // expose its emptiness. The exception is if the pattern is at the top level, because we + // want empty matches to be considered exhaustive. + ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => { + smallvec![NonExhaustive] + } + ty::Never => smallvec![], + _ if cx.is_uninhabited(pcx.ty) => smallvec![], + ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single], + // This type is one for which we cannot list constructors, like `str` or `f64`. + _ => smallvec![NonExhaustive], + }; + SplitWildcard { matrix_ctors: Vec::new(), all_ctors } + } + + /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't + /// do what you want. + pub(super) fn split<'a>( + &mut self, + pcx: PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator> + Clone, + ) where + 'tcx: 'a, + { + // Since `all_ctors` never contains wildcards, this won't recurse further. + self.all_ctors = + self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); + self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect(); + } + + /// Whether there are any value constructors for this type that are not present in the matrix. + fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool { + self.iter_missing(pcx).next().is_some() + } + + /// Iterate over the constructors for this type that are not present in the matrix. + pub(super) fn iter_missing<'a, 'p>( + &'a self, + pcx: PatCtxt<'a, 'p, 'tcx>, + ) -> impl Iterator> + Captures<'p> { + self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors)) + } + + /// Return the set of constructors resulting from splitting the wildcard. As explained at the + /// top of the file, if any constructors are missing we can ignore the present ones. + fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { + if self.any_missing(pcx) { + // Some constructors are missing, thus we can specialize with the special `Missing` + // constructor, which stands for those constructors that are not seen in the matrix, + // and matches the same rows as any of them (namely the wildcard rows). See the top of + // the file for details. + // However, when all constructors are missing we can also specialize with the full + // `Wildcard` constructor. The difference will depend on what we want in diagnostics. + + // If some constructors are missing, we typically want to report those constructors, + // e.g.: + // ``` + // enum Direction { N, S, E, W } + // let Direction::N = ...; + // ``` + // we can report 3 witnesses: `S`, `E`, and `W`. + // + // However, if the user didn't actually specify a constructor + // in this arm, e.g., in + // ``` + // let x: (Direction, Direction, bool) = ...; + // let (_, _, false) = x; + // ``` + // we don't want to show all 16 possible witnesses `(, , + // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we + // prefer to report just a wildcard `_`. + // + // The exception is: if we are at the top-level, for example in an empty match, we + // sometimes prefer reporting the list of constructors instead of just `_`. + let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); + let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing { + Missing + } else { + Wildcard + }; + return smallvec![ctor]; + } + + // All the constructors are present in the matrix, so we just go through them all. + self.all_ctors + } +} + +/// Some fields need to be explicitly hidden away in certain cases; see the comment above the +/// `Fields` struct. This struct represents such a potentially-hidden field. +#[derive(Debug, Copy, Clone)] +pub(super) enum FilteredField<'p, 'tcx> { + Kept(&'p Pat<'tcx>), + Hidden, +} + +impl<'p, 'tcx> FilteredField<'p, 'tcx> { + fn kept(self) -> Option<&'p Pat<'tcx>> { + match self { + FilteredField::Kept(p) => Some(p), + FilteredField::Hidden => None, + } + } +} + +/// A value can be decomposed into a constructor applied to some fields. This struct represents +/// those fields, generalized to allow patterns in each field. See also `Constructor`. +/// This is constructed from a constructor using [`Fields::wildcards()`]. +/// +/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is +/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically +/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used, +/// so we avoid it when possible to preserve performance. +#[derive(Debug, Clone)] +pub(super) enum Fields<'p, 'tcx> { + /// Lists of patterns that don't contain any filtered fields. + /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and + /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril) + /// have not measured if it really made a difference. + Slice(&'p [Pat<'tcx>]), + Vec(SmallVec<[&'p Pat<'tcx>; 2]>), + /// Patterns where some of the fields need to be hidden. For all intents and purposes we only + /// care about the non-hidden fields. We need to keep the real field index for those fields; + /// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient. + /// `len` counts the number of non-hidden fields + Filtered { + fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>, + len: usize, + }, +} + +impl<'p, 'tcx> Fields<'p, 'tcx> { + /// Internal use. Use `Fields::wildcards()` instead. + /// Must not be used if the pattern is a field of a struct/tuple/variant. + fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self { + Fields::Slice(std::slice::from_ref(pat)) + } + + /// Convenience; internal use. + fn wildcards_from_tys( + cx: &MatchCheckCtxt<'p, 'tcx>, + tys: impl IntoIterator>, + ) -> Self { + let wilds = tys.into_iter().map(Pat::wildcard_from_ty); + let pats = cx.pattern_arena.alloc_from_iter(wilds); + Fields::Slice(pats) + } + + /// Creates a new list of wildcard fields for a given constructor. + pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { + let ty = pcx.ty; + let cx = pcx.cx; + let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); + + let ret = match constructor { + Single | Variant(_) => match ty.kind() { + ty::Tuple(ref fs) => { + Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty())) + } + ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)), + ty::Adt(adt, substs) => { + if adt.is_box() { + // Use T as the sub pattern type of Box. + Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0))) + } else { + let variant = &adt.variants[constructor.variant_index_for_adt(adt)]; + // Whether we must not match the fields of this variant exhaustively. + let is_non_exhaustive = + variant.is_field_list_non_exhaustive() && !adt.did.is_local(); + let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs)); + // In the following cases, we don't need to filter out any fields. This is + // the vast majority of real cases, since uninhabited fields are uncommon. + let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive) + || !field_tys.clone().any(|ty| cx.is_uninhabited(ty)); + + if has_no_hidden_fields { + Fields::wildcards_from_tys(cx, field_tys) + } else { + let mut len = 0; + let fields = variant + .fields + .iter() + .map(|field| { + let ty = field.ty(cx.tcx, substs); + let is_visible = adt.is_enum() + || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(ty); + + // In the cases of either a `#[non_exhaustive]` field list + // or a non-public field, we hide uninhabited fields in + // order not to reveal the uninhabitedness of the whole + // variant. + if is_uninhabited && (!is_visible || is_non_exhaustive) { + FilteredField::Hidden + } else { + len += 1; + FilteredField::Kept(wildcard_from_ty(ty)) + } + }) + .collect(); + Fields::Filtered { fields, len } + } + } + } + _ => bug!("Unexpected type for `Single` constructor: {:?}", ty), + }, + Slice(slice) => match *ty.kind() { + ty::Slice(ty) | ty::Array(ty, _) => { + let arity = slice.arity(); + Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty)) + } + _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), + }, + Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing + | Wildcard => Fields::Slice(&[]), + }; + debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); + ret + } + + /// Apply a constructor to a list of patterns, yielding a new pattern. `self` + /// must have as many elements as this constructor's arity. + /// + /// This is roughly the inverse of `specialize_constructor`. + /// + /// Examples: + /// `ctor`: `Constructor::Single` + /// `ty`: `Foo(u32, u32, u32)` + /// `self`: `[10, 20, _]` + /// returns `Foo(10, 20, _)` + /// + /// `ctor`: `Constructor::Variant(Option::Some)` + /// `ty`: `Option` + /// `self`: `[false]` + /// returns `Some(false)` + pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> { + let subpatterns_and_indices = self.patterns_and_indices(); + let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned(); + + let pat = match ctor { + Single | Variant(_) => match pcx.ty.kind() { + ty::Adt(..) | ty::Tuple(..) => { + // We want the real indices here. + let subpatterns = subpatterns_and_indices + .iter() + .map(|&(field, p)| FieldPat { field, pattern: p.clone() }) + .collect(); + + if let ty::Adt(adt, substs) = pcx.ty.kind() { + if adt.is_enum() { + PatKind::Variant { + adt_def: adt, + substs, + variant_index: ctor.variant_index_for_adt(adt), + subpatterns, + } + } else { + PatKind::Leaf { subpatterns } + } + } else { + PatKind::Leaf { subpatterns } + } + } + // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should + // be careful to reconstruct the correct constant pattern here. However a string + // literal pattern will never be reported as a non-exhaustiveness witness, so we + // can ignore this issue. + ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, + ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", ctor, pcx.ty), + _ => PatKind::Wild, + }, + Slice(slice) => match slice.kind { + FixedLen(_) => { + PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] } + } + VarLen(prefix, _) => { + let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect(); + if slice.array_len.is_some() { + // Improves diagnostics a bit: if the type is a known-size array, instead + // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. + // This is incorrect if the size is not known, since `[_, ..]` captures + // arrays of lengths `>= 1` whereas `[..]` captures any length. + while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() { + prefix.pop(); + } + } + let suffix: Vec<_> = if slice.array_len.is_some() { + // Same as above. + subpatterns.skip_while(Pat::is_wildcard).collect() + } else { + subpatterns.collect() + }; + let wild = Pat::wildcard_from_ty(pcx.ty); + PatKind::Slice { prefix, slice: Some(wild), suffix } + } + }, + &Str(value) => PatKind::Constant { value }, + &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), + IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty), + NonExhaustive => PatKind::Wild, + Wildcard => return Pat::wildcard_from_ty(pcx.ty), + Opaque => bug!("we should not try to apply an opaque constructor"), + Missing => bug!( + "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`" + ), + }; + + Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) } + } + + /// Returns the number of patterns. This is the same as the arity of the constructor used to + /// construct `self`. + pub(super) fn len(&self) -> usize { + match self { + Fields::Slice(pats) => pats.len(), + Fields::Vec(pats) => pats.len(), + Fields::Filtered { len, .. } => *len, + } + } + + /// Returns the list of patterns along with the corresponding field indices. + fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> { + match self { + Fields::Slice(pats) => { + pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect() + } + Fields::Vec(pats) => { + pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect() + } + Fields::Filtered { fields, .. } => { + // Indices must be relative to the full list of patterns + fields + .iter() + .enumerate() + .filter_map(|(i, p)| Some((Field::new(i), p.kept()?))) + .collect() + } + } + } + + /// Returns the list of patterns. + pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> { + match self { + Fields::Slice(pats) => pats.iter().collect(), + Fields::Vec(pats) => pats, + Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(), + } + } + + /// Overrides some of the fields with the provided patterns. Exactly like + /// `replace_fields_indexed`, except that it takes `FieldPat`s as input. + fn replace_with_fieldpats( + &self, + new_pats: impl IntoIterator>, + ) -> Self { + self.replace_fields_indexed( + new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)), + ) + } + + /// Overrides some of the fields with the provided patterns. This is used when a pattern + /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start + /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the + /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice + /// patterns for the same reason. + fn replace_fields_indexed( + &self, + new_pats: impl IntoIterator)>, + ) -> Self { + let mut fields = self.clone(); + if let Fields::Slice(pats) = fields { + fields = Fields::Vec(pats.iter().collect()); + } + + match &mut fields { + Fields::Vec(pats) => { + for (i, pat) in new_pats { + pats[i] = pat + } + } + Fields::Filtered { fields, .. } => { + for (i, pat) in new_pats { + if let FilteredField::Kept(p) = &mut fields[i] { + *p = pat + } + } + } + Fields::Slice(_) => unreachable!(), + } + fields + } + + /// Replaces contained fields with the given list of patterns. There must be `len()` patterns + /// in `pats`. + pub(super) fn replace_fields( + &self, + cx: &MatchCheckCtxt<'p, 'tcx>, + pats: impl IntoIterator>, + ) -> Self { + let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + + match self { + Fields::Filtered { fields, len } => { + let mut pats = pats.iter(); + let mut fields = fields.clone(); + for f in &mut fields { + if let FilteredField::Kept(p) = f { + // We take one input pattern for each `Kept` field, in order. + *p = pats.next().unwrap(); + } + } + Fields::Filtered { fields, len: *len } + } + _ => Fields::Slice(pats), + } + } + + /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern + /// that is compatible with the constructor used to build `self`. + /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that + /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern + /// provided to this function fills some of the fields with non-wildcards. + /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call + /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _, + /// _, _]`. + /// ```rust + /// let x: [Option; 4] = foo(); + /// match x { + /// [Some(0), ..] => {} + /// } + /// ``` + /// This is guaranteed to preserve the number of patterns in `self`. + pub(super) fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self { + match pat.kind.as_ref() { + PatKind::Deref { subpattern } => { + assert_eq!(self.len(), 1); + Fields::from_single_pattern(subpattern) + } + PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { + self.replace_with_fieldpats(subpatterns) + } + PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => { + // Number of subpatterns for the constructor + let ctor_arity = self.len(); + + // Replace the prefix and the suffix with the given patterns, leaving wildcards in + // the middle if there was a subslice pattern `..`. + let prefix = prefix.iter().enumerate(); + let suffix = + suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p)); + self.replace_fields_indexed(prefix.chain(suffix)) + } + _ => self.clone(), + } + } +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index db0ecd701b..7e9a3a3727 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -1,8 +1,9 @@ //! Validation of patterns/matches. -mod _match; mod check_match; mod const_to_pat; +mod deconstruct_pat; +mod usefulness; pub(crate) use self::check_match::check_match; diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs new file mode 100644 index 0000000000..83fee380cc --- /dev/null +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -0,0 +1,1070 @@ +//! Note: tests specific to this file can be found in: +//! +//! - `ui/pattern/usefulness` +//! - `ui/or-patterns` +//! - `ui/consts/const_in_pattern` +//! - `ui/rfc-2008-non-exhaustive` +//! - `ui/half-open-range-patterns` +//! - probably many others +//! +//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific +//! reason not to, for example if they depend on a particular feature like `or_patterns`. +//! +//! ----- +//! +//! This file includes the logic for exhaustiveness and reachability checking for pattern-matching. +//! Specifically, given a list of patterns for a type, we can tell whether: +//! (a) each pattern is reachable (reachability) +//! (b) the patterns cover every possible value for the type (exhaustiveness) +//! +//! The algorithm implemented here is a modified version of the one described in [this +//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized +//! it to accommodate the variety of patterns that Rust supports. We thus explain our version here, +//! without being as rigorous. +//! +//! +//! # Summary +//! +//! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful* +//! relative to another pattern `p` of the same type if there is a value that is matched by `q` and +//! not matched by `p`. This generalizes to many `p`s: `q` is useful w.r.t. a list of patterns +//! `p_1 .. p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write +//! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this +//! file is to compute it efficiently. +//! +//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it +//! is useful w.r.t. the patterns above it: +//! ```rust +//! match x { +//! Some(_) => ..., +//! None => ..., // reachable: `None` is matched by this but not the branch above +//! Some(0) => ..., // unreachable: all the values this matches are already matched by +//! // `Some(_)` above +//! } +//! ``` +//! +//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_` +//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness` +//! are used to tell the user which values are missing. +//! ```rust +//! match x { +//! Some(0) => ..., +//! None => ..., +//! // not exhaustive: `_` is useful because it matches `Some(1)` +//! } +//! ``` +//! +//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes +//! reachability for each match branch and exhaustiveness for the whole match. +//! +//! +//! # Constructors and fields +//! +//! Note: we will often abbreviate "constructor" as "ctor". +//! +//! The idea that powers everything that is done in this file is the following: a (matcheable) +//! value is made from a constructor applied to a number of subvalues. Examples of constructors are +//! `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor for a struct +//! `Foo`), and `2` (the constructor for the number `2`). This is natural when we think of +//! pattern-matching, and this is the basis for what follows. +//! +//! Some of the ctors listed above might feel weird: `None` and `2` don't take any arguments. +//! That's ok: those are ctors that take a list of 0 arguments; they are the simplest case of +//! ctors. We treat `2` as a ctor because `u64` and other number types behave exactly like a huge +//! `enum`, with one variant for each number. This allows us to see any matcheable value as made up +//! from a tree of ctors, each having a set number of children. For example: `Foo { bar: None, +//! baz: Ok(0) }` is made from 4 different ctors, namely `Foo{..}`, `None`, `Ok` and `0`. +//! +//! This idea can be extended to patterns: they are also made from constructors applied to fields. +//! A pattern for a given type is allowed to use all the ctors for values of that type (which we +//! call "value constructors"), but there are also pattern-only ctors. The most important one is +//! the wildcard (`_`), and the others are integer ranges (`0..=10`), variable-length slices (`[x, +//! ..]`), and or-patterns (`Ok(0) | Err(_)`). Examples of valid patterns are `42`, `Some(_)`, `Foo +//! { bar: Some(0) | None, baz: _ }`. Note that a binder in a pattern (e.g. `Some(x)`) matches the +//! same values as a wildcard (e.g. `Some(_)`), so we treat both as wildcards. +//! +//! From this deconstruction we can compute whether a given value matches a given pattern; we +//! simply look at ctors one at a time. Given a pattern `p` and a value `v`, we want to compute +//! `matches!(v, p)`. It's mostly straightforward: we compare the head ctors and when they match +//! we compare their fields recursively. A few representative examples: +//! +//! - `matches!(v, _) := true` +//! - `matches!((v0, v1), (p0, p1)) := matches!(v0, p0) && matches!(v1, p1)` +//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)` +//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)` +//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants) +//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)` +//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths) +//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)` +//! - `matches!(v, p0 | p1) := matches!(v, p0) || matches!(v, p1)` +//! +//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] module. +//! +//! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type. +//! For example a value of type `Rc` can't be deconstructed that way, and `&str` has an +//! infinitude of constructors. There are also subtleties with visibility of fields and +//! uninhabitedness and various other things. The constructors idea can be extended to handle most +//! of these subtleties though; caveats are documented where relevant throughout the code. +//! +//! Whether constructors cover each other is computed by [`Constructor::is_covered_by`]. +//! +//! +//! # Specialization +//! +//! Recall that we wish to compute `usefulness(p_1 .. p_n, q)`: given a list of patterns `p_1 .. +//! p_n` and a pattern `q`, all of the same type, we want to find a list of values (called +//! "witnesses") that are matched by `q` and by none of the `p_i`. We obviously don't just +//! enumerate all possible values. From the discussion above we see that we can proceed +//! ctor-by-ctor: for each value ctor of the given type, we ask "is there a value that starts with +//! this constructor and matches `q` and none of the `p_i`?". As we saw above, there's a lot we can +//! say from knowing only the first constructor of our candidate value. +//! +//! Let's take the following example: +//! ``` +//! match x { +//! Enum::Variant1(_) => {} // `p1` +//! Enum::Variant2(None, 0) => {} // `p2` +//! Enum::Variant2(Some(_), 0) => {} // `q` +//! } +//! ``` +//! +//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`. +//! If `v = Variant2(v0, v1)` however, whether or not it matches `p2` and `q` will depend on `v0` +//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple +//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match: +//! +//! ``` +//! match x { +//! (None, 0) => {} // `p2'` +//! (Some(_), 0) => {} // `q'` +//! } +//! ``` +//! +//! This motivates a new step in computing usefulness, that we call _specialization_. +//! Specialization consist of filtering a list of patterns for those that match a constructor, and +//! then looking into the constructor's fields. This enables usefulness to be computed recursively. +//! +//! Instead of acting on a single pattern in each row, we will consider a list of patterns for each +//! row, and we call such a list a _pattern-stack_. The idea is that we will specialize the +//! leftmost pattern, which amounts to popping the constructor and pushing its fields, which feels +//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`. +//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's +//! happening: +//! ``` +//! [Enum::Variant1(_)] +//! [Enum::Variant2(None, 0)] +//! [Enum::Variant2(Some(_), 0)] +//! //==>> specialize with `Variant2` +//! [None, 0] +//! [Some(_), 0] +//! //==>> specialize with `Some` +//! [_, 0] +//! //==>> specialize with `true` (say the type was `bool`) +//! [0] +//! //==>> specialize with `0` +//! [] +//! ``` +//! +//! The function `specialize(c, p)` takes a value constructor `c` and a pattern `p`, and returns 0 +//! or more pattern-stacks. If `c` does not match the head constructor of `p`, it returns nothing; +//! otherwise if returns the fields of the constructor. This only returns more than one +//! pattern-stack if `p` has a pattern-only constructor. +//! +//! - Specializing for the wrong constructor returns nothing +//! +//! `specialize(None, Some(p0)) := []` +//! +//! - Specializing for the correct constructor returns a single row with the fields +//! +//! `specialize(Variant1, Variant1(p0, p1, p2)) := [[p0, p1, p2]]` +//! +//! `specialize(Foo{..}, Foo { bar: p0, baz: p1 }) := [[p0, p1]]` +//! +//! - For or-patterns, we specialize each branch and concatenate the results +//! +//! `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)` +//! +//! - We treat the other pattern constructors as if they were a large or-pattern of all the +//! possibilities: +//! +//! `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)` +//! +//! `specialize(c, 1..=100) := specialize(c, 1 | ... | 100)` +//! +//! `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)` +//! +//! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See +//! the discussion about constructor splitting in [`super::deconstruct_pat`]. +//! +//! +//! We then extend this function to work with pattern-stacks as input, by acting on the first +//! column and keeping the other columns untouched. +//! +//! Specialization for the whole matrix is done in [`Matrix::specialize_constructor`]. Note that +//! or-patterns in the first column are expanded before being stored in the matrix. Specialization +//! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and +//! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the +//! [`Fields`] struct. +//! +//! +//! # Computing usefulness +//! +//! We now have all we need to compute usefulness. The inputs to usefulness are a list of +//! pattern-stacks `p_1 ... p_n` (one per row), and a new pattern_stack `q`. The paper and this +//! file calls the list of patstacks a _matrix_. They must all have the same number of columns and +//! the patterns in a given column must all have the same type. `usefulness` returns a (possibly +//! empty) list of witnesses of usefulness. These witnesses will also be pattern-stacks. +//! +//! - base case: `n_columns == 0`. +//! Since a pattern-stack functions like a tuple of patterns, an empty one functions like the +//! unit type. Thus `q` is useful iff there are no rows above it, i.e. if `n == 0`. +//! +//! - inductive case: `n_columns > 0`. +//! We need a way to list the constructors we want to try. We will be more clever in the next +//! section but for now assume we list all value constructors for the type of the first column. +//! +//! - for each such ctor `c`: +//! +//! - for each `q'` returned by `specialize(c, q)`: +//! +//! - we compute `usefulness(specialize(c, p_1) ... specialize(c, p_n), q')` +//! +//! - for each witness found, we revert specialization by pushing the constructor `c` on top. +//! +//! - We return the concatenation of all the witnesses found, if any. +//! +//! Example: +//! ``` +//! [Some(true)] // p_1 +//! [None] // p_2 +//! [Some(_)] // q +//! //==>> try `None`: `specialize(None, q)` returns nothing +//! //==>> try `Some`: `specialize(Some, q)` returns a single row +//! [true] // p_1' +//! [_] // q' +//! //==>> try `true`: `specialize(true, q')` returns a single row +//! [] // p_1'' +//! [] // q'' +//! //==>> base case; `n != 0` so `q''` is not useful. +//! //==>> go back up a step +//! [true] // p_1' +//! [_] // q' +//! //==>> try `false`: `specialize(false, q')` returns a single row +//! [] // q'' +//! //==>> base case; `n == 0` so `q''` is useful. We return the single witness `[]` +//! witnesses: +//! [] +//! //==>> undo the specialization with `false` +//! witnesses: +//! [false] +//! //==>> undo the specialization with `Some` +//! witnesses: +//! [Some(false)] +//! //==>> we have tried all the constructors. The output is the single witness `[Some(false)]`. +//! ``` +//! +//! This computation is done in [`is_useful`]. In practice we don't care about the list of +//! witnesses when computing reachability; we only need to know whether any exist. We do keep the +//! witnesses when computing exhaustiveness to report them to the user. +//! +//! +//! # Making usefulness tractable: constructor splitting +//! +//! We're missing one last detail: which constructors do we list? Naively listing all value +//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The +//! first obvious insight is that we only want to list constructors that are covered by the head +//! constructor of `q`. If it's a value constructor, we only try that one. If it's a pattern-only +//! constructor, we use the final clever idea for this algorithm: _constructor splitting_, where we +//! group together constructors that behave the same. +//! +//! The details are not necessary to understand this file, so we explain them in +//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function. + +use self::Usefulness::*; +use self::WitnessPreference::*; + +use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; +use super::{Pat, PatKind}; +use super::{PatternFoldable, PatternFolder}; + +use rustc_data_structures::captures::Captures; +use rustc_data_structures::sync::OnceCell; + +use rustc_arena::TypedArena; +use rustc_hir::def_id::DefId; +use rustc_hir::HirId; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::Span; + +use smallvec::{smallvec, SmallVec}; +use std::fmt; +use std::iter::{FromIterator, IntoIterator}; + +crate struct MatchCheckCtxt<'a, 'tcx> { + crate tcx: TyCtxt<'tcx>, + /// The module in which the match occurs. This is necessary for + /// checking inhabited-ness of types because whether a type is (visibly) + /// inhabited can depend on whether it was defined in the current module or + /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty + /// outside its module and should not be matchable with an empty match statement. + crate module: DefId, + crate param_env: ty::ParamEnv<'tcx>, + crate pattern_arena: &'a TypedArena>, +} + +impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { + pub(super) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { + if self.tcx.features().exhaustive_patterns { + self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env) + } else { + false + } + } + + /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. + pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Adt(def, ..) => { + def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local() + } + _ => false, + } + } +} + +#[derive(Copy, Clone)] +pub(super) struct PatCtxt<'a, 'p, 'tcx> { + pub(super) cx: &'a MatchCheckCtxt<'p, 'tcx>, + /// Type of the current column under investigation. + pub(super) ty: Ty<'tcx>, + /// Span of the current pattern under investigation. + pub(super) span: Span, + /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a + /// subpattern. + pub(super) is_top_level: bool, +} + +crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> { + LiteralExpander.fold_pattern(&pat) +} + +struct LiteralExpander; + +impl<'tcx> PatternFolder<'tcx> for LiteralExpander { + fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { + debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); + match (pat.ty.kind(), pat.kind.as_ref()) { + (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self), + (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self), + (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => { + // Treat string literal patterns as deref patterns to a `str` constant, i.e. + // `&CONST`. This expands them like other const patterns. This could have been done + // in `const_to_pat`, but that causes issues with the rest of the matching code. + let mut new_pat = pat.super_fold_with(self); + // Make a fake const pattern of type `str` (instead of `&str`). That the carried + // constant value still knows it is of type `&str`. + new_pat.ty = t; + Pat { + kind: Box::new(PatKind::Deref { subpattern: new_pat }), + span: pat.span, + ty: pat.ty, + } + } + _ => pat.super_fold_with(self), + } + } +} + +impl<'tcx> Pat<'tcx> { + pub(super) fn is_wildcard(&self) -> bool { + matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) + } +} + +/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` +/// works well. +#[derive(Debug, Clone)] +struct PatStack<'p, 'tcx> { + pats: SmallVec<[&'p Pat<'tcx>; 2]>, + /// Cache for the constructor of the head + head_ctor: OnceCell>, +} + +impl<'p, 'tcx> PatStack<'p, 'tcx> { + fn from_pattern(pat: &'p Pat<'tcx>) -> Self { + Self::from_vec(smallvec![pat]) + } + + fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self { + PatStack { pats: vec, head_ctor: OnceCell::new() } + } + + fn is_empty(&self) -> bool { + self.pats.is_empty() + } + + fn len(&self) -> usize { + self.pats.len() + } + + fn head(&self) -> &'p Pat<'tcx> { + self.pats[0] + } + + fn head_ctor<'a>(&'a self, cx: &MatchCheckCtxt<'p, 'tcx>) -> &'a Constructor<'tcx> { + self.head_ctor.get_or_init(|| Constructor::from_pat(cx, self.head())) + } + + fn iter(&self) -> impl Iterator> { + self.pats.iter().copied() + } + + // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`. + fn expand_or_pat(&self) -> Option> { + if self.is_empty() { + None + } else if let PatKind::Or { pats } = &*self.head().kind { + Some( + pats.iter() + .map(|pat| { + let mut new_patstack = PatStack::from_pattern(pat); + new_patstack.pats.extend_from_slice(&self.pats[1..]); + new_patstack + }) + .collect(), + ) + } else { + None + } + } + + /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations. + /// + /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing + /// fields filled with wild patterns. + /// + /// This is roughly the inverse of `Constructor::apply`. + fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> { + // We pop the head pattern and push the new fields extracted from the arguments of + // `self.head()`. + let mut new_fields = + ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns(); + new_fields.extend_from_slice(&self.pats[1..]); + PatStack::from_vec(new_fields) + } +} + +impl<'p, 'tcx> Default for PatStack<'p, 'tcx> { + fn default() -> Self { + Self::from_vec(smallvec![]) + } +} + +impl<'p, 'tcx> PartialEq for PatStack<'p, 'tcx> { + fn eq(&self, other: &Self) -> bool { + self.pats == other.pats + } +} + +impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { + fn from_iter(iter: T) -> Self + where + T: IntoIterator>, + { + Self::from_vec(iter.into_iter().collect()) + } +} + +/// A 2D matrix. +#[derive(Clone, PartialEq)] +pub(super) struct Matrix<'p, 'tcx> { + patterns: Vec>, +} + +impl<'p, 'tcx> Matrix<'p, 'tcx> { + fn empty() -> Self { + Matrix { patterns: vec![] } + } + + /// Number of columns of this matrix. `None` is the matrix is empty. + pub(super) fn column_count(&self) -> Option { + self.patterns.get(0).map(|r| r.len()) + } + + /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. + fn push(&mut self, row: PatStack<'p, 'tcx>) { + if let Some(rows) = row.expand_or_pat() { + for row in rows { + // We recursively expand the or-patterns of the new rows. + // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`. + self.push(row) + } + } else { + self.patterns.push(row); + } + } + + /// Iterate over the first component of each row + fn heads<'a>(&'a self) -> impl Iterator> + Captures<'p> { + self.patterns.iter().map(|r| r.head()) + } + + /// Iterate over the first constructor of each row. + pub(super) fn head_ctors<'a>( + &'a self, + cx: &'a MatchCheckCtxt<'p, 'tcx>, + ) -> impl Iterator> + Captures<'p> + Clone { + self.patterns.iter().map(move |r| r.head_ctor(cx)) + } + + /// Iterate over the first constructor and the corresponding span of each row. + pub(super) fn head_ctors_and_spans<'a>( + &'a self, + cx: &'a MatchCheckCtxt<'p, 'tcx>, + ) -> impl Iterator, Span)> + Captures<'p> { + self.patterns.iter().map(move |r| (r.head_ctor(cx), r.head().span)) + } + + /// This computes `S(constructor, self)`. See top of the file for explanations. + fn specialize_constructor( + &self, + pcx: PatCtxt<'_, 'p, 'tcx>, + ctor: &Constructor<'tcx>, + ctor_wild_subpatterns: &Fields<'p, 'tcx>, + ) -> Matrix<'p, 'tcx> { + self.patterns + .iter() + .filter(|r| ctor.is_covered_by(pcx, r.head_ctor(pcx.cx))) + .map(|r| r.pop_head_constructor(ctor_wild_subpatterns)) + .collect() + } +} + +/// Pretty-printer for matrices of patterns, example: +/// +/// ```text +/// +++++++++++++++++++++++++++++ +/// + _ + [] + +/// +++++++++++++++++++++++++++++ +/// + true + [First] + +/// +++++++++++++++++++++++++++++ +/// + true + [Second(true)] + +/// +++++++++++++++++++++++++++++ +/// + false + [_] + +/// +++++++++++++++++++++++++++++ +/// + _ + [_, _, tail @ ..] + +/// +++++++++++++++++++++++++++++ +/// ``` +impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "\n")?; + + let Matrix { patterns: m, .. } = self; + let pretty_printed_matrix: Vec> = + m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); + + let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0); + assert!(m.iter().all(|row| row.len() == column_count)); + let column_widths: Vec = (0..column_count) + .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)) + .collect(); + + let total_width = column_widths.iter().cloned().sum::() + column_count * 3 + 1; + let br = "+".repeat(total_width); + write!(f, "{}\n", br)?; + for row in pretty_printed_matrix { + write!(f, "+")?; + for (column, pat_str) in row.into_iter().enumerate() { + write!(f, " ")?; + write!(f, "{:1$}", pat_str, column_widths[column])?; + write!(f, " +")?; + } + write!(f, "\n")?; + write!(f, "{}\n", br)?; + } + Ok(()) + } +} + +impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { + fn from_iter(iter: T) -> Self + where + T: IntoIterator>, + { + let mut matrix = Matrix::empty(); + for x in iter { + // Using `push` ensures we correctly expand or-patterns. + matrix.push(x); + } + matrix + } +} + +/// Represents a set of `Span`s closed under the containment relation. That is, if a `Span` is +/// contained in the set then all `Span`s contained in it are also implicitly contained in the set. +/// In particular this means that when intersecting two sets, taking the intersection of some span +/// and one of its subspans returns the subspan, whereas a simple `HashSet` would have returned an +/// empty intersection. +/// It is assumed that two spans don't overlap without one being contained in the other; in other +/// words, that the inclusion structure forms a tree and not a DAG. +/// Intersection is not very efficient. It compares everything pairwise. If needed it could be made +/// faster by sorting the `Span`s and merging cleverly. +#[derive(Debug, Clone, Default)] +pub(crate) struct SpanSet { + /// The minimal set of `Span`s required to represent the whole set. If A and B are `Span`s in + /// the `SpanSet`, and A is a descendant of B, then only B will be in `root_spans`. + /// Invariant: the spans are disjoint. + root_spans: Vec, +} + +impl SpanSet { + /// Creates an empty set. + fn new() -> Self { + Self::default() + } + + /// Tests whether the set is empty. + pub(crate) fn is_empty(&self) -> bool { + self.root_spans.is_empty() + } + + /// Iterate over the disjoint list of spans at the roots of this set. + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + Captures<'a> { + self.root_spans.iter().copied() + } + + /// Tests whether the set contains a given Span. + fn contains(&self, span: Span) -> bool { + self.iter().any(|root_span| root_span.contains(span)) + } + + /// Add a span to the set if we know the span has no intersection in this set. + fn push_nonintersecting(&mut self, new_span: Span) { + self.root_spans.push(new_span); + } + + fn intersection_mut(&mut self, other: &Self) { + if self.is_empty() || other.is_empty() { + *self = Self::new(); + return; + } + // Those that were in `self` but not contained in `other` + let mut leftover = SpanSet::new(); + // We keep the elements in `self` that are also in `other`. + self.root_spans.retain(|span| { + let retain = other.contains(*span); + if !retain { + leftover.root_spans.push(*span); + } + retain + }); + // We keep the elements in `other` that are also in the original `self`. You might think + // this is not needed because `self` already contains the intersection. But those aren't + // just sets of things. If `self = [a]`, `other = [b]` and `a` contains `b`, then `b` + // belongs in the intersection but we didn't catch it in the filtering above. We look at + // `leftover` instead of the full original `self` to avoid duplicates. + for span in other.iter() { + if leftover.contains(span) { + self.root_spans.push(span); + } + } + } +} + +#[derive(Clone, Debug)] +crate enum Usefulness<'tcx> { + /// Pontentially carries a set of sub-branches that have been found to be unreachable. Used + /// only in the presence of or-patterns, otherwise it stays empty. + Useful(SpanSet), + /// Carries a list of witnesses of non-exhaustiveness. + UsefulWithWitness(Vec>), + NotUseful, +} + +impl<'tcx> Usefulness<'tcx> { + fn new_useful(preference: WitnessPreference) -> Self { + match preference { + ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]), + LeaveOutWitness => Useful(Default::default()), + } + } + + /// When trying several branches and each returns a `Usefulness`, we need to combine the + /// results together. + fn merge(usefulnesses: impl Iterator) -> Self { + // If we have detected some unreachable sub-branches, we only want to keep them when they + // were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable + // in the second branch of the first or-pattern, but not otherwise. Therefore we don't want + // to lint that it is unreachable. + // ``` + // match (true, true) { + // (true, true) => {} + // (false | true, false | true) => {} + // } + // ``` + // Here however we _do_ want to lint that the last `false` is unreachable. So we don't want + // to intersect the spans that come directly from the or-pattern, since each branch of the + // or-pattern brings a new disjoint pattern. + // ``` + // match None { + // Some(false) => {} + // None | Some(true | false) => {} + // } + // ``` + + // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the + // sets are only non-empty in the presence of or-patterns. + let mut unreachables: Option = None; + // Witnesses of usefulness, if any. + let mut witnesses = Vec::new(); + + for u in usefulnesses { + match u { + Useful(spans) if spans.is_empty() => { + // Once we reach the empty set, more intersections won't change the result. + return Useful(SpanSet::new()); + } + Useful(spans) => { + if let Some(unreachables) = &mut unreachables { + if !unreachables.is_empty() { + unreachables.intersection_mut(&spans); + } + if unreachables.is_empty() { + return Useful(SpanSet::new()); + } + } else { + unreachables = Some(spans); + } + } + NotUseful => {} + UsefulWithWitness(wits) => { + witnesses.extend(wits); + } + } + } + + if !witnesses.is_empty() { + UsefulWithWitness(witnesses) + } else if let Some(unreachables) = unreachables { + Useful(unreachables) + } else { + NotUseful + } + } + + /// After calculating the usefulness for a branch of an or-pattern, call this to make this + /// usefulness mergeable with those from the other branches. + fn unsplit_or_pat(self, this_span: Span, or_pat_spans: &[Span]) -> Self { + match self { + Useful(mut spans) => { + // We register the spans of the other branches of this or-pattern as being + // unreachable from this one. This ensures that intersecting together the sets of + // spans returns what we want. + // Until we optimize `SpanSet` however, intersecting this entails a number of + // comparisons quadratic in the number of branches. + for &span in or_pat_spans { + if span != this_span { + spans.push_nonintersecting(span); + } + } + Useful(spans) + } + x => x, + } + } + + /// After calculating usefulness after a specialization, call this to recontruct a usefulness + /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged + /// with the results of specializing with the other constructors. + fn apply_constructor<'p>( + self, + pcx: PatCtxt<'_, 'p, 'tcx>, + matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors + ctor: &Constructor<'tcx>, + ctor_wild_subpatterns: &Fields<'p, 'tcx>, + ) -> Self { + match self { + UsefulWithWitness(witnesses) => { + let new_witnesses = if matches!(ctor, Constructor::Missing) { + let mut split_wildcard = SplitWildcard::new(pcx); + split_wildcard.split(pcx, matrix.head_ctors(pcx.cx)); + // Construct for each missing constructor a "wild" version of this + // constructor, that matches everything that can be built with + // it. For example, if `ctor` is a `Constructor::Variant` for + // `Option::Some`, we get the pattern `Some(_)`. + let new_patterns: Vec<_> = split_wildcard + .iter_missing(pcx) + .map(|missing_ctor| { + Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor) + }) + .collect(); + witnesses + .into_iter() + .flat_map(|witness| { + new_patterns.iter().map(move |pat| { + let mut witness = witness.clone(); + witness.0.push(pat.clone()); + witness + }) + }) + .collect() + } else { + witnesses + .into_iter() + .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns)) + .collect() + }; + UsefulWithWitness(new_witnesses) + } + x => x, + } + } +} + +#[derive(Copy, Clone, Debug)] +enum WitnessPreference { + ConstructWitness, + LeaveOutWitness, +} + +/// A witness of non-exhaustiveness for error reporting, represented +/// as a list of patterns (in reverse order of construction) with +/// wildcards inside to represent elements that can take any inhabitant +/// of the type as a value. +/// +/// A witness against a list of patterns should have the same types +/// and length as the pattern matched against. Because Rust `match` +/// is always against a single pattern, at the end the witness will +/// have length 1, but in the middle of the algorithm, it can contain +/// multiple patterns. +/// +/// For example, if we are constructing a witness for the match against +/// +/// ``` +/// struct Pair(Option<(u32, u32)>, bool); +/// +/// match (p: Pair) { +/// Pair(None, _) => {} +/// Pair(_, false) => {} +/// } +/// ``` +/// +/// We'll perform the following steps: +/// 1. Start with an empty witness +/// `Witness(vec![])` +/// 2. Push a witness `true` against the `false` +/// `Witness(vec![true])` +/// 3. Push a witness `Some(_)` against the `None` +/// `Witness(vec![true, Some(_)])` +/// 4. Apply the `Pair` constructor to the witnesses +/// `Witness(vec![Pair(Some(_), true)])` +/// +/// The final `Pair(Some(_), true)` is then the resulting witness. +#[derive(Clone, Debug)] +crate struct Witness<'tcx>(Vec>); + +impl<'tcx> Witness<'tcx> { + /// Asserts that the witness contains a single pattern, and returns it. + fn single_pattern(self) -> Pat<'tcx> { + assert_eq!(self.0.len(), 1); + self.0.into_iter().next().unwrap() + } + + /// Constructs a partial witness for a pattern given a list of + /// patterns expanded by the specialization step. + /// + /// When a pattern P is discovered to be useful, this function is used bottom-up + /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset + /// of values, V, where each value in that set is not covered by any previously + /// used patterns and is covered by the pattern P'. Examples: + /// + /// left_ty: tuple of 3 elements + /// pats: [10, 20, _] => (10, 20, _) + /// + /// left_ty: struct X { a: (bool, &'static str), b: usize} + /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } + fn apply_constructor<'p>( + mut self, + pcx: PatCtxt<'_, 'p, 'tcx>, + ctor: &Constructor<'tcx>, + ctor_wild_subpatterns: &Fields<'p, 'tcx>, + ) -> Self { + let pat = { + let len = self.0.len(); + let arity = ctor_wild_subpatterns.len(); + let pats = self.0.drain((len - arity)..).rev(); + ctor_wild_subpatterns.replace_fields(pcx.cx, pats).apply(pcx, ctor) + }; + + self.0.push(pat); + + self + } +} + +/// Algorithm from . +/// The algorithm from the paper has been modified to correctly handle empty +/// types. The changes are: +/// (0) We don't exit early if the pattern matrix has zero rows. We just +/// continue to recurse over columns. +/// (1) all_constructors will only return constructors that are statically +/// possible. E.g., it will only return `Ok` for `Result`. +/// +/// This finds whether a (row) vector `v` of patterns is 'useful' in relation +/// to a set of such vectors `m` - this is defined as there being a set of +/// inputs that will match `v` but not any of the sets in `m`. +/// +/// All the patterns at each column of the `matrix ++ v` matrix must have the same type. +/// +/// This is used both for reachability checking (if a pattern isn't useful in +/// relation to preceding patterns, it is not reachable) and exhaustiveness +/// checking (if a wildcard pattern is useful in relation to a matrix, the +/// matrix isn't exhaustive). +/// +/// `is_under_guard` is used to inform if the pattern has a guard. If it +/// has one it must not be inserted into the matrix. This shouldn't be +/// relied on for soundness. +fn is_useful<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + matrix: &Matrix<'p, 'tcx>, + v: &PatStack<'p, 'tcx>, + witness_preference: WitnessPreference, + hir_id: HirId, + is_under_guard: bool, + is_top_level: bool, +) -> Usefulness<'tcx> { + let Matrix { patterns: rows, .. } = matrix; + debug!("is_useful({:#?}, {:#?})", matrix, v); + + // The base case. We are pattern-matching on () and the return value is + // based on whether our matrix has a row or not. + // NOTE: This could potentially be optimized by checking rows.is_empty() + // first and then, if v is non-empty, the return value is based on whether + // the type of the tuple we're checking is inhabited or not. + if v.is_empty() { + return if rows.is_empty() { + Usefulness::new_useful(witness_preference) + } else { + NotUseful + }; + }; + + assert!(rows.iter().all(|r| r.len() == v.len())); + + // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). + let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); + let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; + + debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); + + // If the first pattern is an or-pattern, expand it. + let ret = if let Some(vs) = v.expand_or_pat() { + let subspans: Vec<_> = vs.iter().map(|v| v.head().span).collect(); + // We expand the or pattern, trying each of its branches in turn and keeping careful track + // of possible unreachable sub-branches. + let mut matrix = matrix.clone(); + let usefulnesses = vs.into_iter().map(|v| { + let v_span = v.head().span; + let usefulness = + is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); + // If pattern has a guard don't add it to the matrix. + if !is_under_guard { + // We push the already-seen patterns into the matrix in order to detect redundant + // branches like `Some(_) | Some(0)`. + matrix.push(v); + } + usefulness.unsplit_or_pat(v_span, &subspans) + }); + Usefulness::merge(usefulnesses) + } else { + let v_ctor = v.head_ctor(cx); + if let Constructor::IntRange(ctor_range) = &v_ctor { + // Lint on likely incorrect range patterns (#63987) + ctor_range.lint_overlapping_range_endpoints( + pcx, + matrix.head_ctors_and_spans(cx), + matrix.column_count().unwrap_or(0), + hir_id, + ) + } + // We split the head constructor of `v`. + let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx)); + // For each constructor, we compute whether there's a value that starts with it that would + // witness the usefulness of `v`. + let start_matrix = &matrix; + let usefulnesses = split_ctors.into_iter().map(|ctor| { + // We cache the result of `Fields::wildcards` because it is used a lot. + let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); + let spec_matrix = + start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); + let v = v.pop_head_constructor(&ctor_wild_subpatterns); + let usefulness = + is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false); + usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns) + }); + Usefulness::merge(usefulnesses) + }; + debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); + ret +} + +/// The arm of a match expression. +#[derive(Clone, Copy)] +crate struct MatchArm<'p, 'tcx> { + /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`. + crate pat: &'p super::Pat<'tcx>, + crate hir_id: HirId, + crate has_guard: bool, +} + +/// The output of checking a match for exhaustiveness and arm reachability. +crate struct UsefulnessReport<'p, 'tcx> { + /// For each arm of the input, whether that arm is reachable after the arms above it. + crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Usefulness<'tcx>)>, + /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of + /// exhaustiveness. + crate non_exhaustiveness_witnesses: Vec>, +} + +/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which +/// of its arms are reachable. +/// +/// Note: the input patterns must have been lowered through +/// `check_match::MatchVisitor::lower_pattern`. +crate fn compute_match_usefulness<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + arms: &[MatchArm<'p, 'tcx>], + scrut_hir_id: HirId, + scrut_ty: Ty<'tcx>, +) -> UsefulnessReport<'p, 'tcx> { + let mut matrix = Matrix::empty(); + let arm_usefulness: Vec<_> = arms + .iter() + .copied() + .map(|arm| { + let v = PatStack::from_pattern(arm.pat); + let usefulness = + is_useful(cx, &matrix, &v, LeaveOutWitness, arm.hir_id, arm.has_guard, true); + if !arm.has_guard { + matrix.push(v); + } + (arm, usefulness) + }) + .collect(); + + let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty)); + let v = PatStack::from_pattern(wild_pattern); + let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true); + let non_exhaustiveness_witnesses = match usefulness { + NotUseful => vec![], // Wildcard pattern isn't useful, so the match is exhaustive. + UsefulWithWitness(pats) => { + if pats.is_empty() { + bug!("Exhaustiveness check returned no witnesses") + } else { + pats.into_iter().map(|w| w.single_pattern()).collect() + } + } + Useful(_) => bug!(), + }; + UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } +} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 0dfacd7890..b2604ea690 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -510,7 +510,7 @@ impl<'a> StringReader<'a> { FatalError.raise() } - /// Note: It was decided to not add a test case, because it would be to big. + /// Note: It was decided to not add a test case, because it would be too big. /// fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! { self.fatal_span_( @@ -532,10 +532,15 @@ impl<'a> StringReader<'a> { if let Err(err) = result { let span_with_quotes = self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)); + let (start, end) = (range.start as u32, range.end as u32); + let lo = content_start + BytePos(start); + let hi = lo + BytePos(end - start); + let span = self.mk_sp(lo, hi); emit_unescape_error( &self.sess.span_diagnostic, lit_content, span_with_quotes, + span, mode, range, err, diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 47d317f918..6a890be369 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -13,6 +13,8 @@ pub(crate) fn emit_unescape_error( lit: &str, // full span of the literal, including quotes span_with_quotes: Span, + // interior span of the literal, without quotes + span: Span, mode: Mode, // range of the error inside `lit` range: Range, @@ -26,13 +28,6 @@ pub(crate) fn emit_unescape_error( range, error ); - let span = { - let Range { start, end } = range; - let (start, end) = (start as u32, end as u32); - let lo = span_with_quotes.lo() + BytePos(start + 1); - let hi = lo + BytePos(end - start); - span_with_quotes.with_lo(lo).with_hi(hi) - }; let last_char = || { let c = lit[range.clone()].chars().rev().next().unwrap(); let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32)); diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f125a12147..44999c9b63 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -1,21 +1,23 @@ //! The main parser interface. -#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] #![feature(iter_order_by)] #![feature(or_patterns)] use rustc_ast as ast; +use rustc_ast::attr::HasAttrs; use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, LazyTokenStream, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{symbol::kw, FileName, SourceFile, Span, DUMMY_SP}; use smallvec::SmallVec; +use std::cell::RefCell; use std::mem; use std::path::Path; use std::str; @@ -250,29 +252,23 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // before we fall back to the stringification. let convert_tokens = - |tokens: &Option| tokens.as_ref().map(|t| t.create_token_stream()); + |tokens: Option<&LazyTokenStream>| tokens.as_ref().map(|t| t.create_token_stream()); let tokens = match *nt { Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()), - Nonterminal::NtBlock(ref block) => convert_tokens(&block.tokens), - Nonterminal::NtStmt(ref stmt) => { - // FIXME: We currently only collect tokens for `:stmt` - // matchers in `macro_rules!` macros. When we start collecting - // tokens for attributes on statements, we will need to prepend - // attributes here - convert_tokens(&stmt.tokens) - } - Nonterminal::NtPat(ref pat) => convert_tokens(&pat.tokens), - Nonterminal::NtTy(ref ty) => convert_tokens(&ty.tokens), + Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()), + Nonterminal::NtStmt(ref stmt) => prepend_attrs(stmt.attrs(), stmt.tokens()), + Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.as_ref()), + Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.as_ref()), Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } Nonterminal::NtLifetime(ident) => { Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } - Nonterminal::NtMeta(ref attr) => convert_tokens(&attr.tokens), - Nonterminal::NtPath(ref path) => convert_tokens(&path.tokens), - Nonterminal::NtVis(ref vis) => convert_tokens(&vis.tokens), + Nonterminal::NtMeta(ref attr) => convert_tokens(attr.tokens.as_ref()), + Nonterminal::NtPath(ref path) => convert_tokens(path.tokens.as_ref()), + Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.as_ref()), Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { @@ -282,6 +278,25 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke } }; + // Caches the stringification of 'good' `TokenStreams` which passed + // `tokenstream_probably_equal_for_proc_macro`. This allows us to avoid + // repeatedly stringifying and comparing the same `TokenStream` for deeply + // nested nonterminals. + // + // We cache by the strinification instead of the `TokenStream` to avoid + // needing to implement `Hash` for `TokenStream`. Note that it's possible to + // have two distinct `TokenStream`s that stringify to the same result + // (e.g. if they differ only in hygiene information). However, any + // information lost during the stringification process is also intentionally + // ignored by `tokenstream_probably_equal_for_proc_macro`, so it's fine + // that a single cache entry may 'map' to multiple distinct `TokenStream`s. + // + // This is a temporary hack to prevent compilation blowup on certain inputs. + // The entire pretty-print/retokenize process will be removed soon. + thread_local! { + static GOOD_TOKEN_CACHE: RefCell> = Default::default(); + } + // FIXME(#43081): Avoid this pretty-print + reparse hack // Pretty-print the AST struct without inserting any parenthesis // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`). @@ -289,7 +304,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // ever used for a comparison against the capture tokenstream. let source = pprust::nonterminal_to_string_no_extra_parens(nt); let filename = FileName::macro_expansion_source_code(&source); - let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span)); + let reparsed_tokens = parse_stream_from_source_str(filename, source.clone(), sess, Some(span)); // During early phases of the compiler the AST could get modified // directly (e.g., attributes added or removed) and the internal cache @@ -315,8 +330,13 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { + if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source)) { + return tokens; + } + // Compare with a non-relaxed delim match to start. if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) { + GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone())); return tokens; } @@ -325,6 +345,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // token stream to match up with inserted parenthesis in the reparsed stream. let source_with_parens = pprust::nonterminal_to_string(nt); let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens); + + if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source_with_parens)) { + return tokens; + } + let reparsed_tokens_with_parens = parse_stream_from_source_str( filename_with_parens, source_with_parens, @@ -340,6 +365,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke sess, true, ) { + GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone())); return tokens; } @@ -419,9 +445,9 @@ pub fn tokenstream_probably_equal_for_proc_macro( // to iterate breaking tokens mutliple times. For example: // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]' let mut token_trees: SmallVec<[_; 2]>; - if let TokenTree::Token(token) = &tree { + if let TokenTree::Token(token) = tree { let mut out = SmallVec::<[_; 2]>::new(); - out.push(token.clone()); + out.push(token); // Iterate to fixpoint: // * We start off with 'out' containing our initial token, and `temp` empty // * If we are able to break any tokens in `out`, then `out` will have diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 3738fbaeac..fae09fa6fe 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -8,8 +8,9 @@ use rustc_span::{sym, Span}; use tracing::debug; +// Public for rustfmt usage #[derive(Debug)] -pub(super) enum InnerAttrPolicy<'a> { +pub enum InnerAttrPolicy<'a> { Permitted, Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, } @@ -78,7 +79,8 @@ impl<'a> Parser<'a> { /// Matches `attribute = # ! [ meta_item ]`. /// `inner_parse_policy` prescribes how to handle inner attributes. - fn parse_attribute( + // Public for rustfmt usage. + pub fn parse_attribute( &mut self, inner_parse_policy: InnerAttrPolicy<'_>, ) -> PResult<'a, ast::Attribute> { @@ -312,14 +314,13 @@ impl<'a> Parser<'a> { } pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool { + // One of the attributes may either itself be a macro, or apply derive macros (`derive`), + // or expand to macro attributes (`cfg_attr`). attrs.iter().any(|attr| { - if let Some(ident) = attr.ident() { + attr.ident().map_or(true, |ident| { ident.name == sym::derive - // This might apply a custom attribute/derive - || ident.name == sym::cfg_attr - || !rustc_feature::is_builtin_attr_name(ident.name) - } else { - true - } + || ident.name == sym::cfg_attr + || !rustc_feature::is_builtin_attr_name(ident.name) + }) }) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index cd3b8db230..98c7b9a63a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1808,9 +1808,13 @@ impl<'a> Parser<'a> { return Ok(false); // Don't continue. } - /// Handle a generic const argument that had not been enclosed in braces, and suggest enclosing - /// it braces. In this situation, unlike in `handle_ambiguous_unbraced_const_arg`, this is - /// almost certainly a const argument, so we always offer a suggestion. + /// Attempt to parse a generic const argument that has not been enclosed in braces. + /// There are a limited number of expressions that are permitted without being encoded + /// in braces: + /// - Literals. + /// - Single-segment paths (i.e. standalone generic const parameters). + /// All other expressions that can be parsed will emit an error suggesting the expression be + /// wrapped in braces. pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P> { let start = self.token.span; let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| { @@ -1908,4 +1912,22 @@ impl<'a> Parser<'a> { *self = snapshot; Err(err) } + + /// Get the diagnostics for the cases where `move async` is found. + /// + /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword + pub(super) fn incorrect_move_async_order_found( + &self, + move_async_span: Span, + ) -> DiagnosticBuilder<'a> { + let mut err = + self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect"); + err.span_suggestion_verbose( + move_async_span, + "try switching the order", + "async move".to_owned(), + Applicability::MaybeIncorrect, + ); + err + } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 188bf227c4..b147f42fad 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ -use super::pat::{GateOr, PARAM_EXPECTED}; -use super::ty::{AllowPlus, RecoverQPath}; +use super::pat::{GateOr, RecoverComma, PARAM_EXPECTED}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1089,6 +1089,9 @@ impl<'a> Parser<'a> { self.parse_yield_expr(attrs) } else if self.eat_keyword(kw::Let) { self.parse_let_expr(attrs) + } else if self.eat_keyword(kw::Underscore) { + self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span); + Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs)) } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { // Don't complain about bare semicolons after unclosed braces // recovery in order to keep the error count down. Fixing the @@ -1447,10 +1450,10 @@ impl<'a> Parser<'a> { .help("valid widths are 8, 16, 32, 64 and 128") .emit(); } else { - let msg = format!("invalid suffix `{}` for integer literal", suf); + let msg = format!("invalid suffix `{}` for number literal", suf); self.struct_span_err(span, &msg) .span_label(span, format!("invalid suffix `{}`", suf)) - .help("the suffix must be one of the integral types (`u32`, `isize`, etc)") + .help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)") .emit(); } } @@ -1600,7 +1603,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::async_closure, span); } - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; let body = match decl.output { @@ -1623,8 +1626,18 @@ impl<'a> Parser<'a> { } /// Parses an optional `move` prefix to a closure-like construct. - fn parse_capture_clause(&mut self) -> CaptureBy { - if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref } + fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { + if self.eat_keyword(kw::Move) { + // Check for `move async` and recover + if self.check_keyword(kw::Async) { + let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.incorrect_move_async_order_found(move_async_span)) + } else { + Ok(CaptureBy::Value) + } + } else { + Ok(CaptureBy::Ref) + } } /// Parses the `|arg, arg|` header of a closure. @@ -1644,7 +1657,8 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; - let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?; + let output = + self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?; Ok(P(FnDecl { inputs, output })) } @@ -1725,7 +1739,7 @@ impl<'a> Parser<'a> { /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; self.expect(&token::Eq)?; let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) @@ -1788,7 +1802,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_pat(GateOr::Yes)?; + let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; if !self.eat_keyword(kw::In) { self.error_missing_in_for_loop(); } @@ -1898,7 +1912,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - let pat = self.parse_top_pat(GateOr::No)?; + let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?; let guard = if self.eat_keyword(kw::If) { let if_span = self.prev_token.span; let cond = self.parse_expr()?; @@ -2015,7 +2029,7 @@ impl<'a> Parser<'a> { fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.expect_keyword(kw::Async)?; - let capture_clause = self.parse_capture_clause(); + let capture_clause = self.parse_capture_clause()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body); diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index dd99a7587d..ed8d4f7842 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -240,7 +240,7 @@ impl<'a> Parser<'a> { // Parse type with mandatory colon and (possibly empty) bounds, // or with mandatory equality sign and the second type. - let ty = self.parse_ty()?; + let ty = self.parse_ty_for_where_clause()?; if self.eat(&token::Colon) { let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5954b370e6..634cce403d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,5 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -247,9 +247,14 @@ impl<'a> Parser<'a> { (ident, ItemKind::Static(ty, m, expr)) } else if let Const::Yes(const_span) = self.parse_constness() { // CONST ITEM - self.recover_const_mut(const_span); - let (ident, ty, expr) = self.parse_item_global(None)?; - (ident, ItemKind::Const(def(), ty, expr)) + if self.token.is_keyword(kw::Impl) { + // recover from `const impl`, suggest `impl const` + self.recover_const_impl(const_span, attrs, def())? + } else { + self.recover_const_mut(const_span); + let (ident, ty, expr) = self.parse_item_global(None)?; + (ident, ItemKind::Const(def(), ty, expr)) + } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? @@ -988,6 +993,36 @@ impl<'a> Parser<'a> { } } + /// Recover on `const impl` with `const` already eaten. + fn recover_const_impl( + &mut self, + const_span: Span, + attrs: &mut Vec, + defaultness: Defaultness, + ) -> PResult<'a, ItemInfo> { + let impl_span = self.token.span; + let mut err = self.expected_ident_found(); + let mut impl_info = self.parse_item_impl(attrs, defaultness)?; + match impl_info.1 { + // only try to recover if this is implementing a trait for a type + ItemKind::Impl { of_trait: Some(ref trai), ref mut constness, .. } => { + *constness = Const::Yes(const_span); + + let before_trait = trai.path.span.shrink_to_lo(); + let const_up_to_impl = const_span.with_hi(impl_span.lo()); + err.multipart_suggestion( + "you might have meant to write a const trait impl", + vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())], + Applicability::MaybeIncorrect, + ) + .emit(); + } + ItemKind::Impl { .. } => return Err(err), + _ => unreachable!(), + } + Ok(impl_info) + } + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. /// @@ -1514,7 +1549,7 @@ impl<'a> Parser<'a> { let header = self.parse_fn_front_matter()?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` - let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)` + let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)` generics.where_clause = self.parse_where_clause()?; // `where T: Ord` let mut sig_hi = self.prev_token.span; @@ -1645,10 +1680,11 @@ impl<'a> Parser<'a> { &mut self, req_name: ReqName, ret_allow_plus: AllowPlus, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { Ok(P(FnDecl { inputs: self.parse_fn_params(req_name)?, - output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?, })) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index da1c54e88b..e19ebb8fd2 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -12,17 +12,19 @@ mod ty; use crate::lexer::UnmatchedBrace; pub use diagnostics::AttemptLocalParseRecovery; use diagnostics::Error; +pub use pat::OrPatNonterminalMode; pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, Spacing}; -use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit}; use rustc_ast::{Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; +use rustc_data_structures::sync::Lrc; use rustc_errors::PResult; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError}; use rustc_session::parse::ParseSess; @@ -131,6 +133,28 @@ struct TokenCursor { // Counts the number of calls to `next` or `next_desugared`, // depending on whether `desugar_doc_comments` is set. num_next_calls: usize, + // During parsing, we may sometimes need to 'unglue' a + // glued token into two component tokens + // (e.g. '>>' into '>' and '>), so that the parser + // can consume them one at a time. This process + // bypasses the normal capturing mechanism + // (e.g. `num_next_calls` will not be incremented), + // since the 'unglued' tokens due not exist in + // the original `TokenStream`. + // + // If we end up consuming both unglued tokens, + // then this is not an issue - we'll end up + // capturing the single 'glued' token. + // + // However, in certain circumstances, we may + // want to capture just the first 'unglued' token. + // For example, capturing the `Vec` + // in `Option>` requires us to unglue + // the trailing `>>` token. The `append_unglued_token` + // field is used to track this token - it gets + // appended to the captured stream when + // we evaluate a `LazyTokenStream` + append_unglued_token: Option, } #[derive(Clone)] @@ -264,7 +288,7 @@ impl TokenType { TokenType::Ident => "identifier".to_string(), TokenType::Path => "path".to_string(), TokenType::Type => "type".to_string(), - TokenType::Const => "const".to_string(), + TokenType::Const => "a const expression".to_string(), } } } @@ -335,6 +359,7 @@ impl<'a> Parser<'a> { stack: Vec::new(), num_next_calls: 0, desugar_doc_comments, + append_unglued_token: None, }, desugar_doc_comments, unmatched_angle_bracket_count: 0, @@ -358,6 +383,10 @@ impl<'a> Parser<'a> { self.token_cursor.next() }; self.token_cursor.num_next_calls += 1; + // We've retrieved an token from the underlying + // cursor, so we no longer need to worry about + // an unglued token. See `break_and_eat` for more details + self.token_cursor.append_unglued_token = None; if next.span.is_dummy() { // Tweak the location for better diagnostics, but keep syntactic context intact. next.span = fallback_span.with_ctxt(next.span.ctxt()); @@ -554,6 +583,14 @@ impl<'a> Parser<'a> { let first_span = self.sess.source_map().start_point(self.token.span); let second_span = self.token.span.with_lo(first_span.hi()); self.token = Token::new(first, first_span); + // Keep track of this token - if we end token capturing now, + // we'll want to append this token to the captured stream. + // + // If we consume any additional tokens, then this token + // is not needed (we'll capture the entire 'glued' token), + // and `next_tok` will set this field to `None` + self.token_cursor.append_unglued_token = + Some((TokenTree::Token(self.token.clone()), Spacing::Alone)); // Use the spacing of the glued token as the spacing // of the unglued second token. self.bump_with((Token::new(second, second_span), self.token_spacing)); @@ -873,7 +910,8 @@ impl<'a> Parser<'a> { id: DUMMY_NODE_ID, value: self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()), }; - Ok(self.mk_expr(span, ExprKind::ConstBlock(anon_const), AttrVec::new())) + let blk_span = anon_const.value.span; + Ok(self.mk_expr(span.to(blk_span), ExprKind::ConstBlock(anon_const), AttrVec::new())) } /// Parses mutability (`mut` or nothing). @@ -934,16 +972,24 @@ impl<'a> Parser<'a> { is_interpolated_expr = true; } } - let token_tree = if is_interpolated_expr { - // We need to accept arbitrary interpolated expressions to continue - // supporting things like `doc = $expr` that work on stable. - // Non-literal interpolated expressions are rejected after expansion. - self.parse_token_tree() - } else { - self.parse_unsuffixed_lit()?.token_tree() - }; - MacArgs::Eq(eq_span, token_tree.into()) + // The value here is never passed to macros as tokens by itself (not as a part + // of the whole attribute), so we don't collect tokens here. If this changes, + // then token will need to be collected. One catch here is that we are using + // a nonterminal for keeping the expression, but this nonterminal should not + // be wrapped into a group when converting to token stream. + let expr = self.parse_expr()?; + let span = expr.span; + + match &expr.kind { + // Not gated to supporte things like `doc = $expr` that work on stable. + _ if is_interpolated_expr => {} + ExprKind::Lit(lit) if lit.kind.is_unsuffixed() => {} + _ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span), + } + + let token = token::Interpolated(Lrc::new(token::NtExpr(expr))); + MacArgs::Eq(eq_span, TokenTree::token(token, span).into()) } else { MacArgs::Empty } @@ -1180,8 +1226,7 @@ impl<'a> Parser<'a> { /// Records all tokens consumed by the provided callback, /// including the current token. These tokens are collected /// into a `LazyTokenStream`, and returned along with the result - /// of the callback. The returned `LazyTokenStream` will be `None` - /// if not tokens were captured. + /// of the callback. /// /// Note: If your callback consumes an opening delimiter /// (including the case where you call `collect_tokens` @@ -1203,28 +1248,32 @@ impl<'a> Parser<'a> { let ret = f(self)?; - // We didn't capture any tokens - let num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls; - if num_calls == 0 { - return Ok((ret, None)); - } - // Produces a `TokenStream` on-demand. Using `cursor_snapshot` // and `num_calls`, we can reconstruct the `TokenStream` seen // by the callback. This allows us to avoid producing a `TokenStream` // if it is never needed - for example, a captured `macro_rules!` // argument that is never passed to a proc macro. + // In practice token stream creation happens rarely compared to + // calls to `collect_tokens` (see some statistics in #78736), + // so we are doing as little up-front work as possible. // // This also makes `Parser` very cheap to clone, since // there is no intermediate collection buffer to clone. + #[derive(Clone)] struct LazyTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, num_calls: usize, desugar_doc_comments: bool, + trailing_semi: bool, + append_unglued_token: Option, } impl CreateTokenStream for LazyTokenStreamImpl { fn create_token_stream(&self) -> TokenStream { + let mut num_calls = self.num_calls; + if self.trailing_semi { + num_calls += 1; + } // The token produced by the final call to `next` or `next_desugared` // was not actually consumed by the callback. The combination // of chaining the initial token and using `take` produces the desired @@ -1232,24 +1281,40 @@ impl<'a> Parser<'a> { // and omit the final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); let tokens = std::iter::once(self.start_token.clone()) - .chain((0..self.num_calls).map(|_| { + .chain((0..num_calls).map(|_| { if self.desugar_doc_comments { cursor_snapshot.next_desugared() } else { cursor_snapshot.next() } })) - .take(self.num_calls); + .take(num_calls); - make_token_stream(tokens) + make_token_stream(tokens, self.append_unglued_token.clone()) + } + fn add_trailing_semi(&self) -> Box { + if self.trailing_semi { + panic!("Called `add_trailing_semi` twice!"); + } + if self.append_unglued_token.is_some() { + panic!( + "Cannot call `add_trailing_semi` when we have an unglued token {:?}", + self.append_unglued_token + ); + } + let mut new = self.clone(); + new.trailing_semi = true; + Box::new(new) } } let lazy_impl = LazyTokenStreamImpl { start_token, + num_calls: self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls, cursor_snapshot, - num_calls, desugar_doc_comments: self.desugar_doc_comments, + trailing_semi: false, + append_unglued_token: self.token_cursor.append_unglued_token.clone(), }; Ok((ret, Some(LazyTokenStream::new(lazy_impl)))) } @@ -1304,7 +1369,10 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &Pa /// Converts a flattened iterator of tokens (including open and close delimiter tokens) /// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair /// of open and close delims. -fn make_token_stream(tokens: impl Iterator) -> TokenStream { +fn make_token_stream( + tokens: impl Iterator, + append_unglued_token: Option, +) -> TokenStream { #[derive(Debug)] struct FrameData { open: Span, @@ -1327,14 +1395,17 @@ fn make_token_stream(tokens: impl Iterator) -> TokenStr .inner .push((delimited, Spacing::Alone)); } - token => stack - .last_mut() - .expect("Bottom token frame is missing!") - .inner - .push((TokenTree::Token(token), spacing)), + token => { + stack + .last_mut() + .expect("Bottom token frame is missing!") + .inner + .push((TokenTree::Token(token), spacing)); + } } } - let final_buf = stack.pop().expect("Missing final buf!"); + let mut final_buf = stack.pop().expect("Missing final buf!"); + final_buf.inner.extend(append_unglued_token); assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack); TokenStream::new(final_buf.inner) } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 38f04da039..a6b9ac1014 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -4,6 +4,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; +use crate::parser::pat::{GateOr, OrPatNonterminalMode, RecoverComma}; use crate::parser::{FollowedByType, Parser, PathStyle}; impl<'a> Parser<'a> { @@ -11,7 +12,11 @@ impl<'a> Parser<'a> { /// /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that /// token. Be conservative (return true) if not sure. - pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { + pub fn nonterminal_may_begin_with( + kind: NonterminalKind, + token: &Token, + or_pat_mode: OrPatNonterminalMode, + ) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { match *nt { @@ -70,6 +75,8 @@ impl<'a> Parser<'a> { token::ModSep | // path token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) + // leading vert `|` or-pattern + token::BinOp(token::Or) => matches!(or_pat_mode, OrPatNonterminalMode::TopPat), token::Interpolated(ref nt) => may_be_ident(nt), _ => false, }, @@ -86,7 +93,12 @@ impl<'a> Parser<'a> { } } - pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonterminal> { + /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). + pub fn parse_nonterminal( + &mut self, + kind: NonterminalKind, + or_pat_mode: OrPatNonterminalMode, + ) -> PResult<'a, Nonterminal> { // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`) // needs to have them force-captured here. // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, @@ -119,8 +131,8 @@ impl<'a> Parser<'a> { let (stmt, tokens) = self.collect_tokens(|this| this.parse_stmt())?; match stmt { Some(mut s) => { - if s.tokens.is_none() { - s.tokens = tokens; + if s.tokens().is_none() { + s.set_tokens(tokens); } token::NtStmt(s) } @@ -130,7 +142,12 @@ impl<'a> Parser<'a> { } } NonterminalKind::Pat => { - let (mut pat, tokens) = self.collect_tokens(|this| this.parse_pat(None))?; + let (mut pat, tokens) = self.collect_tokens(|this| match or_pat_mode { + OrPatNonterminalMode::TopPat => { + this.parse_top_pat(GateOr::Yes, RecoverComma::No) + } + OrPatNonterminalMode::NoTopAlt => this.parse_pat(None), + })?; // We have have eaten an NtPat, which could already have tokens if pat.tokens.is_none() { pat.tokens = tokens; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ee9a6dca5a..1da371e0b7 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -18,7 +18,7 @@ pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"; /// Whether or not an or-pattern should be gated when occurring in the current context. -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub(super) enum GateOr { Yes, No, @@ -26,11 +26,18 @@ pub(super) enum GateOr { /// Whether or not to recover a `,` when parsing or-patterns. #[derive(PartialEq, Copy, Clone)] -enum RecoverComma { +pub(super) enum RecoverComma { Yes, No, } +/// Used when parsing a non-terminal (see `parse_nonterminal`) to determine if `:pat` should match +/// `top_pat` or `pat`. See issue . +pub enum OrPatNonterminalMode { + TopPat, + NoTopAlt, +} + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -43,13 +50,17 @@ impl<'a> Parser<'a> { /// Entry point to the main pattern parser. /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. - pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { + pub(super) fn parse_top_pat( + &mut self, + gate_or: GateOr, + rc: RecoverComma, + ) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; let leading_vert_span = self.prev_token.span; // Parse the possibly-or-pattern. - let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; + let pat = self.parse_pat_with_or(None, gate_or, rc)?; // If we parsed a leading `|` which should be gated, // and no other gated or-pattern has been parsed thus far, @@ -94,7 +105,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { // Parse the first pattern (`p_0`). let first_pat = self.parse_pat(expected)?; - self.maybe_recover_unexpected_comma(first_pat.span, rc)?; + self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -110,7 +121,7 @@ impl<'a> Parser<'a> { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; - self.maybe_recover_unexpected_comma(pat.span, rc)?; + self.maybe_recover_unexpected_comma(pat.span, rc, gate_or)?; pats.push(pat); } let or_pattern_span = lo.to(self.prev_token.span); @@ -190,7 +201,12 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { + fn maybe_recover_unexpected_comma( + &mut self, + lo: Span, + rc: RecoverComma, + gate_or: GateOr, + ) -> PResult<'a, ()> { if rc == RecoverComma::No || self.token != token::Comma { return Ok(()); } @@ -209,18 +225,24 @@ impl<'a> Parser<'a> { let seq_span = lo.to(self.prev_token.span); let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + const MSG: &str = "try adding parentheses to match on a tuple..."; + + let or_suggestion = + gate_or == GateOr::No || !self.sess.gated_spans.is_ungated(sym::or_patterns); err.span_suggestion( seq_span, - "try adding parentheses to match on a tuple...", + if or_suggestion { MSG } else { MSG.trim_end_matches('.') }, format!("({})", seq_snippet), Applicability::MachineApplicable, - ) - .span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(",", " |"), - Applicability::MachineApplicable, ); + if or_suggestion { + err.span_suggestion( + seq_span, + "...or a vertical bar to match on multiple alternatives", + seq_snippet.replace(",", " |"), + Applicability::MachineApplicable, + ); + } } Err(err) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 79e7374903..4510e86e03 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,12 +1,11 @@ -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; -use rustc_ast::{ - self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs, -}; +use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs}; use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; +use rustc_ast::{GenericArg, GenericArgs}; use rustc_ast::{Path, PathSegment, QSelf}; use rustc_errors::{pluralize, Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; @@ -232,7 +231,8 @@ impl<'a> Parser<'a> { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = ident.span.to(self.prev_token.span); - let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?; + let output = + self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; ParenthesizedArgs { inputs, output, span }.into() }; @@ -414,32 +414,40 @@ impl<'a> Parser<'a> { /// Parses a single argument in the angle arguments `<...>` of a path segment. fn parse_angle_arg(&mut self) -> PResult<'a, Option> { - if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon)) - { - // Parse associated type constraint. - let lo = self.token.span; - let ident = self.parse_ident()?; - let kind = if self.eat(&token::Eq) { - let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; - AssocTyConstraintKind::Equality { ty } - } else if self.eat(&token::Colon) { - let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; - AssocTyConstraintKind::Bound { bounds } - } else { - unreachable!(); - }; + let lo = self.token.span; + let arg = self.parse_generic_arg()?; + match arg { + Some(arg) => { + if self.check(&token::Colon) | self.check(&token::Eq) { + let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?; + let kind = if self.eat(&token::Colon) { + // Parse associated type constraint bound. + + let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; + AssocTyConstraintKind::Bound { bounds } + } else if self.eat(&token::Eq) { + // Parse associated type equality constraint + + let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; + AssocTyConstraintKind::Equality { ty } + } else { + unreachable!(); + }; - let span = lo.to(self.prev_token.span); + let span = lo.to(self.prev_token.span); - // Gate associated type bounds, e.g., `Iterator`. - if let AssocTyConstraintKind::Bound { .. } = kind { - self.sess.gated_spans.gate(sym::associated_type_bounds, span); + // Gate associated type bounds, e.g., `Iterator`. + if let AssocTyConstraintKind::Bound { .. } = kind { + self.sess.gated_spans.gate(sym::associated_type_bounds, span); + } + let constraint = + AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; + Ok(Some(AngleBracketedArg::Constraint(constraint))) + } else { + Ok(Some(AngleBracketedArg::Arg(arg))) + } } - - let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span }; - Ok(Some(AngleBracketedArg::Constraint(constraint))) - } else { - Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg)) + _ => Ok(None), } } @@ -489,6 +497,7 @@ impl<'a> Parser<'a> { /// - An expression surrounded in `{}`. /// - A literal. /// - A numeric literal prefixed by `-`. + /// - A single-segment path. pub(super) fn expr_is_valid_const_arg(&self, expr: &P) -> bool { match &expr.kind { ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true, @@ -496,6 +505,13 @@ impl<'a> Parser<'a> { ast::ExprKind::Lit(_) => true, _ => false, }, + // We can only resolve single-segment paths at the moment, because multi-segment paths + // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`. + ast::ExprKind::Path(None, path) + if path.segments.len() == 1 && path.segments[0].args.is_none() => + { + true + } _ => false, } } @@ -534,4 +550,54 @@ impl<'a> Parser<'a> { }; Ok(Some(arg)) } + + fn get_ident_from_generic_arg( + &self, + gen_arg: GenericArg, + lo: Span, + ) -> PResult<'a, (Ident, Option)> { + let gen_arg_span = gen_arg.span(); + match gen_arg { + GenericArg::Type(t) => match t.into_inner().kind { + ast::TyKind::Path(qself, mut path) => { + if let Some(qself) = qself { + let mut err = self.struct_span_err( + gen_arg_span, + "qualified paths cannot be used in associated type constraints", + ); + err.span_label( + qself.path_span, + "not allowed in associated type constraints", + ); + return Err(err); + } + if path.segments.len() == 1 { + let path_seg = path.segments.remove(0); + let ident = path_seg.ident; + let gen_args = path_seg.args.map(|args| args.into_inner()); + return Ok((ident, gen_args)); + } + let err = self.struct_span_err( + path.span, + "paths with multiple segments cannot be used in associated type constraints", + ); + return Err(err); + } + _ => { + let span = lo.to(self.prev_token.span); + let err = self.struct_span_err( + span, + "only path types can be used in associated type constraints", + ); + return Err(err); + } + }, + _ => { + let span = lo.to(self.prev_token.span); + let err = self + .struct_span_err(span, "only types can be used in associated type constraints"); + return Err(err); + } + } + } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 131ff1ae6b..2942747991 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -1,14 +1,16 @@ use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN; use super::diagnostics::{AttemptLocalParseRecovery, Error}; use super::expr::LhsExpr; -use super::pat::GateOr; +use super::pat::{GateOr, RecoverComma}; use super::path::PathStyle; use super::{BlockMode, Parser, Restrictions, SemiColonMode}; use crate::maybe_whole; use rustc_ast as ast; +use rustc_ast::attr::HasAttrs; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; +use rustc_ast::tokenstream::LazyTokenStream; use rustc_ast::util::classify; use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}; @@ -31,45 +33,75 @@ impl<'a> Parser<'a> { } fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option> { - maybe_whole!(self, NtStmt, |x| Some(x)); - - let attrs = self.parse_outer_attributes()?; + let mut attrs = self.parse_outer_attributes()?; + let has_attrs = !attrs.is_empty(); let lo = self.token.span; - let stmt = if self.eat_keyword(kw::Let) { - self.parse_local_mk(lo, attrs.into())? - } else if self.is_kw_followed_by_ident(kw::Mut) { - self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")? - } else if self.is_kw_followed_by_ident(kw::Auto) { - self.bump(); // `auto` - let msg = "write `let` instead of `auto` to introduce a new variable"; - self.recover_stmt_local(lo, attrs.into(), msg, "let")? - } else if self.is_kw_followed_by_ident(sym::var) { - self.bump(); // `var` - let msg = "write `let` instead of `var` to introduce a new variable"; - self.recover_stmt_local(lo, attrs.into(), msg, "let")? - } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { - // We have avoided contextual keywords like `union`, items with `crate` visibility, - // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something - // that starts like a path (1 token), but it fact not a path. - // Also, we avoid stealing syntax from `parse_item_`. - self.parse_stmt_path_start(lo, attrs)? - } else if let Some(item) = self.parse_item_common(attrs.clone(), false, true, |_| true)? { - // FIXME: Bad copy of attrs - self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) - } else if self.eat(&token::Semi) { - // Do not attempt to parse an expression if we're done here. - self.error_outer_attrs(&attrs); - self.mk_stmt(lo, StmtKind::Empty) - } else if self.token != token::CloseDelim(token::Brace) { - // Remainder are line-expr stmts. - let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; - self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) + maybe_whole!(self, NtStmt, |stmt| { + let mut stmt = stmt; + stmt.visit_attrs(|stmt_attrs| { + mem::swap(stmt_attrs, &mut attrs); + stmt_attrs.extend(attrs); + }); + Some(stmt) + }); + + let parse_stmt_inner = |this: &mut Self| { + let stmt = if this.eat_keyword(kw::Let) { + this.parse_local_mk(lo, attrs.into())? + } else if this.is_kw_followed_by_ident(kw::Mut) { + this.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")? + } else if this.is_kw_followed_by_ident(kw::Auto) { + this.bump(); // `auto` + let msg = "write `let` instead of `auto` to introduce a new variable"; + this.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if this.is_kw_followed_by_ident(sym::var) { + this.bump(); // `var` + let msg = "write `let` instead of `var` to introduce a new variable"; + this.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if this.check_path() + && !this.token.is_qpath_start() + && !this.is_path_start_item() + { + // We have avoided contextual keywords like `union`, items with `crate` visibility, + // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something + // that starts like a path (1 token), but it fact not a path. + // Also, we avoid stealing syntax from `parse_item_`. + this.parse_stmt_path_start(lo, attrs)? + } else if let Some(item) = + this.parse_item_common(attrs.clone(), false, true, |_| true)? + { + // FIXME: Bad copy of attrs + this.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) + } else if this.eat(&token::Semi) { + // Do not attempt to parse an expression if we're done here. + this.error_outer_attrs(&attrs); + this.mk_stmt(lo, StmtKind::Empty) + } else if this.token != token::CloseDelim(token::Brace) { + // Remainder are line-expr stmts. + let e = this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; + this.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) + } else { + this.error_outer_attrs(&attrs); + return Ok(None); + }; + Ok(Some(stmt)) + }; + + let stmt = if has_attrs { + let (mut stmt, tokens) = self.collect_tokens(parse_stmt_inner)?; + if let Some(stmt) = &mut stmt { + // If we already have tokens (e.g. due to encounting an `NtStmt`), + // use those instead. + if stmt.tokens().is_none() { + stmt.set_tokens(tokens); + } + } + stmt } else { - self.error_outer_attrs(&attrs); - return Ok(None); + parse_stmt_inner(self)? }; - Ok(Some(stmt)) + Ok(stmt) } fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec) -> PResult<'a, Stmt> { @@ -107,7 +139,7 @@ impl<'a> Parser<'a> { let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { - StmtKind::MacCall(P(MacCallStmt { mac, style, attrs })) + StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); @@ -153,7 +185,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_token.span; - let pat = self.parse_top_pat(GateOr::Yes)?; + let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` @@ -219,7 +251,7 @@ impl<'a> Parser<'a> { } }; let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span }; - Ok(P(ast::Local { ty, pat, init, id: DUMMY_NODE_ID, span: lo.to(hi), attrs })) + Ok(P(ast::Local { ty, pat, init, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) } /// Parses the RHS of a local variable declaration (e.g., '= 14;'). @@ -376,6 +408,12 @@ impl<'a> Parser<'a> { None => return Ok(None), }; + let add_semi_token = |tokens: Option<&mut LazyTokenStream>| { + if let Some(tokens) = tokens { + *tokens = tokens.add_trailing_semi(); + } + }; + let mut eat_semi = true; match stmt.kind { // Expression without semicolon. @@ -417,6 +455,7 @@ impl<'a> Parser<'a> { *expr = self.mk_expr_err(sp); } } + StmtKind::Expr(_) | StmtKind::MacCall(_) => {} StmtKind::Local(ref mut local) => { if let Err(e) = self.expect_semi() { // We might be at the `,` in `let x = foo;`. Try to recover. @@ -430,13 +469,18 @@ impl<'a> Parser<'a> { } } eat_semi = false; + // We just checked that there's a semicolon in the tokenstream, + // so capture it + add_semi_token(local.tokens.as_mut()); } - StmtKind::Empty => eat_semi = false, - _ => {} + StmtKind::Empty | StmtKind::Item(_) | StmtKind::Semi(_) => eat_semi = false, } if eat_semi && self.eat(&token::Semi) { stmt = stmt.add_trailing_semicolon(); + // We just checked that we have a semicolon in the tokenstream, + // so capture it + add_semi_token(stmt.tokens_mut()); } stmt.span = stmt.span.to(self.prev_token.span); Ok(Some(stmt)) @@ -447,7 +491,7 @@ impl<'a> Parser<'a> { } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { - Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None } + Stmt { id: DUMMY_NODE_ID, kind, span } } pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 7a6ebca4e1..9553f5d09e 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,6 +43,37 @@ pub(super) enum RecoverQPath { No, } +/// Signals whether parsing a type should recover `->`. +/// +/// More specifically, when parsing a function like: +/// ```rust +/// fn foo() => u8 { 0 } +/// fn bar(): u8 { 0 } +/// ``` +/// The compiler will try to recover interpreting `foo() => u8` as `foo() -> u8` when calling +/// `parse_ty` with anything except `RecoverReturnSign::No`, and it will try to recover `bar(): u8` +/// as `bar() -> u8` when passing `RecoverReturnSign::Yes` to `parse_ty` +#[derive(Copy, Clone, PartialEq)] +pub(super) enum RecoverReturnSign { + Yes, + OnlyFatArrow, + No, +} + +impl RecoverReturnSign { + /// [RecoverReturnSign::Yes] allows for recovering `fn foo() => u8` and `fn foo(): u8`, + /// [RecoverReturnSign::OnlyFatArrow] allows for recovering only `fn foo() => u8` (recovering + /// colons can cause problems when parsing where clauses), and + /// [RecoverReturnSign::No] doesn't allow for any recovery of the return type arrow + fn can_recover(self, token: &TokenKind) -> bool { + match self { + Self::Yes => matches!(token, token::FatArrow | token::Colon), + Self::OnlyFatArrow => matches!(token, token::FatArrow), + Self::No => false, + } + } +} + // Is `...` (`CVarArgs`) legal at this level of type parsing? #[derive(PartialEq)] enum AllowCVariadic { @@ -62,14 +93,24 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No) + self.parse_ty_common( + AllowPlus::Yes, + AllowCVariadic::No, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + ) } /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) + self.parse_ty_common( + AllowPlus::Yes, + AllowCVariadic::Yes, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + ) } /// Parses a type in restricted contexts where `+` is not permitted. @@ -79,7 +120,22 @@ impl<'a> Parser<'a> { /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { - self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No) + self.parse_ty_common( + AllowPlus::No, + AllowCVariadic::No, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + ) + } + + /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>` + pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { + self.parse_ty_common( + AllowPlus::Yes, + AllowCVariadic::Yes, + RecoverQPath::Yes, + RecoverReturnSign::OnlyFatArrow, + ) } /// Parses an optional return type `[ -> TY ]` in a function declaration. @@ -87,10 +143,35 @@ impl<'a> Parser<'a> { &mut self, allow_plus: AllowPlus, recover_qpath: RecoverQPath, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, FnRetTy> { Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? - let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + let ty = self.parse_ty_common( + allow_plus, + AllowCVariadic::No, + recover_qpath, + recover_return_sign, + )?; + FnRetTy::Ty(ty) + } else if recover_return_sign.can_recover(&self.token.kind) { + // Don't `eat` to prevent `=>` from being added as an expected token which isn't + // actually expected and could only confuse users + self.bump(); + self.struct_span_err(self.prev_token.span, "return types are denoted using `->`") + .span_suggestion_short( + self.prev_token.span, + "use `->` instead", + "->".to_string(), + Applicability::MachineApplicable, + ) + .emit(); + let ty = self.parse_ty_common( + allow_plus, + AllowCVariadic::No, + recover_qpath, + recover_return_sign, + )?; FnRetTy::Ty(ty) } else { FnRetTy::Default(self.token.span.shrink_to_lo()) @@ -100,8 +181,9 @@ impl<'a> Parser<'a> { fn parse_ty_common( &mut self, allow_plus: AllowPlus, - recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, + recover_qpath: RecoverQPath, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); @@ -129,14 +211,14 @@ impl<'a> Parser<'a> { TyKind::Infer } else if self.check_fn_front_matter() { // Function pointer type - self.parse_ty_bare_fn(lo, Vec::new())? + self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)? } else if self.check_keyword(kw::For) { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.check_fn_front_matter() { - self.parse_ty_bare_fn(lo, lifetime_defs)? + self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)? } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); @@ -338,9 +420,14 @@ impl<'a> Parser<'a> { /// Function Style ABI Parameter types /// ``` /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers. - fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec) -> PResult<'a, TyKind> { + fn parse_ty_bare_fn( + &mut self, + lo: Span, + params: Vec, + recover_return_sign: RecoverReturnSign, + ) -> PResult<'a, TyKind> { let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?; - let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?; + let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; let whole_span = lo.to(self.prev_token.span); if let ast::Const::Yes(span) = constness { self.error_fn_ptr_bad_qualifier(whole_span, span, "const"); diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index df6667a29d..c87799f1c2 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -18,3 +18,4 @@ rustc_ast = { path = "../rustc_ast" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_lexer = { path = "../rustc_lexer" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7679582f88..aeaa862f5f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -78,7 +78,7 @@ impl CheckAttrVisitor<'tcx> { } else if self.tcx.sess.check_name(attr, sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { - self.check_doc_alias(attr, hir_id, target) + self.check_doc_attrs(attr, hir_id, target) } else if self.tcx.sess.check_name(attr, sym::no_link) { self.check_no_link(&attr, span, target) } else if self.tcx.sess.check_name(attr, sym::export_name) { @@ -89,6 +89,8 @@ impl CheckAttrVisitor<'tcx> { self.check_allow_internal_unstable(&attr, span, target, &attrs) } else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) { self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::naked) { + self.check_naked(attr, span, target) } else { // lint-only checks if self.tcx.sess.check_name(attr, sym::cold) { @@ -162,6 +164,25 @@ impl CheckAttrVisitor<'tcx> { } } + /// Checks if `#[naked]` is applied to a function definition. + fn check_naked(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Fn + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function definition", + ) + .span_label(*span, "not a function definition") + .emit(); + false + } + } + } + /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. fn check_track_caller( &self, @@ -171,7 +192,7 @@ impl CheckAttrVisitor<'tcx> { target: Target, ) -> bool { match target { - _ if self.tcx.sess.contains_name(attrs, sym::naked) => { + _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => { struct_span_err!( self.tcx.sess, *attr_span, @@ -266,99 +287,159 @@ impl CheckAttrVisitor<'tcx> { } } - fn doc_alias_str_error(&self, meta: &NestedMetaItem) { + fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) { self.tcx .sess .struct_span_err( meta.span(), - "doc alias attribute expects a string: #[doc(alias = \"0\")]", + &format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name), ) .emit(); } - fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { + fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool { + let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_alias.is_empty() { + self.doc_attr_str_error(meta, "alias"); + return false; + } + if let Some(c) = + doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + &format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c,), + ) + .emit(); + return false; + } + if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + "`#[doc(alias = \"...\")]` cannot start or end with ' '", + ) + .emit(); + return false; + } + if let Some(err) = match target { + Target::Impl => Some("implementation block"), + Target::ForeignMod => Some("extern block"), + Target::AssocTy => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + if Target::from_item(containing_item) == Target::Impl { + Some("type alias in implementation block") + } else { + None + } + } + Target::AssocConst => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + // We can't link to trait impl's consts. + let err = "associated constant in trait implementation block"; + match containing_item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => Some(err), + _ => None, + } + } + _ => None, + } { + self.tcx + .sess + .struct_span_err( + meta.span(), + &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), + ) + .emit(); + return false; + } + true + } + + fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { + let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_keyword.is_empty() { + self.doc_attr_str_error(meta, "keyword"); + return false; + } + match self.tcx.hir().expect_item(hir_id).kind { + ItemKind::Mod(ref module) => { + if !module.item_ids.is_empty() { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(keyword = \"...\")]` can only be used on empty modules", + ) + .emit(); + return false; + } + } + _ => { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(keyword = \"...\")]` can only be used on modules", + ) + .emit(); + return false; + } + } + if !rustc_lexer::is_ident(&doc_keyword) { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + &format!("`{}` is not a valid identifier", doc_keyword), + ) + .emit(); + return false; + } + true + } + + fn check_attr_crate_level( + &self, + meta: &NestedMetaItem, + hir_id: HirId, + attr_name: &str, + ) -> bool { + if CRATE_HIR_ID == hir_id { + self.tcx + .sess + .struct_span_err( + meta.span(), + &format!( + "`#![doc({} = \"...\")]` isn't allowed as a crate level attribute", + attr_name, + ), + ) + .emit(); + return false; + } + true + } + + fn check_doc_attrs(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { if let Some(mi) = attr.meta() { if let Some(list) = mi.meta_item_list() { for meta in list { if meta.has_name(sym::alias) { - if !meta.is_value_str() { - self.doc_alias_str_error(meta); - return false; - } - let doc_alias = - meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); - if doc_alias.is_empty() { - self.doc_alias_str_error(meta); - return false; - } - if let Some(c) = doc_alias - .chars() - .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + if !self.check_attr_crate_level(meta, hir_id, "alias") + || !self.check_doc_alias(meta, hir_id, target) { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!( - "{:?} character isn't allowed in `#[doc(alias = \"...\")]`", - c, - ), - ) - .emit(); - return false; - } - if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(alias = \"...\")]` cannot start or end with ' '", - ) - .emit(); return false; } - if let Some(err) = match target { - Target::Impl => Some("implementation block"), - Target::ForeignMod => Some("extern block"), - Target::AssocTy => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); - if Target::from_item(containing_item) == Target::Impl { - Some("type alias in implementation block") - } else { - None - } - } - Target::AssocConst => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); - // We can't link to trait impl's consts. - let err = "associated constant in trait implementation block"; - match containing_item.kind { - ItemKind::Impl { of_trait: Some(_), .. } => Some(err), - _ => None, - } - } - _ => None, - } { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), - ) - .emit(); - return false; - } - if CRATE_HIR_ID == hir_id { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#![doc(alias = \"...\")]` isn't allowed as a crate \ - level attribute", - ) - .emit(); + } else if meta.has_name(sym::keyword) { + if !self.check_attr_crate_level(meta, hir_id, "keyword") + || !self.check_doc_keyword(meta, hir_id) + { return false; } } @@ -464,60 +545,68 @@ impl CheckAttrVisitor<'tcx> { target: Target, item: Option>, ) -> bool { - if let Target::Fn | Target::Method(..) | Target::ForeignFn = target { - let mut invalid_args = vec![]; - for meta in attr.meta_item_list().expect("no meta item list") { - if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { - if let Some(ItemLike::Item(Item { - kind: ItemKind::Fn(FnSig { decl, .. }, ..), - .. - })) - | Some(ItemLike::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(decl, ..), - .. - })) = item - { - let arg_count = decl.inputs.len() as u128; - if *val >= arg_count { - let span = meta.span(); - self.tcx - .sess - .struct_span_err(span, "index exceeds number of arguments") - .span_label( - span, - format!( - "there {} only {} argument{}", - if arg_count != 1 { "are" } else { "is" }, - arg_count, - pluralize!(arg_count) - ), - ) - .emit(); - return false; - } - } else { - bug!("should be a function item"); + let is_function = matches!(target, Target::Fn | Target::Method(..) | Target::ForeignFn); + if !is_function { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(*span, "not a function") + .emit(); + return false; + } + + let list = match attr.meta_item_list() { + // The attribute form is validated on AST. + None => return false, + Some(it) => it, + }; + + let mut invalid_args = vec![]; + for meta in list { + if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { + if let Some(ItemLike::Item(Item { + kind: ItemKind::Fn(FnSig { decl, .. }, ..), + .. + })) + | Some(ItemLike::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(decl, ..), + .. + })) = item + { + let arg_count = decl.inputs.len() as u128; + if *val >= arg_count { + let span = meta.span(); + self.tcx + .sess + .struct_span_err(span, "index exceeds number of arguments") + .span_label( + span, + format!( + "there {} only {} argument{}", + if arg_count != 1 { "are" } else { "is" }, + arg_count, + pluralize!(arg_count) + ), + ) + .emit(); + return false; } } else { - invalid_args.push(meta.span()); + bug!("should be a function item"); } - } - if !invalid_args.is_empty() { - self.tcx - .sess - .struct_span_err(invalid_args, "arguments should be non-negative integers") - .emit(); - false } else { - true + invalid_args.push(meta.span()); } - } else { + } + + if !invalid_args.is_empty() { self.tcx .sess - .struct_span_err(attr.span, "attribute should be applied to a function") - .span_label(*span, "not a function") + .struct_span_err(invalid_args, "arguments should be non-negative integers") .emit(); false + } else { + true } } @@ -793,6 +882,18 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_item(self, item) } + fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) { + let target = Target::from_generic_param(generic_param); + self.check_attributes( + generic_param.hir_id, + generic_param.attrs, + &generic_param.span, + target, + None, + ); + intravisit::walk_generic_param(self, generic_param) + } + fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) { let target = Target::from_trait_item(trait_item); self.check_attributes(trait_item.hir_id, &trait_item.attrs, &trait_item.span, target, None); diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index b24c62b971..2d6bbff460 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -15,7 +15,6 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; @@ -46,6 +45,8 @@ impl NonConstExpr { return None; } + Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"), + // All other expressions are allowed. Self::Loop(Loop | While | WhileLet) | Self::Match( @@ -145,7 +146,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This // is a pretty narrow case, however. - if nightly_options::is_nightly_build() { + if tcx.sess.is_nightly_build() { for gate in missing_secondary { let note = format!( "add `#![feature({})]` to the crate attributes to enable", diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index f567dd83bc..00152878d6 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -190,7 +190,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_item(self, &item); } - hir::ItemKind::ForeignMod(..) => {} + hir::ItemKind::ForeignMod { .. } => {} _ => { intravisit::walk_item(self, &item); } @@ -396,24 +396,6 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } } - hir::ItemKind::Trait(.., trait_item_refs) => { - for trait_item_ref in trait_item_refs { - let trait_item = self.krate.trait_item(trait_item_ref.id); - match trait_item.kind { - hir::TraitItemKind::Const(_, Some(_)) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => { - if has_allow_dead_code_or_lang_attr( - self.tcx, - trait_item.hir_id, - &trait_item.attrs, - ) { - self.worklist.push(trait_item.hir_id); - } - } - _ => {} - } - } - } hir::ItemKind::Impl { ref of_trait, items, .. } => { if of_trait.is_some() { self.worklist.push(item.hir_id); @@ -440,13 +422,27 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } - fn visit_trait_item(&mut self, _item: &hir::TraitItem<'_>) { - // ignore: we are handling this in `visit_item` above + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { + use hir::TraitItemKind::{Const, Fn}; + if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) + && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id, &trait_item.attrs) + { + self.worklist.push(trait_item.hir_id); + } } fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) { // ignore: we are handling this in `visit_item` above } + + fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { + use hir::ForeignItemKind::{Fn, Static}; + if matches!(foreign_item.kind, Static(..) | Fn(..)) + && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id, &foreign_item.attrs) + { + self.worklist.push(foreign_item.hir_id); + } + } } fn create_and_seed_worklist<'tcx>( diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 0f4aa72d5c..699c96bc49 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -37,6 +37,10 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) { self.observe_item(&impl_item.attrs, impl_item.hir_id); } + + fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { + self.observe_item(foreign_item.attrs, foreign_item.hir_id); + } } impl<'tcx> DiagnosticItemCollector<'tcx> { @@ -100,17 +104,9 @@ fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> FxHashMap { // Collect diagnostic items in this crate. tcx.hir().krate().visit_all_item_likes(&mut collector); - // FIXME(visit_all_item_likes): Foreign items are not visited - // here, so we have to manually look at them for now. - for (_, foreign_module) in tcx.foreign_modules(LOCAL_CRATE).iter() { - for &foreign_item in foreign_module.foreign_items.iter() { - match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(foreign_item.expect_local())) { - hir::Node::ForeignItem(item) => { - collector.observe_item(item.attrs, item.hir_id); - } - item => bug!("unexpected foreign item {:?}", item), - } - } + + for m in tcx.hir().krate().exported_macros { + collector.observe_item(m.attrs, m.hir_id); } collector.items diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index e87adb378e..5ff631a245 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -2,7 +2,7 @@ use rustc_ast::entry::EntryPointType; use rustc_errors::struct_span_err; use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{HirId, ImplItem, Item, ItemKind, TraitItem}; +use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem}; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -45,6 +45,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem<'tcx>) { // Entry fn is never a trait item. } + + fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) { + // Entry fn is never a foreign item. + } } fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> { diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 6d1a5fcc10..fdd6c23805 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -68,6 +68,11 @@ impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { let mut inner_visitor = self.new_inner_visitor(self.hir_map); inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i)); } + + fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) { + let mut inner_visitor = self.new_inner_visitor(self.hir_map); + inner_visitor.check(i.hir_id, |this| intravisit::walk_foreign_item(this, i)); + } } impl<'a, 'hir> HirIdValidator<'a, 'hir> { @@ -164,6 +169,13 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { // different owner. } + fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef<'hir>) { + // Explicitly do nothing here. ForeignItemRefs contain hir::Visibility + // values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod + // we are currently in. So for those it's correct that they have a + // different owner. + } + fn visit_generic_param(&mut self, param: &'hir hir::GenericParam<'hir>) { if let hir::GenericParamKind::Type { synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 956be925be..711e8e87c6 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -347,7 +347,7 @@ impl ExprVisitor<'tcx> { } fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { - for (idx, op) in asm.operands.iter().enumerate() { + for (idx, (op, _op_sp)) in asm.operands.iter().enumerate() { match *op { hir::InlineAsmOperand::In { reg, ref expr } => { self.check_asm_operand_type(idx, reg, expr, asm.template, None); diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 0ae0c381a1..3132661e5f 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -54,6 +54,8 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { impl_item.attrs, ) } + + fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {} } impl LanguageItemCollector<'tcx> { diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 504cbbfcb7..9e83cbd668 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -40,6 +40,7 @@ impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> { fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} + fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {} } impl LayoutTest<'tcx> { diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index c32c9c8eaa..9759a500e0 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -7,6 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(const_fn)] #![feature(const_panic)] +#![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] @@ -32,6 +33,7 @@ pub mod layout_test; mod lib_features; mod liveness; pub mod loops; +mod naked_functions; mod reachable; mod region; pub mod stability; @@ -46,6 +48,7 @@ pub fn provide(providers: &mut Providers) { lang_items::provide(providers); lib_features::provide(providers); loops::provide(providers); + naked_functions::provide(providers); liveness::provide(providers); intrinsicck::provide(providers); reachable::provide(providers); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 7288015e17..86ce35c6d9 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -105,6 +105,8 @@ use std::io; use std::io::prelude::*; use std::rc::Rc; +mod rwu_table; + rustc_index::newtype_index! { pub struct Variable { DEBUG_FORMAT = "v({})", @@ -317,10 +319,11 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { // swap in a new set of IR maps for this body let mut maps = IrMaps::new(self.tcx); let hir_id = maps.tcx.hir().body_owner(body.id()); - let def_id = maps.tcx.hir().local_def_id(hir_id); + let local_def_id = maps.tcx.hir().local_def_id(hir_id); + let def_id = local_def_id.to_def_id(); // Don't run unused pass for #[derive()] - if let Some(parent) = self.tcx.parent(def_id.to_def_id()) { + if let Some(parent) = self.tcx.parent(def_id) { if let DefKind::Impl = self.tcx.def_kind(parent.expect_local()) { if self.tcx.has_attr(parent, sym::automatically_derived) { return; @@ -328,8 +331,8 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } } - if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) { - for (&var_hir_id, _upvar) in upvars { + if let Some(captures) = maps.tcx.typeck(local_def_id).closure_captures.get(&def_id) { + for &var_hir_id in captures.keys() { let var_name = maps.tcx.hir().name(var_hir_id); maps.add_variable(Upvar(var_hir_id, var_name)); } @@ -340,7 +343,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { intravisit::walk_body(&mut maps, body); // compute liveness - let mut lsets = Liveness::new(&mut maps, def_id); + let mut lsets = Liveness::new(&mut maps, local_def_id); let entry_ln = lsets.compute(&body, hir_id); lsets.log_liveness(entry_ln, body.id().hir_id); @@ -357,6 +360,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { self.add_from_pat(&arm.pat); + if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + self.add_from_pat(pat); + } intravisit::walk_arm(self, arm); } @@ -397,10 +403,18 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { // construction site. let mut call_caps = Vec::new(); let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id); - if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { - call_caps.extend(upvars.iter().map(|(&var_id, upvar)| { + if let Some(captures) = self + .tcx + .typeck(closure_def_id) + .closure_captures + .get(&closure_def_id.to_def_id()) + { + // If closure captures is Some, upvars_mentioned must also be Some + let upvars = self.tcx.upvars_mentioned(closure_def_id).unwrap(); + call_caps.extend(captures.keys().map(|var_id| { + let upvar = upvars[var_id]; let upvar_ln = self.add_live_node(UpvarNode(upvar.span)); - CaptureInfo { ln: upvar_ln, var_hid: var_id } + CaptureInfo { ln: upvar_ln, var_hid: *var_id } })); } self.set_captures(expr.hir_id, call_caps); @@ -459,101 +473,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { // Actually we compute just a bit more than just liveness, but we use // the same basic propagation framework in all cases. -#[derive(Clone, Copy)] -struct RWU { - reader: Option, - writer: Option, - used: bool, -} - -/// Conceptually, this is like a `Vec`. But the number of `RWU`s can get -/// very large, so it uses a more compact representation that takes advantage -/// of the fact that when the number of `RWU`s is large, most of them have an -/// invalid reader and an invalid writer. -struct RWUTable { - /// Each entry in `packed_rwus` is either INV_INV_FALSE, INV_INV_TRUE, or - /// an index into `unpacked_rwus`. In the common cases, this compacts the - /// 65 bits of data into 32; in the uncommon cases, it expands the 65 bits - /// in 96. - /// - /// More compact representations are possible -- e.g., use only 2 bits per - /// packed `RWU` and make the secondary table a HashMap that maps from - /// indices to `RWU`s -- but this one strikes a good balance between size - /// and speed. - packed_rwus: Vec, - unpacked_rwus: Vec, -} - -// A constant representing `RWU { reader: None; writer: None; used: false }`. -const INV_INV_FALSE: u32 = u32::MAX; - -// A constant representing `RWU { reader: None; writer: None; used: true }`. -const INV_INV_TRUE: u32 = u32::MAX - 1; - -impl RWUTable { - fn new(num_rwus: usize) -> RWUTable { - Self { packed_rwus: vec![INV_INV_FALSE; num_rwus], unpacked_rwus: vec![] } - } - - fn get(&self, idx: usize) -> RWU { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE => RWU { reader: None, writer: None, used: false }, - INV_INV_TRUE => RWU { reader: None, writer: None, used: true }, - _ => self.unpacked_rwus[packed_rwu as usize], - } - } - - fn get_reader(&self, idx: usize) -> Option { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => None, - _ => self.unpacked_rwus[packed_rwu as usize].reader, - } - } - - fn get_writer(&self, idx: usize) -> Option { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => None, - _ => self.unpacked_rwus[packed_rwu as usize].writer, - } - } - - fn get_used(&self, idx: usize) -> bool { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE => false, - INV_INV_TRUE => true, - _ => self.unpacked_rwus[packed_rwu as usize].used, - } - } - - #[inline] - fn copy_packed(&mut self, dst_idx: usize, src_idx: usize) { - self.packed_rwus[dst_idx] = self.packed_rwus[src_idx]; - } - - fn assign_unpacked(&mut self, idx: usize, rwu: RWU) { - if rwu.reader == None && rwu.writer == None { - // When we overwrite an indexing entry in `self.packed_rwus` with - // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry - // from `self.unpacked_rwus`; it's not worth the effort, and we - // can't have entries shifting around anyway. - self.packed_rwus[idx] = if rwu.used { INV_INV_TRUE } else { INV_INV_FALSE } - } else { - // Add a new RWU to `unpacked_rwus` and make `packed_rwus[idx]` - // point to it. - self.packed_rwus[idx] = self.unpacked_rwus.len() as u32; - self.unpacked_rwus.push(rwu); - } - } - - fn assign_inv_inv(&mut self, idx: usize) { - self.packed_rwus[idx] = if self.get_used(idx) { INV_INV_TRUE } else { INV_INV_FALSE }; - } -} - const ACC_READ: u32 = 1; const ACC_WRITE: u32 = 2; const ACC_USE: u32 = 4; @@ -564,8 +483,9 @@ struct Liveness<'a, 'tcx> { typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, upvars: Option<&'tcx FxIndexMap>, + closure_captures: Option<&'tcx FxIndexMap>, successors: IndexVec>, - rwu_table: RWUTable, + rwu_table: rwu_table::RWUTable, /// A live node representing a point of execution before closure entry & /// after closure exit. Used to calculate liveness of captured variables @@ -587,6 +507,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let typeck_results = ir.tcx.typeck(body_owner); let param_env = ir.tcx.param_env(body_owner); let upvars = ir.tcx.upvars_mentioned(body_owner); + let closure_captures = typeck_results.closure_captures.get(&body_owner.to_def_id()); let closure_ln = ir.add_live_node(ClosureNode); let exit_ln = ir.add_live_node(ExitNode); @@ -600,8 +521,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { typeck_results, param_env, upvars, + closure_captures, successors: IndexVec::from_elem_n(None, num_live_nodes), - rwu_table: RWUTable::new(num_live_nodes * num_vars), + rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars), closure_ln, exit_ln, break_ln: Default::default(), @@ -640,61 +562,37 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { succ } - fn idx(&self, ln: LiveNode, var: Variable) -> usize { - ln.index() * self.ir.var_kinds.len() + var.index() - } - - fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) { - Some(self.ir.lnks[reader]) - } else { - None - } + fn live_on_entry(&self, ln: LiveNode, var: Variable) -> bool { + self.rwu_table.get_reader(ln, var) } // Is this variable live on entry to any of its successor nodes? - fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option { + fn live_on_exit(&self, ln: LiveNode, var: Variable) -> bool { let successor = self.successors[ln].unwrap(); self.live_on_entry(successor, var) } fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool { - self.rwu_table.get_used(self.idx(ln, var)) + self.rwu_table.get_used(ln, var) } - fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) { - Some(self.ir.lnks[writer]) - } else { - None - } + fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> bool { + self.rwu_table.get_writer(ln, var) } - fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option { + fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> bool { let successor = self.successors[ln].unwrap(); self.assigned_on_entry(successor, var) } - fn indices2(&mut self, ln: LiveNode, succ_ln: LiveNode, mut op: F) - where - F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize), - { - let node_base_idx = self.idx(ln, Variable::from(0u32)); - let succ_base_idx = self.idx(succ_ln, Variable::from(0u32)); - for var_idx in 0..self.ir.var_kinds.len() { - op(self, node_base_idx + var_idx, succ_base_idx + var_idx); - } - } - - fn write_vars(&self, wr: &mut dyn Write, ln: LiveNode, mut test: F) -> io::Result<()> + fn write_vars(&self, wr: &mut dyn Write, mut test: F) -> io::Result<()> where - F: FnMut(usize) -> bool, + F: FnMut(Variable) -> bool, { - let node_base_idx = self.idx(ln, Variable::from(0u32)); for var_idx in 0..self.ir.var_kinds.len() { - let idx = node_base_idx + var_idx; - if test(idx) { - write!(wr, " {:?}", Variable::from(var_idx))?; + let var = Variable::from(var_idx); + if test(var) { + write!(wr, " {:?}", var)?; } } Ok(()) @@ -706,11 +604,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { { let wr = &mut wr as &mut dyn Write; write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]); - self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some()); + self.write_vars(wr, |var| self.rwu_table.get_reader(ln, var)); write!(wr, " writes"); - self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some()); + self.write_vars(wr, |var| self.rwu_table.get_writer(ln, var)); write!(wr, " uses"); - self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx)); + self.write_vars(wr, |var| self.rwu_table.get_used(ln, var)); write!(wr, " precedes {:?}]", self.successors[ln]); } @@ -735,100 +633,57 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.successors[ln] = Some(succ_ln); // It is not necessary to initialize the RWUs here because they are all - // set to INV_INV_FALSE when they are created, and the sets only grow - // during iterations. + // empty when created, and the sets only grow during iterations. } fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) { // more efficient version of init_empty() / merge_from_succ() self.successors[ln] = Some(succ_ln); - - self.indices2(ln, succ_ln, |this, idx, succ_idx| { - this.rwu_table.copy_packed(idx, succ_idx); - }); + self.rwu_table.copy(ln, succ_ln); debug!("init_from_succ(ln={}, succ={})", self.ln_str(ln), self.ln_str(succ_ln)); } - fn merge_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode, first_merge: bool) -> bool { + fn merge_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) -> bool { if ln == succ_ln { return false; } - let mut any_changed = false; - self.indices2(ln, succ_ln, |this, idx, succ_idx| { - // This is a special case, pulled out from the code below, where we - // don't have to do anything. It occurs about 60-70% of the time. - if this.rwu_table.packed_rwus[succ_idx] == INV_INV_FALSE { - return; - } - - let mut changed = false; - let mut rwu = this.rwu_table.get(idx); - let succ_rwu = this.rwu_table.get(succ_idx); - if succ_rwu.reader.is_some() && rwu.reader.is_none() { - rwu.reader = succ_rwu.reader; - changed = true - } - - if succ_rwu.writer.is_some() && rwu.writer.is_none() { - rwu.writer = succ_rwu.writer; - changed = true - } - - if succ_rwu.used && !rwu.used { - rwu.used = true; - changed = true; - } - - if changed { - this.rwu_table.assign_unpacked(idx, rwu); - any_changed = true; - } - }); - - debug!( - "merge_from_succ(ln={:?}, succ={}, first_merge={}, changed={})", - ln, - self.ln_str(succ_ln), - first_merge, - any_changed - ); - any_changed + let changed = self.rwu_table.union(ln, succ_ln); + debug!("merge_from_succ(ln={:?}, succ={}, changed={})", ln, self.ln_str(succ_ln), changed); + changed } // Indicates that a local variable was *defined*; we know that no // uses of the variable can precede the definition (resolve checks // this) so we just clear out all the data. fn define(&mut self, writer: LiveNode, var: Variable) { - let idx = self.idx(writer, var); - self.rwu_table.assign_inv_inv(idx); - - debug!("{:?} defines {:?} (idx={}): {}", writer, var, idx, self.ln_str(writer)); + let used = self.rwu_table.get_used(writer, var); + self.rwu_table.set(writer, var, rwu_table::RWU { reader: false, writer: false, used }); + debug!("{:?} defines {:?}: {}", writer, var, self.ln_str(writer)); } // Either read, write, or both depending on the acc bitset fn acc(&mut self, ln: LiveNode, var: Variable, acc: u32) { debug!("{:?} accesses[{:x}] {:?}: {}", ln, acc, var, self.ln_str(ln)); - let idx = self.idx(ln, var); - let mut rwu = self.rwu_table.get(idx); + let mut rwu = self.rwu_table.get(ln, var); if (acc & ACC_WRITE) != 0 { - rwu.reader = None; - rwu.writer = Some(ln); + rwu.reader = false; + rwu.writer = true; } // Important: if we both read/write, must do read second // or else the write will override. if (acc & ACC_READ) != 0 { - rwu.reader = Some(ln); + rwu.reader = true; } if (acc & ACC_USE) != 0 { rwu.used = true; } - self.rwu_table.assign_unpacked(idx, rwu); + self.rwu_table.set(ln, var, rwu); } fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode { @@ -850,14 +705,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // if they are live on the entry to the closure, since only the closure // itself can access them on subsequent calls. - if let Some(upvars) = self.upvars { + if let Some(closure_captures) = self.closure_captures { // Mark upvars captured by reference as used after closure exits. - for (&var_hir_id, upvar) in upvars.iter().rev() { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.body_owner, - }; - match self.typeck_results.upvar_capture(upvar_id) { + // Since closure_captures is Some, upvars must exists too. + let upvars = self.upvars.unwrap(); + for (&var_hir_id, upvar_id) in closure_captures { + let upvar = upvars[&var_hir_id]; + match self.typeck_results.upvar_capture(*upvar_id) { ty::UpvarCapture::ByRef(_) => { let var = self.variable(var_hir_id, upvar.span); self.acc(self.exit_ln, var, ACC_READ | ACC_USE); @@ -869,7 +723,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let succ = self.propagate_through_expr(&body.value, self.exit_ln); - if self.upvars.is_none() { + if self.closure_captures.is_none() { // Either not a closure, or closure without any captured variables. // No need to determine liveness of captured variables, since there // are none. @@ -895,7 +749,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }; // Propagate through calls to the closure. - let mut first_merge = true; loop { self.init_from_succ(self.closure_ln, succ); for param in body.params { @@ -905,10 +758,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }) } - if !self.merge_from_succ(self.exit_ln, self.closure_ln, first_merge) { + if !self.merge_from_succ(self.exit_ln, self.closure_ln) { break; } - first_merge = false; assert_eq!(succ, self.propagate_through_expr(&body.value, self.exit_ln)); } @@ -1014,17 +866,18 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // let ln = self.live_node(expr.hir_id, expr.span); self.init_empty(ln, succ); - let mut first_merge = true; for arm in arms { let body_succ = self.propagate_through_expr(&arm.body, succ); - let guard_succ = self.propagate_through_opt_expr( - arm.guard.as_ref().map(|hir::Guard::If(e)| *e), - body_succ, - ); + let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g { + hir::Guard::If(e) => self.propagate_through_expr(e, body_succ), + hir::Guard::IfLet(pat, e) => { + let let_bind = self.define_bindings_in_pat(pat, body_succ); + self.propagate_through_expr(e, let_bind) + } + }); let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ); - self.merge_from_succ(ln, arm_succ, first_merge); - first_merge = false; + self.merge_from_succ(ln, arm_succ); } self.propagate_through_expr(&e, ln) } @@ -1135,7 +988,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let ln = self.live_node(expr.hir_id, expr.span); self.init_from_succ(ln, succ); - self.merge_from_succ(ln, r_succ, false); + self.merge_from_succ(ln, r_succ); self.propagate_through_expr(&l, ln) } @@ -1163,7 +1016,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }; // Do a first pass for writing outputs only - for op in asm.operands.iter().rev() { + for (op, _op_sp) in asm.operands.iter().rev() { match op { hir::InlineAsmOperand::In { .. } | hir::InlineAsmOperand::Const { .. } @@ -1186,7 +1039,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Then do a second pass for inputs let mut succ = succ; - for op in asm.operands.iter().rev() { + for (op, _op_sp) in asm.operands.iter().rev() { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr, .. } @@ -1341,7 +1194,21 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { acc: u32, ) -> LiveNode { match path.res { - Res::Local(hid) => self.access_var(hir_id, hid, succ, acc, path.span), + Res::Local(hid) => { + let in_upvars = self.upvars.map_or(false, |u| u.contains_key(&hid)); + let in_captures = self.closure_captures.map_or(false, |c| c.contains_key(&hid)); + + match (in_upvars, in_captures) { + (false, _) | (true, true) => self.access_var(hir_id, hid, succ, acc, path.span), + (true, false) => { + // This case is possible when with RFC-2229, a wild pattern + // is used within a closure. + // eg: `let _ = x`. The closure doesn't capture x here, + // even though it's mentioned in the closure. + succ + } + } + } _ => succ, } } @@ -1365,7 +1232,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { */ // first iteration: - let mut first_merge = true; let ln = self.live_node(expr.hir_id, expr.span); self.init_empty(ln, succ); debug!("propagate_through_loop: using id for loop body {} {:?}", expr.hir_id, body); @@ -1377,8 +1243,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let body_ln = self.propagate_through_block(body, ln); // repeat until fixed point is reached: - while self.merge_from_succ(ln, body_ln, first_merge) { - first_merge = false; + while self.merge_from_succ(ln, body_ln) { assert_eq!(body_ln, self.propagate_through_block(body, ln)); } @@ -1429,7 +1294,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { } hir::ExprKind::InlineAsm(ref asm) => { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { @@ -1531,11 +1396,15 @@ impl<'tcx> Liveness<'_, 'tcx> { } fn warn_about_unused_upvars(&self, entry_ln: LiveNode) { - let upvars = match self.upvars { + let closure_captures = match self.closure_captures { None => return, - Some(upvars) => upvars, + Some(closure_captures) => closure_captures, }; - for (&var_hir_id, upvar) in upvars.iter() { + + // If closure_captures is Some(), upvars must be Some() too. + let upvars = self.upvars.unwrap(); + for &var_hir_id in closure_captures.keys() { + let upvar = upvars[&var_hir_id]; let var = self.variable(var_hir_id, upvar.span); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, @@ -1546,7 +1415,7 @@ impl<'tcx> Liveness<'_, 'tcx> { ty::UpvarCapture::ByRef(..) => continue, }; if self.used_on_entry(entry_ln, var) { - if self.live_on_entry(entry_ln, var).is_none() { + if !self.live_on_entry(entry_ln, var) { if let Some(name) = self.should_warn(var) { self.ir.tcx.struct_span_lint_hir( lint::builtin::UNUSED_ASSIGNMENTS, @@ -1580,7 +1449,7 @@ impl<'tcx> Liveness<'_, 'tcx> { fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) { for p in body.params { self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| { - if self.live_on_entry(ln, var).is_none() { + if !self.live_on_entry(ln, var) { self.report_unsed_assign(hir_id, spans, var, |name| { format!("value passed to `{}` is never read", name) }); @@ -1629,7 +1498,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // {ret}`, there is only one node, so asking about // assigned_on_exit() is not meaningful. let is_assigned = - if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; + if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) }; if is_assigned { self.ir.tcx.struct_span_lint_hir( @@ -1696,7 +1565,7 @@ impl<'tcx> Liveness<'_, 'tcx> { } fn warn_about_dead_assign(&self, spans: Vec, hir_id: HirId, ln: LiveNode, var: Variable) { - if self.live_on_exit(ln, var).is_none() { + if !self.live_on_exit(ln, var) { self.report_unsed_assign(hir_id, spans, var, |name| { format!("value assigned to `{}` is never read", name) }); diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs new file mode 100644 index 0000000000..a1a6f27398 --- /dev/null +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -0,0 +1,144 @@ +use crate::liveness::{LiveNode, Variable}; + +#[derive(Clone, Copy)] +pub(super) struct RWU { + pub(super) reader: bool, + pub(super) writer: bool, + pub(super) used: bool, +} + +/// Conceptually, this is like a `Vec>`. But the number of +/// RWU`s can get very large, so it uses a more compact representation. +pub(super) struct RWUTable { + /// Total number of live nodes. + live_nodes: usize, + /// Total number of variables. + vars: usize, + + /// A compressed representation of `RWU`s. + /// + /// Each word represents 2 different `RWU`s packed together. Each packed RWU + /// is stored in 4 bits: a reader bit, a writer bit, a used bit and a + /// padding bit. + /// + /// The data for each live node is contiguous and starts at a word boundary, + /// so there might be an unused space left. + words: Vec, + /// Number of words per each live node. + live_node_words: usize, +} + +impl RWUTable { + const RWU_READER: u8 = 0b0001; + const RWU_WRITER: u8 = 0b0010; + const RWU_USED: u8 = 0b0100; + const RWU_MASK: u8 = 0b1111; + + /// Size of packed RWU in bits. + const RWU_BITS: usize = 4; + /// Size of a word in bits. + const WORD_BITS: usize = std::mem::size_of::() * 8; + /// Number of packed RWUs that fit into a single word. + const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; + + pub(super) fn new(live_nodes: usize, vars: usize) -> RWUTable { + let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT; + Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] } + } + + fn word_and_shift(&self, ln: LiveNode, var: Variable) -> (usize, u32) { + assert!(ln.index() < self.live_nodes); + assert!(var.index() < self.vars); + + let var = var.index(); + let word = var / Self::WORD_RWU_COUNT; + let shift = Self::RWU_BITS * (var % Self::WORD_RWU_COUNT); + (ln.index() * self.live_node_words + word, shift as u32) + } + + fn pick2_rows_mut(&mut self, a: LiveNode, b: LiveNode) -> (&mut [u8], &mut [u8]) { + assert!(a.index() < self.live_nodes); + assert!(b.index() < self.live_nodes); + assert!(a != b); + + let a_start = a.index() * self.live_node_words; + let b_start = b.index() * self.live_node_words; + + unsafe { + let ptr = self.words.as_mut_ptr(); + ( + std::slice::from_raw_parts_mut(ptr.add(a_start), self.live_node_words), + std::slice::from_raw_parts_mut(ptr.add(b_start), self.live_node_words), + ) + } + } + + pub(super) fn copy(&mut self, dst: LiveNode, src: LiveNode) { + if dst == src { + return; + } + + let (dst_row, src_row) = self.pick2_rows_mut(dst, src); + dst_row.copy_from_slice(src_row); + } + + /// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was + /// changed. + pub(super) fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool { + if dst == src { + return false; + } + + let mut changed = false; + let (dst_row, src_row) = self.pick2_rows_mut(dst, src); + for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) { + let old = *dst_word; + let new = *dst_word | src_word; + *dst_word = new; + changed |= old != new; + } + changed + } + + pub(super) fn get_reader(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_READER != 0 + } + + pub(super) fn get_writer(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_WRITER != 0 + } + + pub(super) fn get_used(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_USED != 0 + } + + pub(super) fn get(&self, ln: LiveNode, var: Variable) -> RWU { + let (word, shift) = self.word_and_shift(ln, var); + let rwu_packed = self.words[word] >> shift; + RWU { + reader: rwu_packed & Self::RWU_READER != 0, + writer: rwu_packed & Self::RWU_WRITER != 0, + used: rwu_packed & Self::RWU_USED != 0, + } + } + + pub(super) fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) { + let mut packed = 0; + if rwu.reader { + packed |= Self::RWU_READER; + } + if rwu.writer { + packed |= Self::RWU_WRITER; + } + if rwu.used { + packed |= Self::RWU_USED; + } + + let (word, shift) = self.word_and_shift(ln, var); + let word = &mut self.words[word]; + *word = (*word & !(Self::RWU_MASK << shift)) | (packed << shift) + } +} diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs new file mode 100644 index 0000000000..5b50ef8627 --- /dev/null +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -0,0 +1,322 @@ +//! Checks validity of naked functions. + +use rustc_ast::InlineAsmOptions; +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS; +use rustc_span::symbol::sym; +use rustc_span::Span; +use rustc_target::spec::abi::Abi; + +fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { + tcx.hir().visit_item_likes_in_module( + module_def_id, + &mut CheckNakedFunctions { tcx }.as_deep_visitor(), + ); +} + +crate fn provide(providers: &mut Providers) { + *providers = Providers { check_mod_naked_functions, ..*providers }; +} + +struct CheckNakedFunctions<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { + type Map = ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_fn( + &mut self, + fk: FnKind<'v>, + _fd: &'tcx hir::FnDecl<'tcx>, + body_id: hir::BodyId, + span: Span, + hir_id: HirId, + ) { + let ident_span; + let fn_header; + + match fk { + FnKind::Closure(..) => { + // Closures with a naked attribute are rejected during attribute + // check. Don't validate them any further. + return; + } + FnKind::ItemFn(ident, _, ref header, ..) => { + ident_span = ident.span; + fn_header = header; + } + + FnKind::Method(ident, ref sig, ..) => { + ident_span = ident.span; + fn_header = &sig.header; + } + } + + let naked = fk.attrs().iter().any(|attr| attr.has_name(sym::naked)); + if naked { + let body = self.tcx.hir().body(body_id); + check_abi(self.tcx, hir_id, fn_header.abi, ident_span); + check_no_patterns(self.tcx, body.params); + check_no_parameters_use(self.tcx, body); + check_asm(self.tcx, hir_id, body, span); + } + } +} + +/// Checks that function uses non-Rust ABI. +fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) { + if abi == Abi::Rust { + tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_ident_span, |lint| { + lint.build("Rust ABI is unsupported in naked functions").emit(); + }); + } +} + +/// Checks that parameters don't use patterns. Mirrors the checks for function declarations. +fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { + for param in params { + match param.pat.kind { + hir::PatKind::Wild + | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {} + _ => { + tcx.sess + .struct_span_err( + param.pat.span, + "patterns not allowed in naked function parameters", + ) + .emit(); + } + } + } +} + +/// Checks that function parameters aren't used in the function body. +fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { + let mut params = hir::HirIdSet::default(); + for param in body.params { + param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| { + params.insert(hir_id); + }); + } + CheckParameters { tcx, params }.visit_body(body); +} + +struct CheckParameters<'tcx> { + tcx: TyCtxt<'tcx>, + params: hir::HirIdSet, +} + +impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { + type Map = ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: hir::def::Res::Local(var_hir_id), .. }, + )) = expr.kind + { + if self.params.contains(var_hir_id) { + self.tcx + .sess + .struct_span_err( + expr.span, + "referencing function parameters is not allowed in naked functions", + ) + .help("follow the calling convention in asm block to use parameters") + .emit(); + return; + } + } + hir::intravisit::walk_expr(self, expr); + } +} + +/// Checks that function body contains a single inline assembly block. +fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) { + let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; + this.visit_body(body); + if let &[(ItemKind::Asm, _)] = &this.items[..] { + // Ok. + } else { + tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| { + let mut diag = lint.build("naked functions must contain a single asm block"); + let mut has_asm = false; + for &(kind, span) in &this.items { + match kind { + ItemKind::Asm if has_asm => { + diag.span_label( + span, + "multiple asm blocks are unsupported in naked functions", + ); + } + ItemKind::Asm => has_asm = true, + ItemKind::NonAsm => { + diag.span_label(span, "non-asm is unsupported in naked functions"); + } + } + } + diag.emit(); + }); + } +} + +struct CheckInlineAssembly<'tcx> { + tcx: TyCtxt<'tcx>, + items: Vec<(ItemKind, Span)>, +} + +#[derive(Copy, Clone)] +enum ItemKind { + Asm, + NonAsm, +} + +impl<'tcx> CheckInlineAssembly<'tcx> { + fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { + match expr.kind { + ExprKind::Box(..) + | ExprKind::ConstBlock(..) + | ExprKind::Array(..) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Tup(..) + | ExprKind::Binary(..) + | ExprKind::Unary(..) + | ExprKind::Lit(..) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Closure(..) + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Path(..) + | ExprKind::AddrOf(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::Struct(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) => { + self.items.push((ItemKind::NonAsm, span)); + } + + ExprKind::InlineAsm(ref asm) => { + self.items.push((ItemKind::Asm, span)); + self.check_inline_asm(expr.hir_id, asm, span); + } + + ExprKind::LlvmInlineAsm(..) => { + self.items.push((ItemKind::Asm, span)); + self.tcx.struct_span_lint_hir( + UNSUPPORTED_NAKED_FUNCTIONS, + expr.hir_id, + span, + |lint| { + lint.build( + "the LLVM-style inline assembly is unsupported in naked functions", + ) + .help("use the new asm! syntax specified in RFC 2873") + .emit(); + }, + ); + } + + ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => { + hir::intravisit::walk_expr(self, expr); + } + } + } + + fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { + let unsupported_operands: Vec = asm + .operands + .iter() + .filter_map(|&(ref op, op_sp)| match op { + InlineAsmOperand::Const { .. } | InlineAsmOperand::Sym { .. } => None, + InlineAsmOperand::In { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::InOut { .. } + | InlineAsmOperand::SplitInOut { .. } => Some(op_sp), + }) + .collect(); + if !unsupported_operands.is_empty() { + self.tcx.struct_span_lint_hir( + UNSUPPORTED_NAKED_FUNCTIONS, + hir_id, + unsupported_operands, + |lint| { + lint.build("only `const` and `sym` operands are supported in naked functions") + .emit(); + }, + ); + } + + let unsupported_options: Vec<&'static str> = [ + (InlineAsmOptions::NOMEM, "`nomem`"), + (InlineAsmOptions::NOSTACK, "`nostack`"), + (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"), + (InlineAsmOptions::PURE, "`pure`"), + (InlineAsmOptions::READONLY, "`readonly`"), + ] + .iter() + .filter_map(|&(option, name)| if asm.options.contains(option) { Some(name) } else { None }) + .collect(); + + if !unsupported_options.is_empty() { + self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { + lint.build(&format!( + "asm options unsupported in naked functions: {}", + unsupported_options.join(", ") + )) + .emit(); + }); + } + + if !asm.options.contains(InlineAsmOptions::NORETURN) { + self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { + lint.build("asm in naked functions must use `noreturn` option").emit(); + }); + } + } +} + +impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { + type Map = ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { + match stmt.kind { + StmtKind::Item(..) => {} + StmtKind::Local(..) => { + self.items.push((ItemKind::NonAsm, stmt.span)); + } + StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { + self.check_expr(expr, stmt.span); + } + } + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + self.check_expr(&expr, expr.span); + } +} diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 8d5c980609..fde83af99a 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -262,7 +262,7 @@ impl<'tcx> ReachableContext<'tcx> { | hir::ItemKind::TyAlias(..) | hir::ItemKind::Static(..) | hir::ItemKind::Mod(..) - | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) @@ -378,6 +378,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) { // processed in visit_item above } + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) { + // We never export foreign functions as they have no body to export. + } } fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> FxHashSet { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 04b5c65e46..3c2462aab2 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -182,28 +182,32 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { for (dep_v, stab_v) in dep_since.as_str().split('.').zip(stab_since.as_str().split('.')) { - if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::(), stab_v.parse()) { - match dep_v.cmp(&stab_v) { - Ordering::Less => { - self.tcx.sess.span_err( - item_sp, - "An API can't be stabilized \ - after it is deprecated", - ); + match stab_v.parse::() { + Err(_) => { + self.tcx.sess.span_err(item_sp, "Invalid stability version found"); + break; + } + Ok(stab_vp) => match dep_v.parse::() { + Ok(dep_vp) => match dep_vp.cmp(&stab_vp) { + Ordering::Less => { + self.tcx.sess.span_err( + item_sp, + "An API can't be stabilized after it is deprecated", + ); + break; + } + Ordering::Equal => continue, + Ordering::Greater => break, + }, + Err(_) => { + if dep_v != "TBD" { + self.tcx + .sess + .span_err(item_sp, "Invalid deprecation version found"); + } break; } - Ordering::Equal => continue, - Ordering::Greater => break, - } - } else { - // Act like it isn't less because the question is now nonsensical, - // and this makes us not do anything else interesting. - self.tcx.sess.span_err( - item_sp, - "Invalid stability or deprecation \ - version found", - ); - break; + }, } } } @@ -326,7 +330,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { // they don't have their own stability. They still can be annotated as unstable // and propagate this unstability to children, but this annotation is completely // optional. They inherit stability from their parents when unannotated. - hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) => { + hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. } => { self.in_trait_impl = false; kind = AnnotationKind::Container; } @@ -499,7 +503,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { // optional. They inherit stability from their parents when unannotated. if !matches!( i.kind, - hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) + hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. } ) { self.check_missing_stability(i.hir_id, i.span); } diff --git a/compiler/rustc_plugin_impl/src/build.rs b/compiler/rustc_plugin_impl/src/build.rs index d16dd701a1..4796d9a80b 100644 --- a/compiler/rustc_plugin_impl/src/build.rs +++ b/compiler/rustc_plugin_impl/src/build.rs @@ -25,6 +25,8 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for RegistrarFinder<'tcx> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } /// Finds the function marked with `#[plugin_registrar]`, if any. diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 75d75433f1..3b4249a93e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -4,6 +4,7 @@ #![feature(or_patterns)] #![feature(control_flow_enum)] #![feature(try_blocks)] +#![feature(associated_type_defaults)] #![recursion_limit = "256"] use rustc_attr as attr; @@ -44,6 +45,8 @@ use std::{cmp, fmt, mem}; /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`. trait DefIdVisitor<'tcx> { + type BreakTy = (); + fn tcx(&self) -> TyCtxt<'tcx>; fn shallow(&self) -> bool { false @@ -56,7 +59,7 @@ trait DefIdVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()>; + ) -> ControlFlow; /// Not overridden, but used to actually visit types and traits. fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { @@ -66,13 +69,16 @@ trait DefIdVisitor<'tcx> { dummy: Default::default(), } } - fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<()> { + fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow { ty_fragment.visit_with(&mut self.skeleton()) } - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { self.skeleton().visit_trait(trait_ref) } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { + fn visit_predicates( + &mut self, + predicates: ty::GenericPredicates<'tcx>, + ) -> ControlFlow { self.skeleton().visit_predicates(predicates) } } @@ -87,13 +93,13 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { let TraitRef { def_id, substs } = trait_ref; self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { match predicate.skip_binders() { ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => { self.visit_trait(trait_ref) @@ -119,7 +125,10 @@ where } } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { + fn visit_predicates( + &mut self, + predicates: ty::GenericPredicates<'tcx>, + ) -> ControlFlow { let ty::GenericPredicates { parent: _, predicates } = predicates; predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate)) } @@ -129,7 +138,9 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = V::BreakTy; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. match *ty.kind() { @@ -173,8 +184,8 @@ where ty::Dynamic(predicates, ..) => { // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. - for predicate in predicates.skip_binder() { - let trait_ref = match predicate { + for predicate in predicates { + let trait_ref = match predicate.skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), ty::ExistentialPredicate::AutoTrait(def_id) => { @@ -283,7 +294,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> def_id: DefId, _kind: &str, _descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { self.min = VL::new_min(self, def_id); ControlFlow::CONTINUE } @@ -581,7 +592,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { Option::::of_impl(item.hir_id, self.tcx, &self.access_levels) } // Foreign modules inherit level from parents. - hir::ItemKind::ForeignMod(..) => self.prev_level, + hir::ItemKind::ForeignMod { .. } => self.prev_level, // Other `pub` items inherit levels from parents. hir::ItemKind::Const(..) | hir::ItemKind::Enum(..) @@ -643,10 +654,10 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::ForeignMod(ref foreign_mod) => { - for foreign_item in foreign_mod.items { + hir::ItemKind::ForeignMod { items, .. } => { + for foreign_item in items { if foreign_item.vis.node.is_pub() { - self.update(foreign_item.hir_id, item_level); + self.update(foreign_item.id.hir_id, item_level); } } } @@ -680,7 +691,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { hir::ItemKind::GlobalAsm(..) => {} hir::ItemKind::OpaqueTy(..) => { // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general) - // Since rustdoc never need to do codegen and doesn't care about link-time reachability, + // Since rustdoc never needs to do codegen and doesn't care about link-time reachability, // mark this as unreachable. // See https://github.com/rust-lang/rust/issues/75100 if !self.tcx.sess.opts.actually_rustdoc { @@ -759,11 +770,11 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { } } // Visit everything, but foreign items have their own levels. - hir::ItemKind::ForeignMod(ref foreign_mod) => { - for foreign_item in foreign_mod.items { - let foreign_item_level = self.get(foreign_item.hir_id); + hir::ItemKind::ForeignMod { items, .. } => { + for foreign_item in items { + let foreign_item_level = self.get(foreign_item.id.hir_id); if foreign_item_level.is_some() { - self.reach(foreign_item.hir_id, foreign_item_level) + self.reach(foreign_item.id.hir_id, foreign_item_level) .generics() .predicates() .ty(); @@ -902,7 +913,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { def_id: DefId, _kind: &str, _descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { if let Some(def_id) = def_id.as_local() { if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) = (self.tcx().visibility(def_id.to_def_id()), self.access_level) @@ -1299,7 +1310,7 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { ControlFlow::BREAK } else { @@ -1419,7 +1430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // An `extern {}` doesn't introduce a new privacy // namespace (the contents have their own privacies). - hir::ItemKind::ForeignMod(_) => {} + hir::ItemKind::ForeignMod { .. } => {} hir::ItemKind::Trait(.., ref bounds, _) => { if !self.trait_is_public(item.hir_id) { @@ -1799,7 +1810,7 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { def_id: DefId, kind: &str, descr: &dyn fmt::Display, - ) -> ControlFlow<()> { + ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { ControlFlow::BREAK } else { @@ -1937,10 +1948,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> } } // Subitems of foreign modules have their own publicity. - hir::ItemKind::ForeignMod(ref foreign_mod) => { - for foreign_item in foreign_mod.items { - let vis = tcx.visibility(tcx.hir().local_def_id(foreign_item.hir_id)); - self.check(foreign_item.hir_id, vis).generics().predicates().ty(); + hir::ItemKind::ForeignMod { items, .. } => { + for foreign_item in items { + let vis = tcx.visibility(tcx.hir().local_def_id(foreign_item.id.hir_id)); + self.check(foreign_item.id.hir_id, vis).generics().predicates().ty(); } } // Subitems of structs and unions have their own publicity. diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 7808a28dff..ff52fdab19 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -44,7 +44,7 @@ use super::{DepContext, DepKind}; -use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use std::fmt; @@ -53,7 +53,19 @@ use std::hash::Hash; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] pub struct DepNode { pub kind: K, - pub hash: Fingerprint, + // Important - whenever a `DepNode` is constructed, we need to make + // sure to register a `DefPathHash -> DefId` mapping if needed. + // This is currently done in two places: + // + // * When a `DepNode::construct` is called, `arg.to_fingerprint()` + // is responsible for calling `OnDiskCache::store_foreign_def_id_hash` + // if needed + // * When we serialize the on-disk cache, `OnDiskCache::serialize` is + // responsible for calling `DepGraph::register_reused_dep_nodes`. + // + // FIXME: Enforce this by preventing manual construction of `DefNode` + // (e.g. add a `_priv: ()` field) + pub hash: PackedFingerprint, } impl DepNode { @@ -62,7 +74,7 @@ impl DepNode { /// does not require any parameters. pub fn new_no_params(kind: K) -> DepNode { debug_assert!(!kind.has_params()); - DepNode { kind, hash: Fingerprint::ZERO } + DepNode { kind, hash: Fingerprint::ZERO.into() } } pub fn construct(tcx: Ctxt, kind: K, arg: &Key) -> DepNode @@ -71,7 +83,7 @@ impl DepNode { Key: DepNodeParams, { let hash = arg.to_fingerprint(tcx); - let dep_node = DepNode { kind, hash }; + let dep_node = DepNode { kind, hash: hash.into() }; #[cfg(debug_assertions)] { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index d9b687c48a..605d7ae4af 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, LockGuard, Lrc, Ordering}; use rustc_data_structures::unlikely; use rustc_errors::Diagnostic; use rustc_index::vec::{Idx, IndexVec}; @@ -15,6 +15,7 @@ use std::env; use std::hash::Hash; use std::marker::PhantomData; use std::mem; +use std::ops::Range; use std::sync::atomic::Ordering::Relaxed; use super::debug::EdgeFilter; @@ -68,7 +69,7 @@ struct DepGraphData { /// The new encoding of the dependency graph, optimized for red/green /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into - /// current one anymore. + /// current one anymore, but we do reference shared data to save space. current: CurrentDepGraph, /// The dep-graph from the previous compilation session. It contains all @@ -134,17 +135,61 @@ impl DepGraph { } pub fn query(&self) -> DepGraphQuery { - let data = self.data.as_ref().unwrap().current.data.lock(); - let nodes: Vec<_> = data.iter().map(|n| n.node).collect(); - let mut edges = Vec::new(); - for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) { - for &edge_target in edge_targets.iter() { - let to = data[edge_target].node; - edges.push((from, to)); + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + + // Note locking order: `prev_index_to_index`, then `data`. + let prev_index_to_index = data.current.prev_index_to_index.lock(); + let data = data.current.data.lock(); + let node_count = data.hybrid_indices.len(); + let edge_count = self.edge_count(&data); + + let mut nodes = Vec::with_capacity(node_count); + let mut edge_list_indices = Vec::with_capacity(node_count); + let mut edge_list_data = Vec::with_capacity(edge_count); + + // See `serialize` for notes on the approach used here. + + edge_list_data.extend(data.unshared_edges.iter().map(|i| i.index())); + + for &hybrid_index in data.hybrid_indices.iter() { + match hybrid_index.into() { + HybridIndex::New(new_index) => { + nodes.push(data.new.nodes[new_index]); + let edges = &data.new.edges[new_index]; + edge_list_indices.push((edges.start.index(), edges.end.index())); + } + HybridIndex::Red(red_index) => { + nodes.push(previous.index_to_node(data.red.node_indices[red_index])); + let edges = &data.red.edges[red_index]; + edge_list_indices.push((edges.start.index(), edges.end.index())); + } + HybridIndex::LightGreen(lg_index) => { + nodes.push(previous.index_to_node(data.light_green.node_indices[lg_index])); + let edges = &data.light_green.edges[lg_index]; + edge_list_indices.push((edges.start.index(), edges.end.index())); + } + HybridIndex::DarkGreen(prev_index) => { + nodes.push(previous.index_to_node(prev_index)); + + let edges_iter = previous + .edge_targets_from(prev_index) + .iter() + .map(|&dst| prev_index_to_index[dst].unwrap().index()); + + let start = edge_list_data.len(); + edge_list_data.extend(edges_iter); + let end = edge_list_data.len(); + edge_list_indices.push((start, end)); + } } } - DepGraphQuery::new(&nodes[..], &edges[..]) + debug_assert_eq!(nodes.len(), node_count); + debug_assert_eq!(edge_list_indices.len(), node_count); + debug_assert_eq!(edge_list_data.len(), edge_count); + + DepGraphQuery::new(&nodes[..], &edge_list_indices[..], &edge_list_data[..]) } pub fn assert_ignored(&self) { @@ -201,7 +246,6 @@ impl DepGraph { key, cx, arg, - false, task, |_key| { Some(TaskDeps { @@ -212,7 +256,6 @@ impl DepGraph { phantom_data: PhantomData, }) }, - |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), hash_result, ) } @@ -222,66 +265,69 @@ impl DepGraph { key: DepNode, cx: Ctxt, arg: A, - no_tcx: bool, task: fn(Ctxt, A) -> R, create_task: fn(DepNode) -> Option>, - finish_task_and_alloc_depnode: fn( - &CurrentDepGraph, - DepNode, - Fingerprint, - Option>, - ) -> DepNodeIndex, hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, ) -> (R, DepNodeIndex) { if let Some(ref data) = self.data { let task_deps = create_task(key).map(Lock::new); + let result = K::with_deps(task_deps.as_ref(), || task(cx, arg)); + let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); - // In incremental mode, hash the result of the task. We don't - // do anything with the hash yet, but we are computing it - // anyway so that - // - we make sure that the infrastructure works and - // - we can get an idea of the runtime cost. let mut hcx = cx.create_stable_hashing_context(); - - let result = if no_tcx { - task(cx, arg) - } else { - K::with_deps(task_deps.as_ref(), || task(cx, arg)) - }; - let current_fingerprint = hash_result(&mut hcx, &result); - let dep_node_index = finish_task_and_alloc_depnode( - &data.current, - key, - current_fingerprint.unwrap_or(Fingerprint::ZERO), - task_deps.map(|lock| lock.into_inner()), - ); - let print_status = cfg!(debug_assertions) && cx.debug_dep_tasks(); - // Determine the color of the new DepNode. - if let Some(prev_index) = data.previous.node_to_index_opt(&key) { - let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - - let color = if let Some(current_fingerprint) = current_fingerprint { - if current_fingerprint == prev_fingerprint { + // Intern the new `DepNode`. + let dep_node_index = if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + // Determine the color and index of the new `DepNode`. + let (color, dep_node_index) = if let Some(current_fingerprint) = current_fingerprint + { + if current_fingerprint == data.previous.fingerprint_by_index(prev_index) { if print_status { eprintln!("[task::green] {:?}", key); } - DepNodeColor::Green(dep_node_index) + + // This is a light green node: it existed in the previous compilation, + // its query was re-executed, and it has the same result as before. + let dep_node_index = + data.current.intern_light_green_node(&data.previous, prev_index, edges); + + (DepNodeColor::Green(dep_node_index), dep_node_index) } else { if print_status { eprintln!("[task::red] {:?}", key); } - DepNodeColor::Red + + // This is a red node: it existed in the previous compilation, its query + // was re-executed, but it has a different result from before. + let dep_node_index = data.current.intern_red_node( + &data.previous, + prev_index, + edges, + current_fingerprint, + ); + + (DepNodeColor::Red, dep_node_index) } } else { if print_status { eprintln!("[task::unknown] {:?}", key); } - // Mark the node as Red if we can't hash the result - DepNodeColor::Red + + // This is a red node, effectively: it existed in the previous compilation + // session, its query was re-executed, but it doesn't compute a result hash + // (i.e. it represents a `no_hash` query), so we have no way of determining + // whether or not the result was the same as before. + let dep_node_index = data.current.intern_red_node( + &data.previous, + prev_index, + edges, + Fingerprint::ZERO, + ); + + (DepNodeColor::Red, dep_node_index) }; debug_assert!( @@ -292,12 +338,27 @@ impl DepGraph { ); data.colors.insert(prev_index, color); - } else if print_status { - eprintln!("[task::new] {:?}", key); - } + dep_node_index + } else { + if print_status { + eprintln!("[task::new] {:?}", key); + } + + // This is a new node: it didn't exist in the previous compilation session. + data.current.intern_new_node( + &data.previous, + key, + edges, + current_fingerprint.unwrap_or(Fingerprint::ZERO), + ) + }; (result, dep_node_index) } else { + // Incremental compilation is turned off. We just execute the task + // without tracking. We still provide a dep-node index that uniquely + // identifies the task so that we have a cheap way of referring to + // the query for self-profiling. (task(cx, arg), self.next_virtual_depnode_index()) } } @@ -308,13 +369,36 @@ impl DepGraph { where OP: FnOnce() -> R, { + debug_assert!(!dep_kind.is_eval_always()); + if let Some(ref data) = self.data { let task_deps = Lock::new(TaskDeps::default()); - let result = K::with_deps(Some(&task_deps), op); let task_deps = task_deps.into_inner(); - let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps); + // The dep node indices are hashed here instead of hashing the dep nodes of the + // dependencies. These indices may refer to different nodes per session, but this isn't + // a problem here because we that ensure the final dep node hash is per session only by + // combining it with the per session random number `anon_id_seed`. This hash only need + // to map the dependencies to a single value on a per session basis. + let mut hasher = StableHasher::new(); + task_deps.reads.hash(&mut hasher); + + let target_dep_node = DepNode { + kind: dep_kind, + // Fingerprint::combine() is faster than sending Fingerprint + // through the StableHasher (at least as long as StableHasher + // is so slow). + hash: data.current.anon_id_seed.combine(hasher.finish()).into(), + }; + + let dep_node_index = data.current.intern_new_node( + &data.previous, + target_dep_node, + task_deps.reads, + Fingerprint::ZERO, + ); + (result, dep_node_index) } else { (op(), self.next_virtual_depnode_index()) @@ -331,69 +415,106 @@ impl DepGraph { task: fn(Ctxt, A) -> R, hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option, ) -> (R, DepNodeIndex) { - self.with_task_impl( - key, - cx, - arg, - false, - task, - |_| None, - |data, key, fingerprint, _| data.alloc_node(key, smallvec![], fingerprint), - hash_result, - ) + self.with_task_impl(key, cx, arg, task, |_| None, hash_result) } #[inline] - pub fn read(&self, v: DepNode) { + pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { - let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); - if let Some(dep_node_index) = map.get(&v).copied() { - std::mem::drop(map); - data.read_index(dep_node_index); - } else { - panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind) - } + K::read_deps(|task_deps| { + if let Some(task_deps) = task_deps { + let mut task_deps = task_deps.lock(); + let task_deps = &mut *task_deps; + if cfg!(debug_assertions) { + data.current.total_read_count.fetch_add(1, Relaxed); + } + + // As long as we only have a low number of reads we can avoid doing a hash + // insert and potentially allocating/reallocating the hashmap + let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { + task_deps.reads.iter().all(|other| *other != dep_node_index) + } else { + task_deps.read_set.insert(dep_node_index) + }; + if new_read { + task_deps.reads.push(dep_node_index); + if task_deps.reads.len() == TASK_DEPS_READS_CAP { + // Fill `read_set` with what we have so far so we can use the hashset + // next time + task_deps.read_set.extend(task_deps.reads.iter().copied()); + } + + #[cfg(debug_assertions)] + { + if let Some(target) = task_deps.node { + if let Some(ref forbidden_edge) = data.current.forbidden_edge { + let src = self.dep_node_of(dep_node_index); + if forbidden_edge.test(&src, &target) { + panic!("forbidden edge {:?} -> {:?} created", src, target) + } + } + } + } + } else if cfg!(debug_assertions) { + data.current.total_duplicate_read_count.fetch_add(1, Relaxed); + } + } + }) } } #[inline] - pub fn read_index(&self, dep_node_index: DepNodeIndex) { - if let Some(ref data) = self.data { - data.read_index(dep_node_index); - } + pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { + self.dep_node_index_of_opt(dep_node).unwrap() } #[inline] - pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { - self.data - .as_ref() - .unwrap() - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .get(dep_node) - .cloned() - .unwrap() + pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option { + let data = self.data.as_ref().unwrap(); + let current = &data.current; + + if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { + current.prev_index_to_index.lock()[prev_index] + } else { + current.new_node_to_index.get_shard_by_value(dep_node).lock().get(dep_node).copied() + } } #[inline] pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { - if let Some(ref data) = self.data { - data.current - .node_to_node_index - .get_shard_by_value(&dep_node) - .lock() - .contains_key(dep_node) - } else { - false + self.data.is_some() && self.dep_node_index_of_opt(dep_node).is_some() + } + + #[inline] + pub fn dep_node_of(&self, dep_node_index: DepNodeIndex) -> DepNode { + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + let data = data.current.data.lock(); + + match data.hybrid_indices[dep_node_index].into() { + HybridIndex::New(new_index) => data.new.nodes[new_index], + HybridIndex::Red(red_index) => previous.index_to_node(data.red.node_indices[red_index]), + HybridIndex::LightGreen(light_green_index) => { + previous.index_to_node(data.light_green.node_indices[light_green_index]) + } + HybridIndex::DarkGreen(prev_index) => previous.index_to_node(prev_index), } } #[inline] pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { - let data = self.data.as_ref().expect("dep graph enabled").current.data.lock(); - data[dep_node_index].fingerprint + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + let data = data.current.data.lock(); + + match data.hybrid_indices[dep_node_index].into() { + HybridIndex::New(new_index) => data.new.fingerprints[new_index], + HybridIndex::Red(red_index) => data.red.fingerprints[red_index], + HybridIndex::LightGreen(light_green_index) => { + previous.fingerprint_by_index(data.light_green.node_indices[light_green_index]) + } + HybridIndex::DarkGreen(prev_index) => previous.fingerprint_by_index(prev_index), + } } pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { @@ -443,30 +564,95 @@ impl DepGraph { } } - pub fn serialize(&self) -> SerializedDepGraph { - let data = self.data.as_ref().unwrap().current.data.lock(); + fn edge_count(&self, node_data: &LockGuard<'_, DepNodeData>) -> usize { + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; - let fingerprints: IndexVec = - data.iter().map(|d| d.fingerprint).collect(); - let nodes: IndexVec = data.iter().map(|d| d.node).collect(); + let mut edge_count = node_data.unshared_edges.len(); - let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum(); + for &hybrid_index in node_data.hybrid_indices.iter() { + if let HybridIndex::DarkGreen(prev_index) = hybrid_index.into() { + edge_count += previous.edge_targets_from(prev_index).len() + } + } - let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); - let mut edge_list_data = Vec::with_capacity(total_edge_count); + edge_count + } - for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) { - let start = edge_list_data.len() as u32; - // This should really just be a memcpy :/ - edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index()))); - let end = edge_list_data.len() as u32; + pub fn serialize(&self) -> SerializedDepGraph { + type SDNI = SerializedDepNodeIndex; - debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len()); - edge_list_indices.push((start, end)); + let data = self.data.as_ref().unwrap(); + let previous = &data.previous; + + // Note locking order: `prev_index_to_index`, then `data`. + let prev_index_to_index = data.current.prev_index_to_index.lock(); + let data = data.current.data.lock(); + let node_count = data.hybrid_indices.len(); + let edge_count = self.edge_count(&data); + + let mut nodes = IndexVec::with_capacity(node_count); + let mut fingerprints = IndexVec::with_capacity(node_count); + let mut edge_list_indices = IndexVec::with_capacity(node_count); + let mut edge_list_data = Vec::with_capacity(edge_count); + + // `rustc_middle::ty::query::OnDiskCache` expects nodes to be in + // `DepNodeIndex` order. The edges in `edge_list_data`, on the other + // hand, don't need to be in a particular order, as long as each node + // can reference its edges as a contiguous range within it. This is why + // we're able to copy `unshared_edges` directly into `edge_list_data`. + // It meets the above requirements, and each non-dark-green node already + // knows the range of edges to reference within it, which they'll push + // onto `edge_list_indices`. Dark green nodes, however, don't have their + // edges in `unshared_edges`, so need to add them to `edge_list_data`. + + edge_list_data.extend(data.unshared_edges.iter().map(|i| SDNI::new(i.index()))); + + for &hybrid_index in data.hybrid_indices.iter() { + match hybrid_index.into() { + HybridIndex::New(i) => { + let new = &data.new; + nodes.push(new.nodes[i]); + fingerprints.push(new.fingerprints[i]); + let edges = &new.edges[i]; + edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32())); + } + HybridIndex::Red(i) => { + let red = &data.red; + nodes.push(previous.index_to_node(red.node_indices[i])); + fingerprints.push(red.fingerprints[i]); + let edges = &red.edges[i]; + edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32())); + } + HybridIndex::LightGreen(i) => { + let lg = &data.light_green; + nodes.push(previous.index_to_node(lg.node_indices[i])); + fingerprints.push(previous.fingerprint_by_index(lg.node_indices[i])); + let edges = &lg.edges[i]; + edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32())); + } + HybridIndex::DarkGreen(prev_index) => { + nodes.push(previous.index_to_node(prev_index)); + fingerprints.push(previous.fingerprint_by_index(prev_index)); + + let edges_iter = previous + .edge_targets_from(prev_index) + .iter() + .map(|&dst| prev_index_to_index[dst].as_ref().unwrap()); + + let start = edge_list_data.len() as u32; + edge_list_data.extend(edges_iter.map(|i| SDNI::new(i.index()))); + let end = edge_list_data.len() as u32; + edge_list_indices.push((start, end)); + } + } } + debug_assert_eq!(nodes.len(), node_count); + debug_assert_eq!(fingerprints.len(), node_count); + debug_assert_eq!(edge_list_indices.len(), node_count); + debug_assert_eq!(edge_list_data.len(), edge_count); debug_assert!(edge_list_data.len() <= u32::MAX as usize); - debug_assert_eq!(edge_list_data.len(), total_edge_count); SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data } } @@ -540,14 +726,7 @@ impl DepGraph { #[cfg(not(parallel_compiler))] { - debug_assert!( - !data - .current - .node_to_node_index - .get_shard_by_value(dep_node) - .lock() - .contains_key(dep_node) - ); + debug_assert!(!self.dep_node_exists(dep_node)); debug_assert!(data.colors.get(prev_dep_node_index).is_none()); } @@ -558,13 +737,11 @@ impl DepGraph { let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); - let mut current_deps = SmallVec::new(); - for &dep_dep_node_index in prev_deps { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { + Some(DepNodeColor::Green(_)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other // dependencies. @@ -574,7 +751,6 @@ impl DepGraph { dep_node, data.previous.index_to_node(dep_dep_node_index) ); - current_deps.push(node_index); } Some(DepNodeColor::Red) => { // We found a dependency the value of which has changed @@ -596,9 +772,9 @@ impl DepGraph { // an eval_always node, let's try to mark it green recursively. if !dep_dep_node.kind.is_eval_always() { debug!( - "try_mark_previous_green({:?}) --- state of dependency {:?} \ + "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \ is unknown, trying to mark it green", - dep_node, dep_dep_node + dep_node, dep_dep_node, dep_dep_node.hash, ); let node_index = self.try_mark_previous_green( @@ -607,13 +783,12 @@ impl DepGraph { dep_dep_node_index, dep_dep_node, ); - if let Some(node_index) = node_index { + if node_index.is_some() { debug!( "try_mark_previous_green({:?}) --- managed to MARK \ dependency {:?} as green", dep_node, dep_dep_node ); - current_deps.push(node_index); continue; } } @@ -628,13 +803,12 @@ impl DepGraph { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { - Some(DepNodeColor::Green(node_index)) => { + Some(DepNodeColor::Green(_)) => { debug!( "try_mark_previous_green({:?}) --- managed to \ FORCE dependency {:?} to green", dep_node, dep_dep_node ); - current_deps.push(node_index); } Some(DepNodeColor::Red) => { debug!( @@ -690,13 +864,9 @@ impl DepGraph { // There may be multiple threads trying to mark the same dep node green concurrently let dep_node_index = { - // Copy the fingerprint from the previous graph, - // so we don't have to recompute it - let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index); - // We allocating an entry for the node in the current dependency graph and // adding all the appropriate edges imported from the previous graph - data.current.intern_node(*dep_node, current_deps, fingerprint) + data.current.intern_dark_green_node(&data.previous, prev_dep_node_index) }; // ... emitting any stored diagnostic ... @@ -813,6 +983,20 @@ impl DepGraph { } } + // Register reused dep nodes (i.e. nodes we've marked red or green) with the context. + pub fn register_reused_dep_nodes>(&self, tcx: Ctxt) { + let data = self.data.as_ref().unwrap(); + for prev_index in data.colors.values.indices() { + match data.colors.get(prev_index) { + Some(DepNodeColor::Red) | Some(DepNodeColor::Green(_)) => { + let dep_node = data.previous.index_to_node(prev_index); + tcx.register_reused_dep_node(&dep_node); + } + None => {} + } + } + } + fn next_virtual_depnode_index(&self) -> DepNodeIndex { let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); DepNodeIndex::from_u32(index) @@ -857,31 +1041,234 @@ pub struct WorkProduct { pub saved_file: Option, } -#[derive(Clone)] +// The maximum value of the follow index types leaves the upper two bits unused +// so that we can store multiple index types in `CompressedHybridIndex`, and use +// those bits to encode which index type it contains. + +// Index type for `NewDepNodeData`. +rustc_index::newtype_index! { + struct NewDepNodeIndex { + MAX = 0x7FFF_FFFF + } +} + +// Index type for `RedDepNodeData`. +rustc_index::newtype_index! { + struct RedDepNodeIndex { + MAX = 0x7FFF_FFFF + } +} + +// Index type for `LightGreenDepNodeData`. +rustc_index::newtype_index! { + struct LightGreenDepNodeIndex { + MAX = 0x7FFF_FFFF + } +} + +/// Compressed representation of `HybridIndex` enum. Bits unused by the +/// contained index types are used to encode which index type it contains. +#[derive(Copy, Clone)] +struct CompressedHybridIndex(u32); + +impl CompressedHybridIndex { + const NEW_TAG: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000; + const RED_TAG: u32 = 0b0100_0000_0000_0000_0000_0000_0000_0000; + const LIGHT_GREEN_TAG: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000; + const DARK_GREEN_TAG: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000; + + const TAG_MASK: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000; + const INDEX_MASK: u32 = !Self::TAG_MASK; +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: NewDepNodeIndex) -> Self { + CompressedHybridIndex(Self::NEW_TAG | index.as_u32()) + } +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: RedDepNodeIndex) -> Self { + CompressedHybridIndex(Self::RED_TAG | index.as_u32()) + } +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: LightGreenDepNodeIndex) -> Self { + CompressedHybridIndex(Self::LIGHT_GREEN_TAG | index.as_u32()) + } +} + +impl From for CompressedHybridIndex { + #[inline] + fn from(index: SerializedDepNodeIndex) -> Self { + CompressedHybridIndex(Self::DARK_GREEN_TAG | index.as_u32()) + } +} + +/// Contains an index into one of several node data collections. Elsewhere, we +/// store `CompressedHyridIndex` instead of this to save space, but convert to +/// this type during processing to take advantage of the enum match ergonomics. +enum HybridIndex { + New(NewDepNodeIndex), + Red(RedDepNodeIndex), + LightGreen(LightGreenDepNodeIndex), + DarkGreen(SerializedDepNodeIndex), +} + +impl From for HybridIndex { + #[inline] + fn from(hybrid_index: CompressedHybridIndex) -> Self { + let index = hybrid_index.0 & CompressedHybridIndex::INDEX_MASK; + + match hybrid_index.0 & CompressedHybridIndex::TAG_MASK { + CompressedHybridIndex::NEW_TAG => HybridIndex::New(NewDepNodeIndex::from_u32(index)), + CompressedHybridIndex::RED_TAG => HybridIndex::Red(RedDepNodeIndex::from_u32(index)), + CompressedHybridIndex::LIGHT_GREEN_TAG => { + HybridIndex::LightGreen(LightGreenDepNodeIndex::from_u32(index)) + } + CompressedHybridIndex::DARK_GREEN_TAG => { + HybridIndex::DarkGreen(SerializedDepNodeIndex::from_u32(index)) + } + _ => unreachable!(), + } + } +} + +// Index type for `DepNodeData`'s edges. +rustc_index::newtype_index! { + struct EdgeIndex { .. } +} + +/// Data for nodes in the current graph, divided into different collections +/// based on their presence in the previous graph, and if present, their color. +/// We divide nodes this way because different types of nodes are able to share +/// more or less data with the previous graph. +/// +/// To enable more sharing, we distinguish between two kinds of green nodes. +/// Light green nodes are nodes in the previous graph that have been marked +/// green because we re-executed their queries and the results were the same as +/// in the previous session. Dark green nodes are nodes in the previous graph +/// that have been marked green because we were able to mark all of their +/// dependencies green. +/// +/// Both light and dark green nodes can share the dep node and fingerprint with +/// the previous graph, but for light green nodes, we can't be sure that the +/// edges may be shared without comparing them against the previous edges, so we +/// store them directly (an approach in which we compare edges with the previous +/// edges to see if they can be shared was evaluated, but was not found to be +/// very profitable). +/// +/// For dark green nodes, we can share everything with the previous graph, which +/// is why the `HybridIndex::DarkGreen` enum variant contains the index of the +/// node in the previous graph, and why we don't have a separate collection for +/// dark green node data--the collection is the `PreviousDepGraph` itself. +/// +/// (Note that for dark green nodes, the edges in the previous graph +/// (`SerializedDepNodeIndex`s) must be converted to edges in the current graph +/// (`DepNodeIndex`s). `CurrentDepGraph` contains `prev_index_to_index`, which +/// can perform this conversion. It should always be possible, as by definition, +/// a dark green node is one whose dependencies from the previous session have +/// all been marked green--which means `prev_index_to_index` contains them.) +/// +/// Node data is stored in parallel vectors to eliminate the padding between +/// elements that would be needed to satisfy alignment requirements of the +/// structure that would contain all of a node's data. We could group tightly +/// packing subsets of node data together and use fewer vectors, but for +/// consistency's sake, we use separate vectors for each piece of data. struct DepNodeData { - node: DepNode, - edges: EdgesVec, - fingerprint: Fingerprint, + /// Data for nodes not in previous graph. + new: NewDepNodeData, + + /// Data for nodes in previous graph that have been marked red. + red: RedDepNodeData, + + /// Data for nodes in previous graph that have been marked light green. + light_green: LightGreenDepNodeData, + + // Edges for all nodes other than dark-green ones. Edges for each node + // occupy a contiguous region of this collection, which a node can reference + // using two indices. Storing edges this way rather than using an `EdgesVec` + // for each node reduces memory consumption by a not insignificant amount + // when compiling large crates. The downside is that we have to copy into + // this collection the edges from the `EdgesVec`s that are built up during + // query execution. But this is mostly balanced out by the more efficient + // implementation of `DepGraph::serialize` enabled by this representation. + unshared_edges: IndexVec, + + /// Mapping from `DepNodeIndex` to an index into a collection above. + /// Indicates which of the above collections contains a node's data. + /// + /// This collection is wasteful in time and space during incr-full builds, + /// because for those, all nodes are new. However, the waste is relatively + /// small, and the maintenance cost of avoiding using this for incr-full + /// builds is somewhat high and prone to bugginess. It does not seem worth + /// it at the time of this writing, but we may want to revisit the idea. + hybrid_indices: IndexVec, } -/// `CurrentDepGraph` stores the dependency graph for the current session. -/// It will be populated as we run queries or tasks. +/// Data for nodes not in previous graph. Since we cannot share any data with +/// the previous graph, so we must store all of such a node's data here. +struct NewDepNodeData { + nodes: IndexVec>, + edges: IndexVec>, + fingerprints: IndexVec, +} + +/// Data for nodes in previous graph that have been marked red. We can share the +/// dep node with the previous graph, but the edges may be different, and the +/// fingerprint is known to be different, so we store the latter two directly. +struct RedDepNodeData { + node_indices: IndexVec, + edges: IndexVec>, + fingerprints: IndexVec, +} + +/// Data for nodes in previous graph that have been marked green because we +/// re-executed their queries and the results were the same as in the previous +/// session. We can share the dep node and the fingerprint with the previous +/// graph, but the edges may be different, so we store them directly. +struct LightGreenDepNodeData { + node_indices: IndexVec, + edges: IndexVec>, +} + +/// `CurrentDepGraph` stores the dependency graph for the current session. It +/// will be populated as we run queries or tasks. We never remove nodes from the +/// graph: they are only added. /// -/// The nodes in it are identified by an index (`DepNodeIndex`). -/// The data for each node is stored in its `DepNodeData`, found in the `data` field. +/// The nodes in it are identified by a `DepNodeIndex`. Internally, this maps to +/// a `HybridIndex`, which identifies which collection in the `data` field +/// contains a node's data. Which collection is used for a node depends on +/// whether the node was present in the `PreviousDepGraph`, and if so, the color +/// of the node. Each type of node can share more or less data with the previous +/// graph. When possible, we can store just the index of the node in the +/// previous graph, rather than duplicating its data in our own collections. +/// This is important, because these graph structures are some of the largest in +/// the compiler. /// -/// We never remove nodes from the graph: they are only added. +/// For the same reason, we also avoid storing `DepNode`s more than once as map +/// keys. The `new_node_to_index` map only contains nodes not in the previous +/// graph, and we map nodes in the previous graph to indices via a two-step +/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`, +/// and the `prev_index_to_index` vector (which is more compact and faster than +/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`. /// -/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are -/// locked separately. Operations that take a `DepNodeIndex` typically just access -/// the data field. +/// This struct uses three locks internally. The `data`, `new_node_to_index`, +/// and `prev_index_to_index` fields are locked separately. Operations that take +/// a `DepNodeIndex` typically just access the `data` field. /// -/// The only operation that must manipulate both locks is adding new nodes, in which case -/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted, -/// acquire the lock on `data.` +/// We only need to manipulate at most two locks simultaneously: +/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When +/// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index` +/// first, and `data` second. pub(super) struct CurrentDepGraph { - data: Lock>>, - node_to_node_index: Sharded, DepNodeIndex>>, + data: Lock>, + new_node_to_index: Sharded, DepNodeIndex>>, + prev_index_to_index: Lock>>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. @@ -930,18 +1317,63 @@ impl CurrentDepGraph { // Pre-allocate the dep node structures. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation - // session. The over-allocation is 2% plus a small constant to account - // for the fact that in very small crates 2% might not be enough. - let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200; + // session. The over-allocation for new nodes is 2% plus a small + // constant to account for the fact that in very small crates 2% might + // not be enough. The allocation for red and green node data doesn't + // include a constant, as we don't want to allocate anything for these + // structures during full incremental builds, where they aren't used. + // + // These estimates are based on the distribution of node and edge counts + // seen in rustc-perf benchmarks, adjusted somewhat to account for the + // fact that these benchmarks aren't perfectly representative. + // + // FIXME Use a collection type that doesn't copy node and edge data and + // grow multiplicatively on reallocation. Without such a collection or + // solution having the same effect, there is a performance hazard here + // in both time and space, as growing these collections means copying a + // large amount of data and doubling already large buffer capacities. A + // solution for this will also mean that it's less important to get + // these estimates right. + let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200; + let red_node_count_estimate = (prev_graph_node_count * 3) / 100; + let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100; + let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate; + + let average_edges_per_node_estimate = 6; + let unshared_edge_count_estimate = average_edges_per_node_estimate + * (new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate); + + // We store a large collection of these in `prev_index_to_index` during + // non-full incremental builds, and want to ensure that the element size + // doesn't inadvertently increase. + static_assert_size!(Option, 4); CurrentDepGraph { - data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)), - node_to_node_index: Sharded::new(|| { + data: Lock::new(DepNodeData { + new: NewDepNodeData { + nodes: IndexVec::with_capacity(new_node_count_estimate), + edges: IndexVec::with_capacity(new_node_count_estimate), + fingerprints: IndexVec::with_capacity(new_node_count_estimate), + }, + red: RedDepNodeData { + node_indices: IndexVec::with_capacity(red_node_count_estimate), + edges: IndexVec::with_capacity(red_node_count_estimate), + fingerprints: IndexVec::with_capacity(red_node_count_estimate), + }, + light_green: LightGreenDepNodeData { + node_indices: IndexVec::with_capacity(light_green_node_count_estimate), + edges: IndexVec::with_capacity(light_green_node_count_estimate), + }, + unshared_edges: IndexVec::with_capacity(unshared_edge_count_estimate), + hybrid_indices: IndexVec::with_capacity(total_node_count_estimate), + }), + new_node_to_index: Sharded::new(|| { FxHashMap::with_capacity_and_hasher( new_node_count_estimate / sharded::SHARDS, Default::default(), ) }), + prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), anon_id_seed: stable_hasher.finish(), forbidden_edge, total_read_count: AtomicU64::new(0), @@ -949,116 +1381,127 @@ impl CurrentDepGraph { } } - fn complete_task( + fn intern_new_node( &self, - node: DepNode, - task_deps: TaskDeps, + prev_graph: &PreviousDepGraph, + dep_node: DepNode, + edges: EdgesVec, fingerprint: Fingerprint, ) -> DepNodeIndex { - self.alloc_node(node, task_deps.reads, fingerprint) - } - - fn complete_anon_task(&self, kind: K, task_deps: TaskDeps) -> DepNodeIndex { - debug_assert!(!kind.is_eval_always()); - - let mut hasher = StableHasher::new(); - - // The dep node indices are hashed here instead of hashing the dep nodes of the - // dependencies. These indices may refer to different nodes per session, but this isn't - // a problem here because we that ensure the final dep node hash is per session only by - // combining it with the per session random number `anon_id_seed`. This hash only need - // to map the dependencies to a single value on a per session basis. - task_deps.reads.hash(&mut hasher); - - let target_dep_node = DepNode { - kind, - - // Fingerprint::combine() is faster than sending Fingerprint - // through the StableHasher (at least as long as StableHasher - // is so slow). - hash: self.anon_id_seed.combine(hasher.finish()), - }; + debug_assert!( + prev_graph.node_to_index_opt(&dep_node).is_none(), + "node in previous graph should be interned using one \ + of `intern_red_node`, `intern_light_green_node`, etc." + ); - self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO) + match self.new_node_to_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let data = &mut *self.data.lock(); + let new_index = data.new.nodes.push(dep_node); + add_edges(&mut data.unshared_edges, &mut data.new.edges, edges); + data.new.fingerprints.push(fingerprint); + let dep_node_index = data.hybrid_indices.push(new_index.into()); + entry.insert(dep_node_index); + dep_node_index + } + } } - fn alloc_node( + fn intern_red_node( &self, - dep_node: DepNode, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, edges: EdgesVec, fingerprint: Fingerprint, ) -> DepNodeIndex { - debug_assert!( - !self.node_to_node_index.get_shard_by_value(&dep_node).lock().contains_key(&dep_node) - ); - self.intern_node(dep_node, edges, fingerprint) + self.debug_assert_not_in_new_nodes(prev_graph, prev_index); + + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let data = &mut *self.data.lock(); + let red_index = data.red.node_indices.push(prev_index); + add_edges(&mut data.unshared_edges, &mut data.red.edges, edges); + data.red.fingerprints.push(fingerprint); + let dep_node_index = data.hybrid_indices.push(red_index.into()); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index + } + } } - fn intern_node( + fn intern_light_green_node( &self, - dep_node: DepNode, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, edges: EdgesVec, - fingerprint: Fingerprint, ) -> DepNodeIndex { - match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let mut data = self.data.lock(); - let dep_node_index = DepNodeIndex::new(data.len()); - data.push(DepNodeData { node: dep_node, edges, fingerprint }); - entry.insert(dep_node_index); + self.debug_assert_not_in_new_nodes(prev_graph, prev_index); + + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let data = &mut *self.data.lock(); + let light_green_index = data.light_green.node_indices.push(prev_index); + add_edges(&mut data.unshared_edges, &mut data.light_green.edges, edges); + let dep_node_index = data.hybrid_indices.push(light_green_index.into()); + prev_index_to_index[prev_index] = Some(dep_node_index); dep_node_index } } } -} -impl DepGraphData { - #[inline(never)] - fn read_index(&self, source: DepNodeIndex) { - K::read_deps(|task_deps| { - if let Some(task_deps) = task_deps { - let mut task_deps = task_deps.lock(); - let task_deps = &mut *task_deps; - if cfg!(debug_assertions) { - self.current.total_read_count.fetch_add(1, Relaxed); - } + fn intern_dark_green_node( + &self, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, + ) -> DepNodeIndex { + self.debug_assert_not_in_new_nodes(prev_graph, prev_index); - // As long as we only have a low number of reads we can avoid doing a hash - // insert and potentially allocating/reallocating the hashmap - let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { - task_deps.reads.iter().all(|other| *other != source) - } else { - task_deps.read_set.insert(source) - }; - if new_read { - task_deps.reads.push(source); - if task_deps.reads.len() == TASK_DEPS_READS_CAP { - // Fill `read_set` with what we have so far so we can use the hashset next - // time - task_deps.read_set.extend(task_deps.reads.iter().copied()); - } + let mut prev_index_to_index = self.prev_index_to_index.lock(); - #[cfg(debug_assertions)] - { - if let Some(target) = task_deps.node { - let data = self.current.data.lock(); - if let Some(ref forbidden_edge) = self.current.forbidden_edge { - let source = data[source].node; - if forbidden_edge.test(&source, &target) { - panic!("forbidden edge {:?} -> {:?} created", source, target) - } - } - } - } - } else if cfg!(debug_assertions) { - self.current.total_duplicate_read_count.fetch_add(1, Relaxed); - } + match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let mut data = self.data.lock(); + let dep_node_index = data.hybrid_indices.push(prev_index.into()); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index } - }) + } + } + + #[inline] + fn debug_assert_not_in_new_nodes( + &self, + prev_graph: &PreviousDepGraph, + prev_index: SerializedDepNodeIndex, + ) { + let node = &prev_graph.index_to_node(prev_index); + debug_assert!( + !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node), + "node from previous graph present in new node collection" + ); } } +#[inline] +fn add_edges( + edges: &mut IndexVec, + edge_indices: &mut IndexVec>, + new_edges: EdgesVec, +) { + let start = edges.next_index(); + edges.extend(new_edges); + let end = edges.next_index(); + edge_indices.push(start..end); +} + /// The capacity of the `reads` field `SmallVec` const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index e8d02692f3..da0b5aad6c 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -32,6 +32,8 @@ pub trait DepContext: Copy { /// Try to force a dep node to execute and see if it's green. fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool; + fn register_reused_dep_node(&self, dep_node: &DepNode); + /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index a27b716b95..cc25d08cb5 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -9,17 +9,23 @@ pub struct DepGraphQuery { } impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { - let mut graph = Graph::with_capacity(nodes.len(), edges.len()); + pub fn new( + nodes: &[DepNode], + edge_list_indices: &[(usize, usize)], + edge_list_data: &[usize], + ) -> DepGraphQuery { + let mut graph = Graph::with_capacity(nodes.len(), edge_list_data.len()); let mut indices = FxHashMap::default(); for node in nodes { indices.insert(*node, graph.add_node(*node)); } - for &(ref source, ref target) in edges { - let source = indices[source]; - let target = indices[target]; - graph.add_edge(source, target, ()); + for (source, &(start, end)) in edge_list_indices.iter().enumerate() { + for &target in &edge_list_data[start..end] { + let source = indices[&nodes[source]]; + let target = indices[&nodes[target]]; + graph.add_edge(source, target, ()); + } } DepGraphQuery { graph, indices } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 932c6d2a2f..28e0740691 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -4,8 +4,13 @@ use super::{DepKind, DepNode}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_index::vec::IndexVec; +// The maximum value of `SerializedDepNodeIndex` leaves the upper two bits +// unused so that we can store multiple index types in `CompressedHybridIndex`, +// and use those bits to encode which index type it contains. rustc_index::newtype_index! { - pub struct SerializedDepNodeIndex { .. } + pub struct SerializedDepNodeIndex { + MAX = 0x7FFF_FFFF + } } /// Data for use when recompiling the **current crate**. diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index c1d3210b61..5fed500390 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -33,11 +33,11 @@ pub struct QueryInfo { pub(crate) type QueryMap = FxHashMap, QueryJobInfo>; -/// A value uniquely identifiying an active query job within a shard in the query cache. +/// A value uniquely identifying an active query job within a shard in the query cache. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct QueryShardJobId(pub NonZeroU32); -/// A value uniquely identifiying an active query job. +/// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct QueryJobId { /// Which job within a shard is this @@ -536,7 +536,7 @@ fn remove_cycle( }; // We unwrap `waiter` here since there must always be one - // edge which is resumeable / waited using a query latch + // edge which is resumable / waited using a query latch let (waitee_query, waiter_idx) = waiter.unwrap(); // Extract the waiter we want to resume diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 34145c3c13..06e9969697 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -258,7 +258,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))) } ast::VisibilityKind::Inherited => { - Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)) + if matches!(self.parent_scope.module.kind, ModuleKind::Def(DefKind::Enum, _, _)) { + // Any inherited visibility resolved directly inside an enum + // (e.g. variants or fields) inherits from the visibility of the enum. + let parent_enum = self.parent_scope.module.def_id().unwrap().expect_local(); + Ok(self.r.visibilities[&parent_enum]) + } else { + // If it's not in an enum, its visibility is restricted to the `mod` item + // that it's defined in. + Ok(ty::Visibility::Restricted(self.parent_scope.module.normal_ancestor_id)) + } } ast::VisibilityKind::Restricted { ref path, id, .. } => { // For visibilities we are not ready to provide correct implementation of "uniform @@ -1155,17 +1164,19 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { false } - fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> { + fn visit_invoc(&mut self, id: NodeId) -> ExpnId { let invoc_id = id.placeholder_to_expn_id(); - - self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); - let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope); assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation"); + invoc_id + } - let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)); - self.r.invocation_macro_rules_scopes.entry(invoc_id).or_default().insert(scope); - scope + /// Visit invocation in context in which it can emit a named item (possibly `macro_rules`) + /// directly into its parent scope's module. + fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> { + let invoc_id = self.visit_invoc(id); + self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); + self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { @@ -1293,7 +1304,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { return; } ItemKind::MacCall(..) => { - self.parent_scope.macro_rules = self.visit_invoc(item.id); + self.parent_scope.macro_rules = self.visit_invoc_in_module(item.id); return; } ItemKind::Mod(..) => self.contains_macro_use(&item.attrs), @@ -1311,7 +1322,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_stmt(&mut self, stmt: &'b ast::Stmt) { if let ast::StmtKind::MacCall(..) = stmt.kind { - self.parent_scope.macro_rules = self.visit_invoc(stmt.id); + self.parent_scope.macro_rules = self.visit_invoc_in_module(stmt.id); } else { visit::walk_stmt(self, stmt); } @@ -1319,7 +1330,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) { if let ForeignItemKind::MacCall(_) = foreign_item.kind { - self.visit_invoc(foreign_item.id); + self.visit_invoc_in_module(foreign_item.id); return; } @@ -1338,7 +1349,14 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) { if let AssocItemKind::MacCall(_) = item.kind { - self.visit_invoc(item.id); + match ctxt { + AssocCtxt::Trait => { + self.visit_invoc_in_module(item.id); + } + AssocCtxt::Impl => { + self.visit_invoc(item.id); + } + } return; } @@ -1462,7 +1480,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { // type and value namespaces. fn visit_variant(&mut self, variant: &'b ast::Variant) { if variant.is_placeholder { - self.visit_invoc(variant.id); + self.visit_invoc_in_module(variant.id); return; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index acd88af180..809de9beff 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,7 +1,6 @@ use std::cmp::Reverse; use std::ptr; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_ast::{self as ast, Path}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -14,6 +13,7 @@ use rustc_middle::bug; use rustc_middle::ty::{self, DefIdTree}; use rustc_session::Session; use rustc_span::hygiene::MacroKind; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, MultiSpan, Span}; @@ -143,7 +143,7 @@ impl<'a> Resolver<'a> { _ => { bug!( "GenericParamsFromOuterFunction should only be used with Res::SelfTy, \ - DefKind::TyParam" + DefKind::TyParam or DefKind::ConstParam" ); } } @@ -481,6 +481,7 @@ impl<'a> Resolver<'a> { name )); } + err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions"); err } @@ -609,7 +610,7 @@ impl<'a> Resolver<'a> { } } Scope::DeriveHelpersCompat => { - let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); + let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; @@ -715,7 +716,7 @@ impl<'a> Resolver<'a> { suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); match find_best_match_for_name( - suggestions.iter().map(|suggestion| &suggestion.candidate), + &suggestions.iter().map(|suggestion| suggestion.candidate).collect::>(), ident.name, None, ) { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 026cf8be73..cb1f0834ce 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -10,7 +10,6 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding}; use rustc_ast::unwrap_or; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_ast::NodeId; use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::FxHashSet; @@ -25,6 +24,7 @@ use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPOR use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::DiagnosticMessageId; use rustc_span::hygiene::ExpnId; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{MultiSpan, Span}; @@ -1096,33 +1096,37 @@ impl<'a, 'b> ImportResolver<'a, 'b> { _ => None, }; let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); - let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| { - if *i == ident { - return None; - } // Never suggest the same name - match *resolution.borrow() { - NameResolution { binding: Some(name_binding), .. } => { - match name_binding.kind { - NameBindingKind::Import { binding, .. } => { - match binding.kind { - // Never suggest the name that has binding error - // i.e., the name that cannot be previously resolved - NameBindingKind::Res(Res::Err, _) => None, - _ => Some(&i.name), + let names = resolutions + .filter_map(|(BindingKey { ident: i, .. }, resolution)| { + if *i == ident { + return None; + } // Never suggest the same name + match *resolution.borrow() { + NameResolution { binding: Some(name_binding), .. } => { + match name_binding.kind { + NameBindingKind::Import { binding, .. } => { + match binding.kind { + // Never suggest the name that has binding error + // i.e., the name that cannot be previously resolved + NameBindingKind::Res(Res::Err, _) => None, + _ => Some(i.name), + } } + _ => Some(i.name), } - _ => Some(&i.name), } + NameResolution { ref single_imports, .. } + if single_imports.is_empty() => + { + None + } + _ => Some(i.name), } - NameResolution { ref single_imports, .. } if single_imports.is_empty() => { - None - } - _ => Some(&i.name), - } - }); + }) + .collect::>(); let lev_suggestion = - find_best_match_for_name(names, ident.name, None).map(|suggestion| { + find_best_match_for_name(&names, ident.name, None).map(|suggestion| { ( vec![(ident.span, suggestion.to_string())], String::from("a similar name exists in the module"), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f156caf23b..b13462587b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -29,7 +29,7 @@ use rustc_span::Span; use smallvec::{smallvec, SmallVec}; use rustc_span::source_map::{respan, Spanned}; -use std::collections::BTreeSet; +use std::collections::{hash_map::Entry, BTreeSet}; use std::mem::{replace, take}; use tracing::debug; @@ -953,8 +953,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); }; - for item in trait_items { - this.with_trait_items(trait_items, |this| { + this.with_trait_items(trait_items, |this| { + for item in trait_items { match &item.kind { AssocItemKind::Const(_, ty, default) => { this.visit_ty(ty); @@ -983,8 +983,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { panic!("unexpanded macro in resolve!") } }; - }); - } + } + }); }); }); } @@ -1060,36 +1060,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { continue; } - let def_kind = match param.kind { - GenericParamKind::Type { .. } => DefKind::TyParam, - GenericParamKind::Const { .. } => DefKind::ConstParam, - _ => unreachable!(), - }; - let ident = param.ident.normalize_to_macros_2_0(); debug!("with_generic_param_rib: {}", param.id); - if seen_bindings.contains_key(&ident) { - let span = seen_bindings.get(&ident).unwrap(); - let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span); - self.report_error(param.ident.span, err); + match seen_bindings.entry(ident) { + Entry::Occupied(entry) => { + let span = *entry.get(); + let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span); + self.report_error(param.ident.span, err); + } + Entry::Vacant(entry) => { + entry.insert(param.ident.span); + } } - seen_bindings.entry(ident).or_insert(param.ident.span); // Plain insert (no renaming). - let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id()); - - match param.kind { - GenericParamKind::Type { .. } => { - function_type_rib.bindings.insert(ident, res); - self.r.record_partial_res(param.id, PartialRes::new(res)); - } - GenericParamKind::Const { .. } => { - function_value_rib.bindings.insert(ident, res); - self.r.record_partial_res(param.id, PartialRes::new(res)); - } + let (rib, def_kind) = match param.kind { + GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam), + GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam), _ => unreachable!(), - } + }; + let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id()); + self.r.record_partial_res(param.id, PartialRes::new(res)); + rib.bindings.insert(ident, res); } self.ribs[ValueNS].push(function_value_rib); @@ -1778,7 +1771,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { path ); let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); let report_errors = |this: &mut Self, res: Option| { if this.should_report_errs() { @@ -1881,7 +1873,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { crate_lint, ) { Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => { - if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { + if source.is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err + { partial_res } else { report_errors(self, Some(partial_res.base_res())) @@ -1898,11 +1891,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.trait_map.insert(id, traits); } - let mut std_path = vec![Segment::from_ident(Ident::with_dummy_span(sym::std))]; - - std_path.extend(path); - if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { + let mut std_path = Vec::with_capacity(1 + path.len()); + + std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std))); + std_path.extend(path); if let PathResult::Module(_) | PathResult::NonModule(_) = self.resolve_path(&std_path, Some(ns), false, span, CrateLint::No) { @@ -1983,7 +1976,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ) -> Result, Spanned>> { let mut fin_res = None; - for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() { + for (i, &ns) in [primary_ns, TypeNS, ValueNS].iter().enumerate() { if i == 0 || ns != primary_ns { match self.resolve_qpath(id, qself, path, ns, span, crate_lint)? { Some(partial_res) @@ -1993,7 +1986,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } partial_res => { if fin_res.is_none() { - fin_res = partial_res + fin_res = partial_res; } } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 00e6d5ca38..68f59baffc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -5,7 +5,6 @@ use crate::path_names_to_string; use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_ast::visit::FnKind; use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind}; use rustc_ast_pretty::pprust::path_segment_to_string; @@ -16,9 +15,9 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::PrimTy; -use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; @@ -543,6 +542,26 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_label(base_span, fallback_label); } } + if let Some(err_code) = &err.code { + if err_code == &rustc_errors::error_code!(E0425) { + for label_rib in &self.label_ribs { + for (label_ident, _) in &label_rib.bindings { + if format!("'{}", ident) == label_ident.to_string() { + let msg = "a label with a similar name exists"; + // FIXME: consider only emitting this suggestion if a label would be valid here + // which is pretty much only the case for `break` expressions. + err.span_suggestion( + span, + &msg, + label_ident.name.to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + (err, candidates) } @@ -890,7 +909,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => { err.span_label(span, "type aliases cannot be used as traits"); - if nightly_options::is_nightly_build() { + if self.r.session.is_nightly_build() { let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \ `type` alias"; if let Some(span) = self.def_span(def_id) { @@ -1207,7 +1226,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); match find_best_match_for_name( - names.iter().map(|suggestion| &suggestion.candidate), + &names.iter().map(|suggestion| suggestion.candidate).collect::>(), name, None, ) { @@ -1593,9 +1612,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .bindings .iter() .filter(|(id, _)| id.span.ctxt() == label.span.ctxt()) - .map(|(id, _)| &id.name); + .map(|(id, _)| id.name) + .collect::>(); - find_best_match_for_name(names, label.name, None).map(|symbol| { + find_best_match_for_name(&names, label.name, None).map(|symbol| { // Upon finding a similar name, get the ident that it was from - the span // contained within helps make a useful diagnostic. In addition, determine // whether this candidate is within scope. @@ -1675,7 +1695,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { _ => {} } } - if nightly_options::is_nightly_build() + if self.tcx.sess.is_nightly_build() && !self.tcx.features().in_band_lifetimes && suggests_in_band { diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index c79d670737..69f28045bb 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -388,7 +388,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) | hir::ItemKind::Mod(..) - | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); @@ -1098,7 +1098,7 @@ fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shado ) }; err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime {} already in scope", name)); + err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name)); err.emit(); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4e85c88c0e..f764fbc3f8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -403,6 +403,7 @@ enum PathResult<'a> { }, } +#[derive(Debug)] enum ModuleKind { /// An anonymous module; e.g., just a block. /// @@ -976,9 +977,6 @@ pub struct Resolver<'a> { /// `macro_rules` scopes *produced* by expanding the macro invocations, /// include all the `macro_rules` items and other invocations generated by them. output_macro_rules_scopes: FxHashMap>, - /// References to all `MacroRulesScope::Invocation(invoc_id)`s, used to update such scopes - /// when their corresponding `invoc_id`s get expanded. - invocation_macro_rules_scopes: FxHashMap>>, /// Helper attributes that are in scope for the given expansion. helper_attrs: FxHashMap>, @@ -1310,7 +1308,6 @@ impl<'a> Resolver<'a> { non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)], invocation_parent_scopes: Default::default(), output_macro_rules_scopes: Default::default(), - invocation_macro_rules_scopes: Default::default(), helper_attrs: Default::default(), local_macro_def_scopes: FxHashMap::default(), name_already_seen: FxHashMap::default(), @@ -1680,7 +1677,20 @@ impl<'a> Resolver<'a> { !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive)) } Scope::DeriveHelpersCompat => true, - Scope::MacroRules(..) => true, + Scope::MacroRules(macro_rules_scope) => { + // Use "path compression" on `macro_rules` scope chains. This is an optimization + // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. + // As another consequence of this optimization visitors never observe invocation + // scopes for macros that were already expanded. + while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() { + if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) { + macro_rules_scope.set(next_scope.get()); + } else { + break; + } + } + true + } Scope::CrateRoot => true, Scope::Module(..) => true, Scope::RegisteredAttrs => use_prelude, @@ -1716,11 +1726,9 @@ impl<'a> Resolver<'a> { MacroRulesScope::Binding(binding) => { Scope::MacroRules(binding.parent_macro_rules_scope) } - MacroRulesScope::Invocation(invoc_id) => Scope::MacroRules( - self.output_macro_rules_scopes.get(&invoc_id).cloned().unwrap_or_else( - || self.invocation_parent_scopes[&invoc_id].macro_rules, - ), - ), + MacroRulesScope::Invocation(invoc_id) => { + Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) + } MacroRulesScope::Empty => Scope::Module(module), }, Scope::CrateRoot => match ns { @@ -2532,6 +2540,7 @@ impl<'a> Resolver<'a> { span: Span, all_ribs: &[Rib<'a>], ) -> Res { + const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation"; debug!("validate_res_from_ribs({:?})", res); let ribs = &all_ribs[rib_index + 1..]; @@ -2632,6 +2641,8 @@ impl<'a> Resolver<'a> { }, ); } + + self.session.delay_span_bug(span, CG_BUG_STR); return Res::Err; } } @@ -2713,6 +2724,8 @@ impl<'a> Resolver<'a> { }, ); } + + self.session.delay_span_bug(span, CG_BUG_STR); return Res::Err; } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 6bc9419ea8..c8dbe68512 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -12,24 +12,24 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::ptr_key::PtrKey; +use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension}; use rustc_expand::compile_declarative_macro; -use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; +use rustc_expand::expand::{AstFragment, Invocation, InvocationKind}; use rustc_feature::is_builtin_attr_name; use rustc_hir::def::{self, DefKind, NonMacroAttrKind}; use rustc_hir::def_id; use rustc_middle::middle::stability; use rustc_middle::ty; -use rustc_session::lint::builtin::UNUSED_MACROS; +use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS}; +use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind}; +use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; - -use rustc_data_structures::sync::Lrc; -use rustc_span::hygiene::{AstPass, MacroKind}; use std::cell::Cell; use std::{mem, ptr}; @@ -62,8 +62,8 @@ pub enum MacroRulesScope<'a> { } /// `macro_rules!` scopes are always kept by reference and inside a cell. -/// The reason is that we update all scopes with value `MacroRulesScope::Invocation(invoc_id)` -/// in-place immediately after `invoc_id` gets expanded. +/// The reason is that we update scopes with value `MacroRulesScope::Invocation(invoc_id)` +/// in-place after `invoc_id` gets expanded. /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains, /// which usually grow lineraly with the number of macro invocations /// in a module (including derives) and hurt performance. @@ -173,22 +173,6 @@ impl<'a> ResolverExpand for Resolver<'a> { let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope); self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); - // Update all `macro_rules` scopes referring to this invocation. This is an optimization - // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. - if let Some(invocation_scopes) = self.invocation_macro_rules_scopes.remove(&expansion) { - for invocation_scope in &invocation_scopes { - invocation_scope.set(output_macro_rules_scope.get()); - } - // All `macro_rules` scopes that previously referred to `expansion` - // are now rerouted to its output scope, if it's also an invocation. - if let MacroRulesScope::Invocation(invoc_id) = output_macro_rules_scope.get() { - self.invocation_macro_rules_scopes - .entry(invoc_id) - .or_default() - .extend(invocation_scopes); - } - } - parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); } @@ -257,15 +241,20 @@ impl<'a> ResolverExpand for Resolver<'a> { } }; - let (path, kind, derives, after_derive) = match invoc.kind { + let (path, kind, inner_attr, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => ( &attr.get_normal_item().path, MacroKind::Attr, + attr.style == ast::AttrStyle::Inner, self.arenas.alloc_ast_paths(derives), after_derive, ), - InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false), - InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false), + InvocationKind::Bang { ref mac, .. } => { + (&mac.path, MacroKind::Bang, false, &[][..], false) + } + InvocationKind::Derive { ref path, .. } => { + (path, MacroKind::Derive, false, &[][..], false) + } InvocationKind::DeriveContainer { ref derives, .. } => { // Block expansion of the container until we resolve all derives in it. // This is required for two reasons: @@ -297,7 +286,7 @@ impl<'a> ResolverExpand for Resolver<'a> { ext.helper_attrs.iter().map(|name| Ident::new(*name, span)), ); if ext.is_derive_copy { - self.add_derive_copy(invoc_id); + self.containers_deriving_copy.insert(invoc_id); } ext } @@ -315,8 +304,17 @@ impl<'a> ResolverExpand for Resolver<'a> { // Derives are not included when `invocations` are collected, so we have to add them here. let parent_scope = &ParentScope { derives, ..parent_scope }; + let require_inert = !invoc.fragment_kind.supports_macro_expansion(); let node_id = self.lint_node_id(eager_expansion_root); - let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, node_id, force)?; + let (ext, res) = self.smart_resolve_macro_path( + path, + kind, + require_inert, + inner_attr, + parent_scope, + node_id, + force, + )?; let span = invoc.span(); invoc_id.set_expn_data(ext.expn_data( @@ -334,29 +332,6 @@ impl<'a> ResolverExpand for Resolver<'a> { self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); } - match invoc.fragment_kind { - AstFragmentKind::Arms - | AstFragmentKind::Fields - | AstFragmentKind::FieldPats - | AstFragmentKind::GenericParams - | AstFragmentKind::Params - | AstFragmentKind::StructFields - | AstFragmentKind::Variants => { - if let Res::Def(..) = res { - self.session.span_err( - span, - &format!( - "expected an inert attribute, found {} {}", - res.article(), - res.descr() - ), - ); - return Ok(InvocationRes::Single(self.dummy_ext(kind))); - } - } - _ => {} - } - Ok(InvocationRes::Single(ext)) } @@ -376,10 +351,6 @@ impl<'a> ResolverExpand for Resolver<'a> { self.containers_deriving_copy.contains(&expn_id) } - fn add_derive_copy(&mut self, expn_id: ExpnId) { - self.containers_deriving_copy.insert(expn_id); - } - // The function that implements the resolution logic of `#[cfg_accessible(path)]`. // Returns true if the path can certainly be resolved in one of three namespaces, // returns false if the path certainly cannot be resolved in any of the three namespaces. @@ -419,10 +390,14 @@ impl<'a> ResolverExpand for Resolver<'a> { impl<'a> Resolver<'a> { /// Resolve macro path with error reporting and recovery. + /// Uses dummy syntax extensions for unresolved macros or macros with unexpected resolutions + /// for better error recovery. fn smart_resolve_macro_path( &mut self, path: &ast::Path, kind: MacroKind, + require_inert: bool, + inner_attr: bool, parent_scope: &ParentScope<'a>, node_id: NodeId, force: bool, @@ -430,7 +405,6 @@ impl<'a> Resolver<'a> { let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force) { Ok((Some(ext), res)) => (ext, res), - // Use dummy syntax extensions for unresolved macros for better recovery. Ok((None, res)) => (self.dummy_ext(kind), res), Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err), Err(Determinacy::Undetermined) => return Err(Indeterminate), @@ -467,19 +441,42 @@ impl<'a> Resolver<'a> { self.check_stability_and_deprecation(&ext, path, node_id); - Ok(if ext.macro_kind() != kind { - let expected = kind.descr_expected(); + let unexpected_res = if ext.macro_kind() != kind { + Some((kind.article(), kind.descr_expected())) + } else if require_inert && matches!(res, Res::Def(..)) { + Some(("a", "non-macro attribute")) + } else { + None + }; + if let Some((article, expected)) = unexpected_res { let path_str = pprust::path_to_string(path); let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); self.session .struct_span_err(path.span, &msg) - .span_label(path.span, format!("not {} {}", kind.article(), expected)) + .span_label(path.span, format!("not {} {}", article, expected)) .emit(); - // Use dummy syntax extensions for unexpected macro kinds for better recovery. - (self.dummy_ext(kind), Res::Err) - } else { - (ext, res) - }) + return Ok((self.dummy_ext(kind), Res::Err)); + } + + // We are trying to avoid reporting this error if other related errors were reported. + if res != Res::Err + && inner_attr + && !self.session.features_untracked().custom_inner_attributes + { + let msg = match res { + Res::Def(..) => "inner macro attributes are unstable", + Res::NonMacroAttr(..) => "custom inner attributes are unstable", + _ => unreachable!(), + }; + if path == &sym::test { + self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg); + } else { + feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg) + .emit(); + } + } + + Ok((ext, res)) } pub fn resolve_macro_path( @@ -584,10 +581,9 @@ impl<'a> Resolver<'a> { struct Flags: u8 { const MACRO_RULES = 1 << 0; const MODULE = 1 << 1; - const DERIVE_HELPER_COMPAT = 1 << 2; - const MISC_SUGGEST_CRATE = 1 << 3; - const MISC_SUGGEST_SELF = 1 << 4; - const MISC_FROM_PRELUDE = 1 << 5; + const MISC_SUGGEST_CRATE = 1 << 2; + const MISC_SUGGEST_SELF = 1 << 3; + const MISC_FROM_PRELUDE = 1 << 4; } } @@ -662,14 +658,11 @@ impl<'a> Resolver<'a> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = ( - Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), - ty::Visibility::Public, + result = ok( + Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), derive.span, - ExpnId::root(), - ) - .to_name_binding(this.arenas); - result = Ok((binding, Flags::DERIVE_HELPER_COMPAT)); + this.arenas, + ); break; } } @@ -687,11 +680,7 @@ impl<'a> Resolver<'a> { { Ok((macro_rules_binding.binding, Flags::MACRO_RULES)) } - MacroRulesScope::Invocation(invoc_id) - if !this.output_macro_rules_scopes.contains_key(&invoc_id) => - { - Err(Determinacy::Undetermined) - } + MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), }, Scope::CrateRoot => { @@ -819,17 +808,15 @@ impl<'a> Resolver<'a> { let (res, innermost_res) = (binding.res(), innermost_binding.res()); if res != innermost_res { let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin); - let is_derive_helper_compat = |res, flags: Flags| { - res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper) - && flags.contains(Flags::DERIVE_HELPER_COMPAT) - }; + let derive_helper_compat = + Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); let ambiguity_error_kind = if is_import { Some(AmbiguityKind::Import) } else if innermost_res == builtin || res == builtin { Some(AmbiguityKind::BuiltinAttr) - } else if is_derive_helper_compat(innermost_res, innermost_flags) - || is_derive_helper_compat(res, flags) + } else if innermost_res == derive_helper_compat + || res == derive_helper_compat { Some(AmbiguityKind::DeriveHelper) } else if innermost_flags.contains(Flags::MACRO_RULES) @@ -1054,6 +1041,7 @@ impl<'a> Resolver<'a> { depr.suggestion, lint, span, + node_id, ); } } diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index eed9f2eb74..056c0b3d9d 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -825,7 +825,7 @@ impl<'tcx> SaveContext<'tcx> { for attr in attrs { if let Some(val) = attr.doc_str() { // FIXME: Should save-analysis beautify doc strings itself or leave it to users? - result.push_str(&beautify_doc_string(val)); + result.push_str(&beautify_doc_string(val).as_str()); result.push('\n'); } else if self.tcx.sess.check_name(attr, sym::doc) { if let Some(meta_list) = attr.meta_item_list() { diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 1bf8160e4c..ff445d727f 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -21,7 +21,7 @@ // references. // // Signatures do not include visibility info. I'm not sure if this is a feature -// or an ommission (FIXME). +// or an omission (FIXME). // // FIXME where clauses need implementing, defs/refs in generics are mostly missing. @@ -550,7 +550,7 @@ impl<'hir> Sig for hir::Item<'hir> { // FIXME where clause } - hir::ItemKind::ForeignMod(_) => Err("extern mod"), + hir::ItemKind::ForeignMod { .. } => Err("extern mod"), hir::ItemKind::GlobalAsm(_) => Err("global asm"), hir::ItemKind::ExternCrate(_) => Err("extern crate"), hir::ItemKind::OpaqueTy(..) => Err("opaque type"), @@ -677,7 +677,7 @@ impl<'hir> Sig for hir::Variant<'hir> { let mut text = self.ident.to_string(); match self.data { hir::VariantData::Struct(fields, r) => { - let id = parent_id.unwrap(); + let id = parent_id.ok_or("Missing id for Variant's parent")?; let name_def = SigElement { id: id_from_hir_id(id, scx), start: offset, diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs index 6c8965aa2e..bbbe568f17 100644 --- a/compiler/rustc_serialize/src/json.rs +++ b/compiler/rustc_serialize/src/json.rs @@ -1859,7 +1859,7 @@ impl> Parser { } let n2 = self.decode_hex_escape()?; - if n2 < 0xDC00 || n2 > 0xDFFF { + if !(0xDC00..=0xDFFF).contains(&n2) { return self.error(LoneLeadingSurrogateInHexEscape); } let c = diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8768733937..c9ddcbdb5f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -214,13 +214,30 @@ pub enum SymbolManglingVersion { impl_stable_hash_via_hash!(SymbolManglingVersion); -#[derive(Clone, Copy, PartialEq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Hash)] pub enum DebugInfo { None, Limited, Full, } +/// Some debuginfo requires link-time relocation and some does not. LLVM can partition the debuginfo +/// into sections depending on whether or not it requires link-time relocation. Split DWARF +/// provides a mechanism which allows the linker to skip the sections which don't require link-time +/// relocation - either by putting those sections into DWARF object files, or keeping them in the +/// object file in such a way that the linker will skip them. +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum SplitDwarfKind { + /// Disabled. + None, + /// Sections which do not require relocation are written into the object file but ignored + /// by the linker. + Single, + /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file, + /// which is skipped by the linker by virtue of being a different file. + Split, +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] #[derive(Encodable, Decodable)] pub enum OutputType { @@ -533,6 +550,7 @@ impl_stable_hash_via_hash!(OutputFilenames); pub const RLINK_EXT: &str = "rlink"; pub const RUST_CGU_EXT: &str = "rcgu"; +pub const DWARF_OBJECT_EXT: &str = "dwo"; impl OutputFilenames { pub fn new( @@ -566,7 +584,12 @@ impl OutputFilenames { self.temp_path_ext(extension, codegen_unit_name) } - /// Like temp_path, but also supports things where there is no corresponding + /// Like `temp_path`, but specifically for dwarf objects. + pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf { + self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name) + } + + /// Like `temp_path`, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { let mut extension = String::new(); @@ -593,6 +616,37 @@ impl OutputFilenames { path.set_extension(extension); path } + + /// Returns the name of the Split DWARF file - this can differ depending on which Split DWARF + /// mode is being used, which is the logic that this function is intended to encapsulate. + pub fn split_dwarf_filename( + &self, + split_dwarf_kind: SplitDwarfKind, + cgu_name: Option<&str>, + ) -> Option { + self.split_dwarf_path(split_dwarf_kind, cgu_name) + .map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf()) + } + + /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF + /// mode is being used, which is the logic that this function is intended to encapsulate. + pub fn split_dwarf_path( + &self, + split_dwarf_kind: SplitDwarfKind, + cgu_name: Option<&str>, + ) -> Option { + let obj_out = self.temp_path(OutputType::Object, cgu_name); + let dwo_out = self.temp_path_dwo(cgu_name); + match split_dwarf_kind { + SplitDwarfKind::None => None, + // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes + // (pointing at the path which is being determined here). Use the path to the current + // object file. + SplitDwarfKind::Single => Some(obj_out), + // Split mode emits the DWARF into a different file, use that path. + SplitDwarfKind::Split => Some(dwo_out), + } + } } pub fn host_triple() -> &'static str { @@ -692,6 +746,10 @@ impl DebuggingOptions { deduplicate_diagnostics: self.deduplicate_diagnostics, } } + + pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { + self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) + } } // The type of entry function, so users can have their own entry functions @@ -1250,7 +1308,7 @@ fn parse_crate_edition(matches: &getopts::Matches) -> Edition { None => DEFAULT_EDITION, }; - if !edition.is_stable() && !nightly_options::is_nightly_build() { + if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) { early_error( ErrorOutputType::default(), &format!( @@ -1296,8 +1354,10 @@ fn parse_output_types( if !debugging_opts.parse_only { for list in matches.opt_strs("emit") { for output_type in list.split(',') { - let mut parts = output_type.splitn(2, '='); - let shorthand = parts.next().unwrap(); + let (shorthand, path) = match output_type.split_once('=') { + None => (output_type, None), + Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))), + }; let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { early_error( error_format, @@ -1308,7 +1368,6 @@ fn parse_output_types( ), ) }); - let path = parts.next().map(PathBuf::from); output_types.insert(output_type, path); } } @@ -1432,7 +1491,7 @@ fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType early_error(error_format, &format!("target file {:?} does not exist", path)) }) } - Some(target) => TargetTriple::TargetTriple(target), + Some(target) => TargetTriple::from_alias(target), _ => TargetTriple::from_triple(host_triple()), } } @@ -1452,11 +1511,10 @@ fn parse_opt_level( let max_c = matches .opt_strs_pos("C") .into_iter() - .flat_map( - |(i, s)| { - if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } - }, - ) + .flat_map(|(i, s)| { + // NB: This can match a string without `=`. + if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } + }) .max(); if max_o > max_c { OptLevel::Default @@ -1491,11 +1549,10 @@ fn select_debuginfo( let max_c = matches .opt_strs_pos("C") .into_iter() - .flat_map( - |(i, s)| { - if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } - }, - ) + .flat_map(|(i, s)| { + // NB: This can match a string without `=`. + if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } + }) .max(); if max_g > max_c { DebugInfo::Full @@ -1528,36 +1585,42 @@ fn parse_libs( .map(|s| { // Parse string of the form "[KIND=]lib[:new_name]", // where KIND is one of "dylib", "framework", "static". - let mut parts = s.splitn(2, '='); - let kind = parts.next().unwrap(); - let (name, kind) = match (parts.next(), kind) { - (None, name) => (name, NativeLibKind::Unspecified), - (Some(name), "dylib") => (name, NativeLibKind::Dylib), - (Some(name), "framework") => (name, NativeLibKind::Framework), - (Some(name), "static") => (name, NativeLibKind::StaticBundle), - (Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle), - (_, s) => { - early_error( - error_format, - &format!( - "unknown library kind `{}`, expected \ - one of dylib, framework, or static", - s - ), - ); + let (name, kind) = match s.split_once('=') { + None => (s, NativeLibKind::Unspecified), + Some((kind, name)) => { + let kind = match kind { + "dylib" => NativeLibKind::Dylib, + "framework" => NativeLibKind::Framework, + "static" => NativeLibKind::StaticBundle, + "static-nobundle" => NativeLibKind::StaticNoBundle, + s => { + early_error( + error_format, + &format!( + "unknown library kind `{}`, expected \ + one of dylib, framework, or static", + s + ), + ); + } + }; + (name.to_string(), kind) } }; - if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() { + if kind == NativeLibKind::StaticNoBundle + && !nightly_options::match_is_nightly_build(matches) + { early_error( error_format, "the library kind 'static-nobundle' is only \ accepted on the nightly compiler", ); } - let mut name_parts = name.splitn(2, ':'); - let name = name_parts.next().unwrap(); - let new_name = name_parts.next(); - (name.to_owned(), new_name.map(|n| n.to_owned()), kind) + let (name, new_name) = match name.split_once(':') { + None => (name, None), + Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), + }; + (name, new_name, kind) }) .collect() } @@ -1578,20 +1641,13 @@ pub fn parse_externs( let is_unstable_enabled = debugging_opts.unstable_options; let mut externs: BTreeMap = BTreeMap::new(); for arg in matches.opt_strs("extern") { - let mut parts = arg.splitn(2, '='); - let name = parts - .next() - .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty")); - let path = parts.next().map(|s| s.to_string()); - - let mut name_parts = name.splitn(2, ':'); - let first_part = name_parts.next(); - let second_part = name_parts.next(); - let (options, name) = match (first_part, second_part) { - (Some(opts), Some(name)) => (Some(opts), name), - (Some(name), None) => (None, name), - (None, None) => early_error(error_format, "--extern name must not be empty"), - _ => unreachable!(), + let (name, path) = match arg.split_once('=') { + None => (arg, None), + Some((name, path)) => (name.to_string(), Some(path.to_string())), + }; + let (options, name) = match name.split_once(':') { + None => (None, name), + Some((opts, name)) => (Some(opts), name.to_string()), }; let entry = externs.entry(name.to_owned()); @@ -1680,17 +1736,12 @@ fn parse_remap_path_prefix( matches .opt_strs("remap-path-prefix") .into_iter() - .map(|remap| { - let mut parts = remap.rsplitn(2, '='); // reverse iterator - let to = parts.next(); - let from = parts.next(); - match (from, to) { - (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)), - _ => early_error( - error_format, - "--remap-path-prefix must contain '=' between FROM and TO", - ), - } + .map(|remap| match remap.rsplit_once('=') { + None => early_error( + error_format, + "--remap-path-prefix must contain '=' between FROM and TO", + ), + Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), }) .collect() } @@ -1764,7 +1815,30 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over // multiple runs, including some changes to source code; so mangled names must be consistent // across compilations. - debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0; + match debugging_opts.symbol_mangling_version { + None => { + debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0); + } + Some(SymbolManglingVersion::Legacy) => { + early_warn( + error_format, + "-Z instrument-coverage requires symbol mangling version `v0`, \ + but `-Z symbol-mangling-version=legacy` was specified", + ); + } + Some(SymbolManglingVersion::V0) => {} + } + + if debugging_opts.mir_opt_level > 1 { + early_warn( + error_format, + &format!( + "`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \ + limits the effectiveness of `-Z instrument-coverage`.", + debugging_opts.mir_opt_level, + ), + ); + } } if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { @@ -1836,10 +1910,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { cg, error_format, externs, + unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), crate_name, alt_std_name: None, libs, - unstable_features: UnstableFeatures::from_environment(), debug_assertions, actually_rustdoc: false, trimmed_def_paths: TrimmedDefPaths::default(), @@ -1960,17 +2034,21 @@ pub mod nightly_options { use rustc_feature::UnstableFeatures; pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { - is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") + match_is_nightly_build(matches) + && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") + } + + pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { + is_nightly_build(matches.opt_str("crate-name").as_deref()) } - pub fn is_nightly_build() -> bool { - UnstableFeatures::from_environment().is_nightly_build() + pub fn is_nightly_build(krate: Option<&str>) -> bool { + UnstableFeatures::from_environment(krate).is_nightly_build() } pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) { let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options"); - let really_allows_unstable_options = - UnstableFeatures::from_environment().is_nightly_build(); + let really_allows_unstable_options = match_is_nightly_build(matches); for opt in flags.iter() { if opt.stability == OptionStability::Stable { @@ -2165,7 +2243,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(Edition); impl_dep_tracking_hash_via_hash!(LinkerPluginLto); impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); - impl_dep_tracking_hash_via_hash!(SymbolManglingVersion); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(TrimmedDefPaths); diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d002f59739..36bf8634c6 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,7 @@ #![feature(crate_visibility_modifier)] #![feature(once_cell)] #![feature(or_patterns)] +#![feature(str_split_once)] #[macro_use] extern crate bitflags; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1cd3d11e32..81f79f4b0e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -179,9 +179,10 @@ macro_rules! options { { let mut op = $defaultfn(); for option in matches.opt_strs($prefix) { - let mut iter = option.splitn(2, '='); - let key = iter.next().unwrap(); - let value = iter.next(); + let (key, value) = match option.split_once('=') { + None => (option, None), + Some((k, v)) => (k.to_string(), Some(v)), + }; let option_to_lookup = key.replace("-", "_"); let mut found = false; for &(candidate, setter, type_desc, _) in $stat { @@ -268,6 +269,7 @@ macro_rules! options { pub const parse_switch_with_opt_path: &str = "an optional path to the profiling data output directory"; pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`"; + pub const parse_split_dwarf_kind: &str = "one of: `none`, `single` or `split`"; pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)"; pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub const parse_relocation_model: &str = @@ -675,13 +677,26 @@ macro_rules! options { true } + fn parse_split_dwarf_kind( + slot: &mut SplitDwarfKind, + v: Option<&str>, + ) -> bool { + *slot = match v { + Some("none") => SplitDwarfKind::None, + Some("split") => SplitDwarfKind::Split, + Some("single") => SplitDwarfKind::Single, + _ => return false, + }; + true + } + fn parse_symbol_mangling_version( - slot: &mut SymbolManglingVersion, + slot: &mut Option, v: Option<&str>, ) -> bool { *slot = match v { - Some("legacy") => SymbolManglingVersion::Legacy, - Some("v0") => SymbolManglingVersion::V0, + Some("legacy") => Some(SymbolManglingVersion::Legacy), + Some("v0") => Some(SymbolManglingVersion::V0), _ => return false, }; true @@ -900,7 +915,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "emits a future-incompatibility report for lints (RFC 2834)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), - fewer_names: bool = (false, parse_bool, [TRACKED], + fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], @@ -945,8 +960,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`, \ and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \ - implies `-C link-dead-code` (unless targeting MSVC, or explicitly disabled) \ - and `-Z symbol-mangling-version=v0`; disables/overrides some Rust \ + implies `-Z symbol-mangling-version=v0`; disables/overrides some Rust \ optimizations (default: no)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), @@ -996,6 +1010,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED], "prevent automatic injection of the profiler_builtins crate"), + normalize_docs: bool = (false, parse_bool, [TRACKED], + "normalize associated items in rustdoc when generating documentation"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], "pass `-install_name @rpath/...` to the macOS linker (default: no)"), panic_abort_tests: bool = (false, parse_bool, [TRACKED], @@ -1008,7 +1024,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "whether to use the PLT when calling into shared libraries; only has effect for PIC code on systems with ELF binaries (default: PLT is disabled if full relro is enabled)"), - polonius: bool = (false, parse_bool, [UNTRACKED], + polonius: bool = (false, parse_bool, [TRACKED], "enable polonius-based borrow-checker (default: no)"), polymorphize: bool = (false, parse_bool, [TRACKED], "perform polymorphization analysis"), @@ -1086,9 +1102,14 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), - symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy, + split_dwarf: SplitDwarfKind = (SplitDwarfKind::None, parse_split_dwarf_kind, [UNTRACKED], + "enable generation of split dwarf"), + split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED], + "provide minimal debug info in the object/executable to facilitate online \ + symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), + symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names"), + "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], @@ -1113,6 +1134,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments (default: no)"), + trap_unreachable: Option = (None, parse_opt_bool, [TRACKED], + "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], "treat error number `val` that occurs as bug"), trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index a2bb8c4f91..b1a4834241 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -4,7 +4,7 @@ use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{Lock, Lrc, OnceCell}; +use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{error_code, Applicability, DiagnosticBuilder}; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; @@ -130,7 +130,6 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock>, - pub injected_crate_name: OnceCell, pub gated_spans: GatedSpans, pub symbol_gallery: SymbolGallery, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. @@ -151,7 +150,7 @@ impl ParseSess { pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { Self { span_diagnostic: handler, - unstable_features: UnstableFeatures::from_environment(), + unstable_features: UnstableFeatures::from_environment(None), config: FxHashSet::default(), edition: ExpnId::root().expn_data().edition, missing_fragment_specifiers: Default::default(), @@ -160,7 +159,6 @@ impl ParseSess { source_map, buffered_lints: Lock::new(vec![]), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - injected_crate_name: OnceCell::new(), gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), reached_eof: Lock::new(false), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 98b7f03df3..75faab12e3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -734,17 +734,23 @@ impl Session { self.opts.cg.panic.unwrap_or(self.target.panic_strategy) } pub fn fewer_names(&self) -> bool { - let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) - || self.opts.output_types.contains_key(&OutputType::Bitcode) - // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. - || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); - - self.opts.debugging_opts.fewer_names || !more_names + if let Some(fewer_names) = self.opts.debugging_opts.fewer_names { + fewer_names + } else { + let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) + || self.opts.output_types.contains_key(&OutputType::Bitcode) + // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. + || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); + !more_names + } } pub fn unstable_options(&self) -> bool { self.opts.debugging_opts.unstable_options } + pub fn is_nightly_build(&self) -> bool { + self.opts.unstable_features.is_nightly_build() + } pub fn overflow_checks(&self) -> bool { self.opts .cg @@ -1103,36 +1109,7 @@ impl Session { } pub fn link_dead_code(&self) -> bool { - match self.opts.cg.link_dead_code { - Some(explicitly_set) => explicitly_set, - None => { - self.opts.debugging_opts.instrument_coverage && !self.target.is_like_msvc - // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid - // binaries when LLVM InstrProf counters are enabled). As described by this issue, - // the "link dead code" option produces incorrect binaries when compiled and linked - // under MSVC. The resulting Rust programs typically crash with a segmentation - // fault, or produce an empty "*.profraw" file (profiling counter results normally - // generated during program exit). - // - // If not targeting MSVC, `-Z instrument-coverage` implies `-C link-dead-code`, so - // unexecuted code is still counted as zero, rather than be optimized out. Note that - // instrumenting dead code can be explicitly disabled with: - // - // `-Z instrument-coverage -C link-dead-code=no`. - // - // FIXME(richkadel): Investigate if `instrument-coverage` implementation can inject - // [zero counters](https://llvm.org/docs/CoverageMappingFormat.html#counter) in the - // coverage map when "dead code" is removed, rather than forcing `link-dead-code`. - // This may not be possible, however, if (as it seems to appear) the "dead code" - // that would otherwise not be linked is only identified as "dead" by the native - // linker. If that's the case, I believe it is too late for the Rust compiler to - // leverage any information it might be able to get from the linker regarding what - // code is dead, to be able to add those counters. - // - // On the other hand, if any Rust compiler passes are optimizing out dead code blocks - // we should inject "zero" counters for those code regions. - } - } + self.opts.cg.link_dead_code.unwrap_or(false) } pub fn mark_attr_known(&self, attr: &Attribute) { @@ -1332,7 +1309,7 @@ pub fn build_session( let profiler = SelfProfiler::new( directory, - sopts.crate_name.as_ref().map(|s| &s[..]), + sopts.crate_name.as_deref(), &sopts.debugging_opts.self_profile_events, ); match profiler { diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index b4beb3dc37..5987fb2a19 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -97,7 +97,7 @@ cfg_if::cfg_if! { let ptr = src_bytes.as_ptr() as *const __m128i; // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. - let chunk = _mm_loadu_si128(ptr.offset(chunk_index as isize)); + let chunk = _mm_loadu_si128(ptr.add(chunk_index)); // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. @@ -253,7 +253,7 @@ fn analyze_source_file_generic( let pos = BytePos::from_usize(i) + output_offset; if char_len > 1 { - assert!(char_len >= 2 && char_len <= 4); + assert!((2..=4).contains(&char_len)); let mbc = MultiByteChar { pos, bytes: char_len as u8 }; multi_byte_chars.push(mbc); } diff --git a/compiler/rustc_ast/src/util/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs similarity index 86% rename from compiler/rustc_ast/src/util/lev_distance.rs rename to compiler/rustc_span/src/lev_distance.rs index 21c2c925bc..edc6625a6e 100644 --- a/compiler/rustc_ast/src/util/lev_distance.rs +++ b/compiler/rustc_span/src/lev_distance.rs @@ -1,6 +1,4 @@ -// FIXME(Centril): Move to rustc_span? - -use rustc_span::symbol::Symbol; +use crate::symbol::Symbol; use std::cmp; #[cfg(test)] @@ -45,17 +43,14 @@ pub fn lev_distance(a: &str, b: &str) -> usize { /// /// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with /// a lower(upper)case letters mismatch. -pub fn find_best_match_for_name<'a, T>( - iter_names: T, +#[cold] +pub fn find_best_match_for_name( + name_vec: &[Symbol], lookup: Symbol, dist: Option, -) -> Option -where - T: Iterator, -{ +) -> Option { let lookup = &lookup.as_str(); let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); - let name_vec: Vec<&Symbol> = iter_names.collect(); let (case_insensitive_match, levenshtein_match) = name_vec .iter() @@ -83,18 +78,18 @@ where // 2. Levenshtein distance match // 3. Sorted word match if let Some(candidate) = case_insensitive_match { - Some(*candidate) + Some(candidate) } else if levenshtein_match.is_some() { - levenshtein_match.map(|(candidate, _)| *candidate) + levenshtein_match.map(|(candidate, _)| candidate) } else { find_match_by_sorted_words(name_vec, lookup) } } -fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> Option { +fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option { iter_names.iter().fold(None, |result, candidate| { if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) { - Some(**candidate) + Some(*candidate) } else { result } diff --git a/compiler/rustc_ast/src/util/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs similarity index 69% rename from compiler/rustc_ast/src/util/lev_distance/tests.rs rename to compiler/rustc_span/src/lev_distance/tests.rs index 7ebedbcb76..7aa01cb8ef 100644 --- a/compiler/rustc_ast/src/util/lev_distance/tests.rs +++ b/compiler/rustc_span/src/lev_distance/tests.rs @@ -21,38 +21,35 @@ fn test_lev_distance() { #[test] fn test_find_best_match_for_name() { - use rustc_span::with_default_session_globals; + use crate::with_default_session_globals; with_default_session_globals(|| { let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")]; assert_eq!( - find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None), + find_best_match_for_name(&input, Symbol::intern("aaaa"), None), Some(Symbol::intern("aaab")) ); - assert_eq!( - find_best_match_for_name(input.iter(), Symbol::intern("1111111111"), None), - None - ); + assert_eq!(find_best_match_for_name(&input, Symbol::intern("1111111111"), None), None); let input = vec![Symbol::intern("aAAA")]; assert_eq!( - find_best_match_for_name(input.iter(), Symbol::intern("AAAA"), None), + find_best_match_for_name(&input, Symbol::intern("AAAA"), None), Some(Symbol::intern("aAAA")) ); let input = vec![Symbol::intern("AAAA")]; // Returns None because `lev_distance > max_dist / 3` - assert_eq!(find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None), None); + assert_eq!(find_best_match_for_name(&input, Symbol::intern("aaaa"), None), None); let input = vec![Symbol::intern("AAAA")]; assert_eq!( - find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), Some(4)), + find_best_match_for_name(&input, Symbol::intern("aaaa"), Some(4)), Some(Symbol::intern("AAAA")) ); let input = vec![Symbol::intern("a_longer_variable_name")]; assert_eq!( - find_best_match_for_name(input.iter(), Symbol::intern("a_variable_longer_name"), None), + find_best_match_for_name(&input, Symbol::intern("a_variable_longer_name"), None), Some(Symbol::intern("a_longer_variable_name")) ); }) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 0926561f4c..fbef4d0670 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -34,6 +34,7 @@ use hygiene::Transparency; pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind}; pub mod def_id; use def_id::{CrateNum, DefId, LOCAL_CRATE}; +pub mod lev_distance; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -181,7 +182,7 @@ impl std::fmt::Display for FileName { use FileName::*; match *self { Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()), - // FIXME: might be nice to display both compoments of Devirtualized. + // FIXME: might be nice to display both components of Devirtualized. // But for now (to backport fix for issue #70924), best to not // perturb diagnostics so its obvious test suite still works. Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => { @@ -1014,10 +1015,7 @@ pub enum ExternalSourceKind { impl ExternalSource { pub fn is_absent(&self) -> bool { - match self { - ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. } => false, - _ => true, - } + !matches!(self, ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. }) } pub fn get_source(&self) -> Option<&Lrc> { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f067cdb730..e9b4eb6e4a 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -623,7 +623,7 @@ impl SourceMap { self.span_to_source(sp, |src, start_index, end_index| { src.get(start_index..end_index) .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + .ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } @@ -640,9 +640,7 @@ impl SourceMap { /// Returns the source snippet as `String` before the given `Span`. pub fn span_to_prev_source(&self, sp: Span) -> Result { self.span_to_source(sp, |src, start_index, _| { - src.get(..start_index) - .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ad58f89d87..99a523c3f3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -13,7 +13,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::str; -use crate::{Span, DUMMY_SP, SESSION_GLOBALS}; +use crate::{Edition, Span, DUMMY_SP, SESSION_GLOBALS}; #[cfg(test)] mod tests; @@ -267,6 +267,7 @@ symbols! { asm, assert, assert_inhabited, + assert_macro, assert_receiver_is_total_eq, assert_uninit_valid, assert_zero_valid, @@ -284,6 +285,7 @@ symbols! { attr_literals, attributes, augmented_assignments, + auto_traits, automatically_derived, avx512_target_feature, await_macro, @@ -318,6 +320,7 @@ symbols! { call_mut, call_once, caller_location, + capture_disjoint_fields, cdylib, ceilf32, ceilf64, @@ -353,6 +356,7 @@ symbols! { concat_idents, conservative_impl_trait, console, + const_allocate, const_compare_raw_pointers, const_constructor, const_eval_limit, @@ -392,6 +396,7 @@ symbols! { copysignf64, core, core_intrinsics, + core_panic_macro, cosf32, cosf64, crate_id, @@ -415,6 +420,7 @@ symbols! { dead_code, dealloc, debug, + debug_assert_macro, debug_assertions, debug_struct, debug_trait, @@ -454,6 +460,9 @@ symbols! { document_private_items, dotdot_in_tuple_patterns, dotdoteq_in_patterns, + dreg, + dreg_low16, + dreg_low8, drop, drop_in_place, drop_types_in_const, @@ -490,6 +499,7 @@ symbols! { expf64, export_name, expr, + extended_key_value_attributes, extern_absolute_paths, extern_crate_item_prelude, extern_crate_self, @@ -537,6 +547,7 @@ symbols! { format_args_capture, format_args_nl, freeze, + freg, frem_fast, from, from_desugaring, @@ -620,6 +631,7 @@ symbols! { iter, keyword, kind, + kreg, label, label_break_value, lang, @@ -645,6 +657,7 @@ symbols! { lint_reasons, literal, llvm_asm, + local, local_inner_macros, log10f32, log10f64, @@ -788,6 +801,7 @@ symbols! { panic_runtime, panic_str, panic_unwind, + panicking, param_attrs, parent_trait, partial_cmp, @@ -846,6 +860,9 @@ symbols! { pub_restricted, pure, pushpop_unsafe, + qreg, + qreg_low4, + qreg_low8, quad_precision_float, question_mark, quote, @@ -867,6 +884,13 @@ symbols! { reexport_test_harness_main, reference, reflect, + reg, + reg16, + reg32, + reg64, + reg_abcd, + reg_byte, + reg_thumb, register_attr, register_tool, relaxed_adts, @@ -909,6 +933,7 @@ symbols! { rustc_args_required_const, rustc_attrs, rustc_builtin_macro, + rustc_capture_analysis, rustc_clean, rustc_const_stable, rustc_const_unstable, @@ -1051,6 +1076,8 @@ symbols! { spotlight, sqrtf32, sqrtf64, + sreg, + sreg_low16, sse4a_target_feature, stable, staged_api, @@ -1062,6 +1089,7 @@ symbols! { staticlib, std, std_inject, + std_panic_macro, stmt, stmt_expr_attributes, stop_after_dataflow, @@ -1205,6 +1233,8 @@ symbols! { volatile_load, volatile_set_memory, volatile_store, + vreg, + vreg_low16, warn, wasm_import_module, wasm_target_feature, @@ -1216,6 +1246,9 @@ symbols! { wrapping_mul, wrapping_sub, write_bytes, + xmm_reg, + ymm_reg, + zmm_reg, } } @@ -1354,15 +1387,13 @@ impl fmt::Display for IdentPrinter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_raw { f.write_str("r#")?; - } else { - if self.symbol == kw::DollarCrate { - if let Some(span) = self.convert_dollar_crate { - let converted = span.ctxt().dollar_crate_name(); - if !converted.is_path_segment_keyword() { - f.write_str("::")?; - } - return fmt::Display::fmt(&converted, f); + } else if self.symbol == kw::DollarCrate { + if let Some(span) = self.convert_dollar_crate { + let converted = span.ctxt().dollar_crate_name(); + if !converted.is_path_segment_keyword() { + f.write_str("::")?; } + return fmt::Display::fmt(&converted, f); } } fmt::Display::fmt(&self.symbol, f) @@ -1438,6 +1469,10 @@ impl Symbol { self.0.as_u32() } + pub fn is_empty(self) -> bool { + self == kw::Invalid + } + /// This method is supposed to be used in error messages, so it's expected to be /// identical to printing the original identifier token written in source code /// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag @@ -1542,8 +1577,7 @@ impl Interner { /// Given that `kw` is imported, use them like `kw::keyword_name`. /// For example `kw::Loop` or `kw::Break`. pub mod kw { - use super::Symbol; - keywords!(); + pub use super::kw_generated::*; } // This module has a very short name because it's used a lot. @@ -1551,22 +1585,23 @@ pub mod kw { /// /// Given that `sym` is imported, use them like `sym::symbol_name`. /// For example `sym::rustfmt` or `sym::u8`. -#[allow(rustc::default_hash_types)] pub mod sym { use super::Symbol; use std::convert::TryInto; - define_symbols!(); + pub use super::sym_generated::*; // Used from a macro in `librustc_feature/accepted.rs` pub use super::kw::MacroRules as macro_rules; - // Get the symbol for an integer. The first few non-negative integers each - // have a static symbol and therefore are fast. + /// Get the symbol for an integer. + /// + /// The first few non-negative integers each have a static symbol and therefore + /// are fast. pub fn integer + Copy + ToString>(n: N) -> Symbol { if let Result::Ok(idx) = n.try_into() { - if let Option::Some(&sym_) = digits_array.get(idx) { - return sym_; + if idx < 10 { + return Symbol::new(super::SYMBOL_DIGITS_BASE + idx as u32); } } Symbol::intern(&n.to_string()) @@ -1574,17 +1609,32 @@ pub mod sym { } impl Symbol { - fn is_used_keyword_2018(self) -> bool { - self >= kw::Async && self <= kw::Dyn + fn is_special(self) -> bool { + self <= kw::Underscore + } + + fn is_used_keyword_always(self) -> bool { + self >= kw::As && self <= kw::While } - fn is_unused_keyword_2018(self) -> bool { - self == kw::Try + fn is_used_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { + (self >= kw::Async && self <= kw::Dyn) && edition() >= Edition::Edition2018 } - /// Used for sanity checking rustdoc keyword sections. - pub fn is_doc_keyword(self) -> bool { - self <= kw::Union + fn is_unused_keyword_always(self) -> bool { + self >= kw::Abstract && self <= kw::Yield + } + + fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool { + self == kw::Try && edition() >= Edition::Edition2018 + } + + pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool { + self.is_special() + || self.is_used_keyword_always() + || self.is_unused_keyword_always() + || self.is_used_keyword_conditional(edition) + || self.is_unused_keyword_conditional(edition) } /// A keyword or reserved identifier that can be used as a path segment. @@ -1602,7 +1652,7 @@ impl Symbol { self == kw::True || self == kw::False } - /// This symbol can be a raw identifier. + /// Returns `true` if this symbol can be a raw identifier. pub fn can_be_raw(self) -> bool { self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword() } @@ -1612,26 +1662,27 @@ impl Ident { // Returns `true` for reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. pub fn is_special(self) -> bool { - self.name <= kw::Underscore + self.name.is_special() } /// Returns `true` if the token is a keyword used in the language. pub fn is_used_keyword(self) -> bool { // Note: `span.edition()` is relatively expensive, don't call it unless necessary. - self.name >= kw::As && self.name <= kw::While - || self.name.is_used_keyword_2018() && self.span.rust_2018() + self.name.is_used_keyword_always() + || self.name.is_used_keyword_conditional(|| self.span.edition()) } /// Returns `true` if the token is a keyword reserved for possible future use. pub fn is_unused_keyword(self) -> bool { // Note: `span.edition()` is relatively expensive, don't call it unless necessary. - self.name >= kw::Abstract && self.name <= kw::Yield - || self.name.is_unused_keyword_2018() && self.span.rust_2018() + self.name.is_unused_keyword_always() + || self.name.is_unused_keyword_conditional(|| self.span.edition()) } /// Returns `true` if the token is either a special identifier or a keyword. pub fn is_reserved(self) -> bool { - self.is_special() || self.is_used_keyword() || self.is_unused_keyword() + // Note: `span.edition()` is relatively expensive, don't call it unless necessary. + self.name.is_reserved(|| self.span.edition()) } /// A keyword or reserved identifier that can be used as a path segment. @@ -1651,7 +1702,7 @@ fn with_interner T>(f: F) -> T { SESSION_GLOBALS.with(|session_globals| f(&mut *session_globals.symbol_interner.lock())) } -/// An alternative to `Symbol`, useful when the chars within the symbol need to +/// An alternative to [`Symbol`], useful when the chars within the symbol need to /// be accessed. It deliberately has limited functionality and should only be /// used for temporary values. /// diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index ac91fcf629..6356a7e783 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -51,7 +51,7 @@ pub(super) fn mangle( // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = tcx.erase_regions(&instance_ty); + let instance_ty = tcx.erase_regions(instance_ty); let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); @@ -222,7 +222,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { let mut first = true; for p in predicates { diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 10245d21b6..7f8cded0ac 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -245,7 +245,7 @@ fn compute_symbol_name( // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); let mangling_version = if mangling_version_crate == LOCAL_CRATE { - tcx.sess.opts.debugging_opts.symbol_mangling_version + tcx.sess.opts.debugging_opts.get_symbol_mangling_version() } else { tcx.symbol_mangling_version(mangling_version_crate) }; diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 822a835293..8c5e438a72 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -39,7 +39,7 @@ impl SymbolNamesTest<'tcx> { let def_id = def_id.to_def_id(); let instance = Instance::new( def_id, - tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)), + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)), ); let mangled = tcx.symbol_name(instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); @@ -71,4 +71,8 @@ impl hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { self.process_attrs(impl_item.hir_id); } + + fn visit_foreign_item(&mut self, foreign_item: &'tcx hir::ForeignItem<'tcx>) { + self.process_attrs(foreign_item.hir_id); + } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index c28c2fecfb..7b6e6ad069 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -319,7 +319,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { // Late-bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. - ty::ReLateBound(debruijn, ty::BrAnon(i)) => { + ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i) }) => { let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; let depth = binder.lifetime_depths.start + i; @@ -465,9 +465,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { ty::Dynamic(predicates, r) => { self.push("D"); - self = self.in_binder(&predicates, |cx, predicates| { - cx.print_dyn_existential(predicates) - })?; + self = self.print_dyn_existential(predicates)?; self = r.print(self)?; } @@ -486,26 +484,29 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { for predicate in predicates { - match predicate { - ty::ExistentialPredicate::Trait(trait_ref) => { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); - let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; - } - ty::ExistentialPredicate::Projection(projection) => { - let name = self.tcx.associated_item(projection.item_def_id).ident; - self.push("p"); - self.push_ident(&name.as_str()); - self = projection.ty.print(self)?; - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - self = self.print_def_path(def_id, &[])?; + self = self.in_binder(&predicate, |mut cx, predicate| { + match predicate { + ty::ExistentialPredicate::Trait(trait_ref) => { + // Use a type that can't appear in defaults of type parameters. + let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0)); + let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); + cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + ty::ExistentialPredicate::Projection(projection) => { + let name = cx.tcx.associated_item(projection.item_def_id).ident; + cx.push("p"); + cx.push_ident(&name.as_str()); + cx = projection.ty.print(cx)?; + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + cx = cx.print_def_path(*def_id, &[])?; + } } - } + Ok(cx) + })?; } self.push("E"); Ok(self) diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs index 917dd104d1..a630c84142 100644 --- a/compiler/rustc_target/src/abi/call/mips64.rs +++ b/compiler/rustc_target/src/abi/call/mips64.rs @@ -1,4 +1,4 @@ -use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; +use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; use crate::abi::{self, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods}; fn extend_integer_width_mips(arg: &mut ArgAbi<'_, Ty>, bits: u64) { @@ -7,7 +7,7 @@ fn extend_integer_width_mips(arg: &mut ArgAbi<'_, Ty>, bits: u64) { if let abi::Int(i, signed) = scalar.value { if !signed && i.size().bits() == 32 { if let PassMode::Direct(ref mut attrs) = arg.mode { - attrs.set(ArgAttribute::SExt); + attrs.ext(ArgExtension::Sext); return; } } @@ -137,7 +137,7 @@ where let rest_size = size - Size::from_bytes(8) * prefix_index as u64; arg.cast_to(CastTarget { prefix, - prefix_chunk: Size::from_bytes(8), + prefix_chunk_size: Size::from_bytes(8), rest: Uniform { unit: Reg::i64(), total: rest_size }, }); } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 429a3375cd..5de9a8dfa7 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -36,9 +36,12 @@ pub enum PassMode { /// a single uniform or a pair of registers. Cast(CastTarget), /// Pass the argument indirectly via a hidden pointer. - /// The second value, if any, is for the extra data (vtable or length) + /// The `extra_attrs` value, if any, is for the extra data (vtable or length) /// which indicates that it refers to an unsized rvalue. - Indirect(ArgAttributes, Option), + /// `on_stack` defines that the the value should be passed at a fixed + /// stack offset in accordance to the ABI rather than passed using a + /// pointer. This corresponds to the `byval` LLVM argument attribute. + Indirect { attrs: ArgAttributes, extra_attrs: Option, on_stack: bool }, } // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest @@ -52,24 +55,31 @@ mod attr_impl { bitflags::bitflags! { #[derive(Default)] pub struct ArgAttribute: u16 { - const ByVal = 1 << 0; const NoAlias = 1 << 1; const NoCapture = 1 << 2; const NonNull = 1 << 3; const ReadOnly = 1 << 4; - const SExt = 1 << 5; - const StructRet = 1 << 6; - const ZExt = 1 << 7; const InReg = 1 << 8; } } } +/// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum +/// defines if this extension should be zero-extension or sign-extension when necssary. When it is +/// not necesary to extend the argument, this enum is ignored. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum ArgExtension { + None, + Zext, + Sext, +} + /// A compact representation of LLVM attributes (at least those relevant for this module) /// that can be manipulated without interacting with LLVM's Attribute machinery. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct ArgAttributes { pub regular: ArgAttribute, + pub arg_ext: ArgExtension, /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call /// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes). pub pointee_size: Size, @@ -80,11 +90,18 @@ impl ArgAttributes { pub fn new() -> Self { ArgAttributes { regular: ArgAttribute::default(), + arg_ext: ArgExtension::None, pointee_size: Size::ZERO, pointee_align: None, } } + pub fn ext(&mut self, ext: ArgExtension) -> &mut Self { + assert!(self.arg_ext == ArgExtension::None || self.arg_ext == ext); + self.arg_ext = ext; + self + } + pub fn set(&mut self, attr: ArgAttribute) -> &mut Self { self.regular |= attr; self @@ -180,7 +197,7 @@ impl Uniform { #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct CastTarget { pub prefix: [Option; 8], - pub prefix_chunk: Size, + pub prefix_chunk_size: Size, pub rest: Uniform, } @@ -192,7 +209,7 @@ impl From for CastTarget { impl From for CastTarget { fn from(uniform: Uniform) -> CastTarget { - CastTarget { prefix: [None; 8], prefix_chunk: Size::ZERO, rest: uniform } + CastTarget { prefix: [None; 8], prefix_chunk_size: Size::ZERO, rest: uniform } } } @@ -200,13 +217,13 @@ impl CastTarget { pub fn pair(a: Reg, b: Reg) -> CastTarget { CastTarget { prefix: [Some(a.kind), None, None, None, None, None, None, None], - prefix_chunk: a.size, + prefix_chunk_size: a.size, rest: Uniform::from(b), } } pub fn size(&self, cx: &C) -> Size { - (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64) + (self.prefix_chunk_size * self.prefix.iter().filter(|x| x.is_some()).count() as u64) .align_to(self.rest.align(cx)) + self.rest.total } @@ -214,7 +231,7 @@ impl CastTarget { pub fn align(&self, cx: &C) -> Align { self.prefix .iter() - .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx))) + .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk_size }.align(cx))) .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| { acc.max(align) }) @@ -438,14 +455,14 @@ impl<'a, Ty> ArgAbi<'a, Ty> { let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new()); - self.mode = PassMode::Indirect(attrs, extra_attrs); + self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false }; } pub fn make_indirect_byval(&mut self) { self.make_indirect(); match self.mode { - PassMode::Indirect(ref mut attrs, _) => { - attrs.set(ArgAttribute::ByVal); + PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => { + *on_stack = true; } _ => unreachable!(), } @@ -457,7 +474,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> { if let abi::Int(i, signed) = scalar.value { if i.size().bits() < bits { if let PassMode::Direct(ref mut attrs) = self.mode { - attrs.set(if signed { ArgAttribute::SExt } else { ArgAttribute::ZExt }); + if signed { + attrs.ext(ArgExtension::Sext) + } else { + attrs.ext(ArgExtension::Zext) + }; } } } @@ -474,15 +495,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn is_indirect(&self) -> bool { - matches!(self.mode, PassMode::Indirect(..)) + matches!(self.mode, PassMode::Indirect {..}) } pub fn is_sized_indirect(&self) -> bool { - matches!(self.mode, PassMode::Indirect(_, None)) + matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }) } pub fn is_unsized_indirect(&self) -> bool { - matches!(self.mode, PassMode::Indirect(_, Some(_))) + matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }) } pub fn is_ignore(&self) -> bool { @@ -591,10 +612,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { a => return Err(format!("unrecognized arch \"{}\" in target specification", a)), } - if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); - } - Ok(()) } } diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 782c661c31..1ab881dd13 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -4,7 +4,7 @@ // Reference: Clang RISC-V ELF psABI lowering code // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773 -use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; +use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; use crate::abi::{ self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods, }; @@ -308,7 +308,7 @@ fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) { // 32-bit integers are always sign-extended if i.size().bits() == 32 && xlen > 32 { if let PassMode::Direct(ref mut attrs) = arg.mode { - attrs.set(ArgAttribute::SExt); + attrs.ext(ArgExtension::Sext); return; } } diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index 07bf1e94c6..713b4100a3 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -92,9 +92,14 @@ where for arg in &mut fn_abi.args { let attrs = match arg.mode { - PassMode::Ignore | PassMode::Indirect(_, None) => continue, + PassMode::Ignore + | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + continue; + } PassMode::Direct(ref mut attrs) => attrs, - PassMode::Pair(..) | PassMode::Indirect(_, Some(_)) | PassMode::Cast(_) => { + PassMode::Pair(..) + | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } + | PassMode::Cast(_) => { unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } }; diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 5ebd6c4a23..3c65c84b0d 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -20,16 +20,16 @@ macro_rules! def_reg_class { } impl $arch_regclass { - pub fn name(self) -> &'static str { + pub fn name(self) -> rustc_span::Symbol { match self { - $(Self::$class => stringify!($class),)* + $(Self::$class => rustc_span::symbol::sym::$class,)* } } - pub fn parse(_arch: super::InlineAsmArch, name: &str) -> Result { + pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result { match name { $( - stringify!($class) => Ok(Self::$class), + rustc_span::sym::$class => Ok(Self::$class), )* _ => Err("unknown register class"), } @@ -156,6 +156,7 @@ mod mips; mod nvptx; mod riscv; mod spirv; +mod wasm; mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; @@ -165,6 +166,7 @@ pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}; +pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)] @@ -180,6 +182,7 @@ pub enum InlineAsmArch { Mips, Mips64, SpirV, + Wasm32, } impl FromStr for InlineAsmArch { @@ -198,6 +201,7 @@ impl FromStr for InlineAsmArch { "mips" => Ok(Self::Mips), "mips64" => Ok(Self::Mips64), "spirv" => Ok(Self::SpirV), + "wasm32" => Ok(Self::Wasm32), _ => Err(()), } } @@ -213,6 +217,7 @@ pub enum InlineAsmReg { Hexagon(HexagonInlineAsmReg), Mips(MipsInlineAsmReg), SpirV(SpirVInlineAsmReg), + Wasm(WasmInlineAsmReg), } impl InlineAsmReg { @@ -272,6 +277,9 @@ impl InlineAsmReg { InlineAsmArch::SpirV => { Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?) } + InlineAsmArch::Wasm32 => { + Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?) + } }) } @@ -315,10 +323,11 @@ pub enum InlineAsmRegClass { Hexagon(HexagonInlineAsmRegClass), Mips(MipsInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass), + Wasm(WasmInlineAsmRegClass), } impl InlineAsmRegClass { - pub fn name(self) -> &'static str { + pub fn name(self) -> Symbol { match self { Self::X86(r) => r.name(), Self::Arm(r) => r.name(), @@ -328,6 +337,7 @@ impl InlineAsmRegClass { Self::Hexagon(r) => r.name(), Self::Mips(r) => r.name(), Self::SpirV(r) => r.name(), + Self::Wasm(r) => r.name(), } } @@ -344,6 +354,7 @@ impl InlineAsmRegClass { Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), + Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), } } @@ -367,6 +378,7 @@ impl InlineAsmRegClass { Self::Hexagon(r) => r.suggest_modifier(arch, ty), Self::Mips(r) => r.suggest_modifier(arch, ty), Self::SpirV(r) => r.suggest_modifier(arch, ty), + Self::Wasm(r) => r.suggest_modifier(arch, ty), } } @@ -386,6 +398,7 @@ impl InlineAsmRegClass { Self::Hexagon(r) => r.default_modifier(arch), Self::Mips(r) => r.default_modifier(arch), Self::SpirV(r) => r.default_modifier(arch), + Self::Wasm(r) => r.default_modifier(arch), } } @@ -404,32 +417,27 @@ impl InlineAsmRegClass { Self::Hexagon(r) => r.supported_types(arch), Self::Mips(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), + Self::Wasm(r) => r.supported_types(arch), } } pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result { - // FIXME: use direct symbol comparison for register class names - name.with(|name| { - Ok(match arch { - InlineAsmArch::X86 | InlineAsmArch::X86_64 => { - Self::X86(X86InlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?), - InlineAsmArch::AArch64 => { - Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { - Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), - InlineAsmArch::Hexagon => { - Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::Mips | InlineAsmArch::Mips64 => { - Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) - } - InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?), - }) + Ok(match arch { + InlineAsmArch::X86 | InlineAsmArch::X86_64 => { + Self::X86(X86InlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { + Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { + Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) + } + InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?), }) } @@ -445,6 +453,7 @@ impl InlineAsmRegClass { Self::Hexagon(r) => r.valid_modifiers(arch), Self::Mips(r) => r.valid_modifiers(arch), Self::SpirV(r) => r.valid_modifiers(arch), + Self::Wasm(r) => r.valid_modifiers(arch), } } } @@ -468,7 +477,7 @@ impl fmt::Display for InlineAsmRegOrRegClass { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Reg(r) => write!(f, "\"{}\"", r.name()), - Self::RegClass(r) => f.write_str(r.name()), + Self::RegClass(r) => write!(f, "{}", r.name()), } } } @@ -592,5 +601,10 @@ pub fn allocatable_registers( spirv::fill_reg_map(arch, has_feature, target, &mut map); map } + InlineAsmArch::Wasm32 => { + let mut map = wasm::regclass_map(); + wasm::fill_reg_map(arch, has_feature, target, &mut map); + map + } } } diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs new file mode 100644 index 0000000000..1b33f8f963 --- /dev/null +++ b/compiler/rustc_target/src/asm/wasm.rs @@ -0,0 +1,46 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; + +def_reg_class! { + Wasm WasmInlineAsmRegClass { + local, + } +} + +impl WasmInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::local => { + types! { _: I8, I16, I32, I64, F32, F64; } + } + } + } +} + +def_regs! { + // WebAssembly doesn't have registers. + Wasm WasmInlineAsmReg WasmInlineAsmRegClass {} +} diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index fb747dfcbd..1ad57582eb 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -15,6 +15,7 @@ #![feature(never_type)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] +#![feature(str_split_once)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs new file mode 100644 index 0000000000..3a88197523 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs @@ -0,0 +1,31 @@ +use super::apple_sdk_base::{opts, Arch}; +use crate::spec::{Target, TargetOptions}; + +pub fn target() -> Target { + let base = opts("ios", Arch::Arm64_macabi); + Target { + llvm_target: "arm64-apple-ios-macabi".to_string(), + pointer_width: 64, + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + options: TargetOptions { + features: "+neon,+fp-armv8,+apple-a7".to_string(), + eliminate_frame_pointer: false, + max_atomic_width: Some(128), + unsupported_abis: super::arm_base::unsupported_abis(), + forces_embed_bitcode: true, + // Taken from a clang build on Xcode 11.4.1. + // These arguments are not actually invoked - they just have + // to look right to pass App Store validation. + bitcode_llvm_cmdline: "-triple\0\ + arm64-apple-ios-macabi\0\ + -emit-obj\0\ + -disable-llvm-passes\0\ + -target-abi\0\ + darwinpcs\0\ + -Os\0" + .to_string(), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs deleted file mode 100644 index 67f69b40e5..0000000000 --- a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::spec::Target; - -pub fn target() -> Target { - let mut base = super::cloudabi_base::opts(); - base.max_atomic_width = Some(128); - base.unsupported_abis = super::arm_base::unsupported_abis(); - base.linker = Some("aarch64-unknown-cloudabi-cc".to_string()); - - Target { - llvm_target: "aarch64-unknown-cloudabi".to_string(), - pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), - arch: "aarch64".to_string(), - options: base, - } -} diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs index d0ad45153d..c9f622820d 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs @@ -10,7 +10,6 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp pub fn target() -> Target { let opts = TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".to_owned()), features: "+strict-align,+neon,+fp-armv8".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs index 41bd218290..0811871c99 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs @@ -10,7 +10,6 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp pub fn target() -> Target { let opts = TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".to_owned()), features: "+strict-align,-neon,-fp-armv8".to_string(), diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index e271a6dec4..8842239521 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -54,10 +54,7 @@ fn macos_deployment_target() -> (u32, u32) { let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok(); let version = deployment_target .as_ref() - .and_then(|s| { - let mut i = s.splitn(2, '.'); - i.next().and_then(|a| i.next().map(|b| (a, b))) - }) + .and_then(|s| s.split_once('.')) .and_then(|(a, b)| a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok()); version.unwrap_or((10, 7)) diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index 092401f114..d894f75993 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -10,6 +10,7 @@ pub enum Arch { I386, X86_64, X86_64_macabi, + Arm64_macabi, } fn target_cpu(arch: Arch) -> String { @@ -20,6 +21,7 @@ fn target_cpu(arch: Arch) -> String { I386 => "yonah", X86_64 => "core2", X86_64_macabi => "core2", + Arm64_macabi => "apple-a12", } .to_string() } @@ -27,7 +29,7 @@ fn target_cpu(arch: Arch) -> String { fn link_env_remove(arch: Arch) -> Vec { match arch { Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()], - X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()], + X86_64_macabi | Arm64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()], } } diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs index 3685630572..c6586b79b8 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs @@ -12,7 +12,6 @@ pub fn target() -> Target { options: TargetOptions { endian: "big".to_string(), - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), executables: true, linker: Some("rust-lld".to_owned()), diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs index 2ff3c8950c..e3d4397f61 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs @@ -12,7 +12,6 @@ pub fn target() -> Target { options: TargetOptions { endian: "big".to_string(), - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), executables: true, linker: Some("rust-lld".to_owned()), diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs new file mode 100644 index 0000000000..3eb0f4db83 --- /dev/null +++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs @@ -0,0 +1,20 @@ +use crate::spec::{Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "armv5te-unknown-linux-uclibcgnueabi".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + options: TargetOptions { + features: "+soft-float,+strict-align".to_string(), + // Atomic operations provided by compiler-builtins + max_atomic_width: Some(32), + unsupported_abis: super::arm_base::unsupported_abis(), + mcount: "\u{1}__gnu_mcount_nc".to_string(), + has_thumb_interworking: true, + + ..super::linux_uclibc_base::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs deleted file mode 100644 index d47ee541b2..0000000000 --- a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::spec::{Target, TargetOptions}; - -pub fn target() -> Target { - let mut base = super::cloudabi_base::opts(); - base.cpu = "cortex-a8".to_string(); - base.max_atomic_width = Some(64); - base.features = "+v7,+vfp3,+neon".to_string(); - base.unsupported_abis = super::arm_base::unsupported_abis(); - base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string()); - - Target { - llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(), - pointer_width: 32, - data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), - arch: "arm".to_string(), - options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base }, - } -} diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs index 742b403cff..74deab0191 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs @@ -10,9 +10,6 @@ // bare-metal binaries (the `gcc` linker has the advantage that it knows where C // libraries and crt*.o are but it's not much of an advantage here); LLD is also // faster -// - `os` set to `none`. rationale: matches `thumb` targets -// - `env` and `vendor` are set to an empty string. rationale: matches `thumb` -// targets // - `panic_strategy` set to `abort`. rationale: matches `thumb` targets // - `relocation-model` set to `static`; also no PIE, no relro and no dynamic // linking. rationale: matches `thumb` targets @@ -21,7 +18,6 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp pub fn target() -> Target { let opts = TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".to_owned()), features: "+v7,+thumb2,+soft-float,-neon,+strict-align".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs index b9cda18d6b..c5c720f5fb 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs @@ -9,7 +9,6 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp pub fn target() -> Target { let opts = TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".to_owned()), features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs index 440c243490..3f49bd8786 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs @@ -11,7 +11,6 @@ pub fn target() -> Target { arch: "arm".to_string(), options: TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), executables: true, linker: Some("rust-lld".to_owned()), diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs index c1bf332a72..9b2e8a8058 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs @@ -11,7 +11,6 @@ pub fn target() -> Target { arch: "arm".to_string(), options: TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), executables: true, linker: Some("rust-lld".to_owned()), diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index 9cc10032c7..67a7684da2 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -11,7 +11,6 @@ pub fn target(target_cpu: String) -> Target { pointer_width: 16, options: TargetOptions { c_int_width: "16".to_string(), - os: "unknown".to_string(), cpu: target_cpu.clone(), exe_suffix: ".elf".to_string(), diff --git a/compiler/rustc_target/src/spec/cloudabi_base.rs b/compiler/rustc_target/src/spec/cloudabi_base.rs deleted file mode 100644 index 20a095742e..0000000000 --- a/compiler/rustc_target/src/spec/cloudabi_base.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions, TlsModel}; - -pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - "-Wl,-Bstatic".to_string(), - "-Wl,--no-dynamic-linker".to_string(), - "-Wl,--gc-sections".to_string(), - ], - ); - - TargetOptions { - os: "cloudabi".to_string(), - executables: true, - os_family: None, - linker_is_gnu: true, - pre_link_args: args, - position_independent_executables: true, - // As CloudABI only supports static linkage, there is no need - // for dynamic TLS. The C library therefore does not provide - // __tls_get_addr(), which is normally used to perform dynamic - // TLS lookups by programs that make use of dlopen(). Only the - // "local-exec" and "initial-exec" TLS models can be used. - // - // "local-exec" is more efficient than "initial-exec", as the - // latter has one more level of indirection: it accesses the GOT - // (Global Offset Table) to obtain the effective address of a - // thread-local variable. Using a GOT is useful only when doing - // dynamic linking. - tls_model: TlsModel::LocalExec, - relro_level: RelroLevel::Full, - ..Default::default() - } -} diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs index e467c7c8f2..5c39773cbe 100644 --- a/compiler/rustc_target/src/spec/fuchsia_base.rs +++ b/compiler/rustc_target/src/spec/fuchsia_base.rs @@ -21,7 +21,6 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "fuchsia".to_string(), - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".to_owned()), lld_flavor: LldFlavor::Ld, diff --git a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs deleted file mode 100644 index 0cdb9f9de5..0000000000 --- a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::spec::{LinkerFlavor, Target}; - -pub fn target() -> Target { - let mut base = super::cloudabi_base::opts(); - base.cpu = "pentium4".to_string(); - base.max_atomic_width = Some(64); - base.linker = Some("i686-unknown-cloudabi-cc".to_string()); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.stack_probes = true; - - Target { - llvm_target: "i686-unknown-cloudabi".to_string(), - pointer_width: 32, - data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - f64:32:64-f80:32-n8:16:32-S128" - .to_string(), - arch: "x86".to_string(), - options: base, - } -} diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs index a8005927a7..0f9d3c3de1 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs @@ -14,7 +14,6 @@ pub fn target() -> Target { arch: "mips".to_string(), options: TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float,+noabicalls".to_string(), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f949bf95a5..8d72df6850 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -54,7 +54,6 @@ mod apple_base; mod apple_sdk_base; mod arm_base; mod avr_gnu_base; -mod cloudabi_base; mod dragonfly_base; mod freebsd_base; mod fuchsia_base; @@ -505,6 +504,7 @@ supported_targets! { ("armv4t-unknown-linux-gnueabi", armv4t_unknown_linux_gnueabi), ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi), ("armv5te-unknown-linux-musleabi", armv5te_unknown_linux_musleabi), + ("armv5te-unknown-linux-uclibceabi", armv5te_unknown_linux_uclibceabi), ("armv7-unknown-linux-gnueabi", armv7_unknown_linux_gnueabi), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), ("thumbv7neon-unknown-linux-gnueabihf", thumbv7neon_unknown_linux_gnueabihf), @@ -580,6 +580,7 @@ supported_targets! { ("armv7-apple-ios", armv7_apple_ios), ("armv7s-apple-ios", armv7s_apple_ios), ("x86_64-apple-ios-macabi", x86_64_apple_ios_macabi), + ("aarch64-apple-ios-macabi", aarch64_apple_ios_macabi), ("aarch64-apple-tvos", aarch64_apple_tvos), ("x86_64-apple-tvos", x86_64_apple_tvos), @@ -628,11 +629,6 @@ supported_targets! { ("msp430-none-elf", msp430_none_elf), - ("aarch64-unknown-cloudabi", aarch64_unknown_cloudabi), - ("armv7-unknown-cloudabi-eabihf", armv7_unknown_cloudabi_eabihf), - ("i686-unknown-cloudabi", i686_unknown_cloudabi), - ("x86_64-unknown-cloudabi", x86_64_unknown_cloudabi), - ("aarch64-unknown-hermit", aarch64_unknown_hermit), ("x86_64-unknown-hermit", x86_64_unknown_hermit), ("x86_64-unknown-hermit-kernel", x86_64_unknown_hermit_kernel), @@ -713,11 +709,14 @@ pub struct TargetOptions { pub endian: String, /// Width of c_int type. Defaults to "32". pub c_int_width: String, - /// OS name to use for conditional compilation. Defaults to "none". + /// OS name to use for conditional compilation (`target_os`). Defaults to "none". + /// "none" implies a bare metal target without `std` library. + /// A couple of targets having `std` also use "unknown" as an `os` value, + /// but they are exceptions. pub os: String, - /// Environment name to use for conditional compilation. Defaults to "". + /// Environment name to use for conditional compilation (`target_env`). Defaults to "". pub env: String, - /// Vendor name to use for conditional compilation. Defaults to "unknown". + /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". pub vendor: String, /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed /// on the command line. Defaults to `LinkerFlavor::Gcc`. @@ -819,10 +818,23 @@ pub struct TargetOptions { /// Only useful for compiling against Illumos/Solaris, /// as they have a different set of linker flags. Defaults to false. pub is_like_solaris: bool, - /// Whether the target toolchain is like Windows'. Only useful for compiling against Windows, - /// only really used for figuring out how to find libraries, since Windows uses its own - /// library naming convention. Defaults to false. + /// Whether the target is like Windows. + /// This is a combination of several more specific properties represented as a single flag: + /// - The target uses a Windows ABI, + /// - uses PE/COFF as a format for object code, + /// - uses Windows-style dllexport/dllimport for shared libraries, + /// - uses import libraries and .def files for symbol exports, + /// - executables support setting a subsystem. pub is_like_windows: bool, + /// Whether the target is like MSVC. + /// This is a combination of several more specific properties represented as a single flag: + /// - The target has all the properties from `is_like_windows` + /// (for in-tree targets "is_like_msvc ⇒ is_like_windows" is ensured by a unit test), + /// - has some MSVC-specific Windows ABI properties, + /// - uses a link.exe-like linker, + /// - uses CodeView/PDB for debuginfo and natvis for its visualization, + /// - uses SEH-based unwinding, + /// - supports control flow guard mechanism. pub is_like_msvc: bool, /// Whether the target toolchain is like Emscripten's. Only useful for compiling with /// Emscripten toolchain. @@ -1428,8 +1440,8 @@ impl Target { } key!(is_builtin, bool); - key!(endian = "target_endian"); - key!(c_int_width = "target_c_int_width"); + key!(endian = "target-endian"); + key!(c_int_width = "target-c-int-width"); key!(os); key!(env); key!(vendor); @@ -1466,7 +1478,7 @@ impl Target { key!(exe_suffix); key!(staticlib_prefix); key!(staticlib_suffix); - key!(os_family = "target_family", optional); + key!(os_family = "target-family", optional); key!(abi_return_struct_as_int, bool); key!(is_like_osx, bool); key!(is_like_solaris, bool); @@ -1511,7 +1523,7 @@ impl Target { key!(limit_rdylib_exports, bool); key!(override_export_symbols, opt_list); key!(merge_functions, MergeFunctions)?; - key!(mcount = "target_mcount"); + key!(mcount = "target-mcount"); key!(llvm_abiname); key!(relax_elf_relocations, bool); key!(llvm_args, list); @@ -1663,8 +1675,8 @@ impl ToJson for Target { target_val!(data_layout); target_option_val!(is_builtin); - target_option_val!(endian, "target_endian"); - target_option_val!(c_int_width, "target_c_int_width"); + target_option_val!(endian, "target-endian"); + target_option_val!(c_int_width, "target-c-int-width"); target_option_val!(os); target_option_val!(env); target_option_val!(vendor); @@ -1701,7 +1713,7 @@ impl ToJson for Target { target_option_val!(exe_suffix); target_option_val!(staticlib_prefix); target_option_val!(staticlib_suffix); - target_option_val!(os_family, "target_family"); + target_option_val!(os_family, "target-family"); target_option_val!(abi_return_struct_as_int); target_option_val!(is_like_osx); target_option_val!(is_like_solaris); @@ -1746,7 +1758,7 @@ impl ToJson for Target { target_option_val!(limit_rdylib_exports); target_option_val!(override_export_symbols); target_option_val!(merge_functions); - target_option_val!(mcount, "target_mcount"); + target_option_val!(mcount, "target-mcount"); target_option_val!(llvm_abiname); target_option_val!(relax_elf_relocations); target_option_val!(llvm_args); @@ -1788,6 +1800,24 @@ impl TargetTriple { Ok(TargetTriple::TargetPath(canonicalized_path)) } + /// Creates a target triple from its alias + pub fn from_alias(triple: String) -> Self { + macro_rules! target_aliases { + ( $(($alias:literal, $target:literal ),)+ ) => { + match triple.as_str() { + $( $alias => TargetTriple::from_triple($target), )+ + _ => TargetTriple::TargetTriple(triple), + } + } + } + + target_aliases! { + // `x86_64-pc-solaris` is an alias for `x86_64_sun_solaris` for backwards compatibility reasons. + // (See .) + ("x86_64-pc-solaris", "x86_64-sun-solaris"), + } + } + /// Returns a string triple for this target. /// /// If this target is a path, the file name (without extension) is returned. diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs index ef966cb702..cc2578aa57 100644 --- a/compiler/rustc_target/src/spec/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs @@ -9,7 +9,6 @@ pub fn target() -> Target { options: TargetOptions { c_int_width: "16".to_string(), - vendor: String::new(), executables: true, // The LLVM backend currently can't generate object files. To diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index f348df7d5a..9ec8467e0a 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -8,6 +8,7 @@ pub(super) fn test_target(target: Target) { impl Target { fn check_consistency(&self) { + assert!(self.is_like_windows || !self.is_like_msvc); // Check that LLD with the given flavor is treated identically to the linker it emulates. // If your target really needs to deviate from the rules below, except it and document the // reasons. @@ -16,6 +17,7 @@ impl Target { || self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link), self.lld_flavor == LldFlavor::Link, ); + assert_eq!(self.is_like_msvc, self.lld_flavor == LldFlavor::Link); for args in &[ &self.pre_link_args, &self.late_link_args, @@ -36,5 +38,18 @@ impl Target { && self.post_link_objects_fallback.is_empty()) || self.crt_objects_fallback.is_some() ); + // Keep the default "unknown" vendor instead. + assert_ne!(self.vendor, ""); + if !self.can_use_os_unknown() { + // Keep the default "none" for bare metal targets instead. + assert_ne!(self.os, "unknown"); + } + } + + // Add your target to the whitelist if it has `std` library + // and you certainly want "unknown" for the OS name. + fn can_use_os_unknown(&self) -> bool { + self.llvm_target == "wasm32-unknown-unknown" + || (self.env == "sgx" && self.vendor == "fortanix") } } diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs index e550467502..ec24807fec 100644 --- a/compiler/rustc_target/src/spec/thumb_base.rs +++ b/compiler/rustc_target/src/spec/thumb_base.rs @@ -32,7 +32,6 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOpti pub fn opts() -> TargetOptions { // See rust-lang/rfcs#1645 for a discussion about these defaults TargetOptions { - vendor: String::new(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), executables: true, // In most cases, LLD is good enough diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs index 79fe77495e..322b6f530e 100644 --- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs +++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs @@ -46,15 +46,6 @@ pub fn opts() -> TargetOptions { stack_probes: true, singlethread: true, linker: Some("rust-lld".to_string()), - // FIXME: This should likely be `true` inherited from `msvc_base` - // because UEFI follows Windows ABI and uses PE/COFF. - // The `false` is probably causing ABI bugs right now. - is_like_windows: false, - // FIXME: This should likely be `true` inherited from `msvc_base` - // because UEFI follows Windows ABI and uses PE/COFF. - // The `false` is probably causing ABI bugs right now. - is_like_msvc: false, - ..base } } diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 9c697674f3..3f44acdc36 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -79,7 +79,6 @@ pub fn target() -> Target { let mut options = wasm32_base::options(); options.os = "wasi".to_string(); - options.vendor = String::new(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); options .pre_link_args diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 4ae940ee5c..f556a13a51 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -11,6 +11,10 @@ pub fn opts() -> TargetOptions { "-fno-use-linker-plugin".to_string(), // Always enable DEP (NX bit) when it is available "-Wl,--nxcompat".to_string(), + // Enable ASLR + "-Wl,--dynamicbase".to_string(), + // ASLR will rebase it anyway so leaving that option enabled only leads to confusion + "-Wl,--disable-auto-image-base".to_string(), ], ); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index e8dee94cce..36726ab4ae 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + gcc_pre_link_args.push("-m64".to_string()); + // Use high-entropy 64 bit address space for ASLR + gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string()); base.pre_link_args .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs deleted file mode 100644 index cf57f4ec62..0000000000 --- a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::spec::{LinkerFlavor, Target}; - -pub fn target() -> Target { - let mut base = super::cloudabi_base::opts(); - base.cpu = "x86-64".to_string(); - base.max_atomic_width = Some(64); - base.linker = Some("x86_64-unknown-cloudabi-cc".to_string()); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); - base.stack_probes = true; - - Target { - llvm_target: "x86_64-unknown-cloudabi".to_string(), - pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .to_string(), - arch: "x86_64".to_string(), - options: base, - } -} diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index e2ba553c5f..57913ba0da 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + gcc_pre_link_args.push("-m64".to_string()); + // Use high-entropy 64 bit address space for ASLR + gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string()); base.pre_link_args .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index b9c5123e49..05b6c4a48d 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -109,7 +109,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { param_env, state: AutoderefSnapshot { steps: vec![], - cur_ty: infcx.resolve_vars_if_possible(&base_ty), + cur_ty: infcx.resolve_vars_if_possible(base_ty), obligations: vec![], at_start: true, reached_recursion_limit: false, @@ -164,14 +164,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); - Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) + Some(self.infcx.resolve_vars_if_possible(normalized_ty)) } /// Returns the final type we ended up with, which may be an inference /// variable (we will resolve it first, if we want). pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> { if resolve { - self.infcx.resolve_vars_if_possible(&self.state.cur_ty) + self.infcx.resolve_vars_if_possible(self.state.cur_ty) } else { self.state.cur_ty } diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 4ec1b29bca..41184ce211 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -28,7 +28,7 @@ pub trait InferCtxtExt<'tcx> { span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> InferOk<'tcx, T> where T: TypeFoldable<'tcx>; @@ -41,7 +41,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { ty: Ty<'tcx>, span: Span, ) -> bool { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); if !(param_env, ty).needs_infer() { return ty.is_copy_modulo_regions(self.tcx.at(span), param_env); @@ -63,7 +63,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> InferOk<'tcx, T> where T: TypeFoldable<'tcx>, @@ -173,7 +173,7 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { debug!("add_implied_bounds()"); for &ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(&ty); + let ty = infcx.resolve_vars_if_possible(ty); debug!("add_implied_bounds: ty = {}", ty); let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); self.add_outlives_bounds(Some(infcx), implied_bounds) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 914fa1e52c..f5bc90e6f9 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -12,7 +12,6 @@ use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::config::nightly_options; use rustc_span::Span; use std::ops::ControlFlow; @@ -113,7 +112,7 @@ pub trait InferCtxtExt<'tcx> { parent_def_id: LocalDefId, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, value_span: Span, ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>; @@ -189,7 +188,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { parent_def_id: LocalDefId, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, value_span: Span, ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> { debug!( @@ -403,7 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let tcx = self.tcx; - let concrete_ty = self.resolve_vars_if_possible(&opaque_defn.concrete_ty); + let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty); debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); @@ -602,7 +601,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; err.span_label(span, label); - if nightly_options::is_nightly_build() { + if self.tcx.sess.is_nightly_build() { err.help("add #![feature(member_constraints)] to the crate attributes to enable"); } @@ -693,12 +692,15 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor where OP: FnMut(ty::Region<'tcx>), { - fn visit_binder>(&mut self, t: &ty::Binder) -> ControlFlow<()> { + fn visit_binder>( + &mut self, + t: &ty::Binder, + ) -> ControlFlow { t.as_ref().skip_binder().visit_with(self); ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { // ignore bound regions, keep visiting ty::ReLateBound(_, _) => ControlFlow::CONTINUE, @@ -709,7 +711,7 @@ where } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { return ControlFlow::CONTINUE; @@ -720,11 +722,6 @@ where // Skip lifetime parameters of the enclosing item(s) substs.as_closure().tupled_upvars_ty().visit_with(self); - - for upvar_ty in substs.as_closure().upvar_tys() { - upvar_ty.visit_with(self); - } - substs.as_closure().sig_as_fn_ptr_ty().visit_with(self); } @@ -733,11 +730,6 @@ where // Also skip the witness type, because that has no free regions. substs.as_generator().tupled_upvars_ty().visit_with(self); - - for upvar_ty in substs.as_generator().upvar_tys() { - upvar_ty.visit_with(self); - } - substs.as_generator().return_ty().visit_with(self); substs.as_generator().yield_ty().visit_with(self); substs.as_generator().resume_ty().visit_with(self); @@ -1002,7 +994,7 @@ struct Instantiator<'a, 'tcx> { } impl<'a, 'tcx> Instantiator<'a, 'tcx> { - fn instantiate_opaque_types_in_map>(&mut self, value: &T) -> T { + fn instantiate_opaque_types_in_map>(&mut self, value: T) -> T { debug!("instantiate_opaque_types_in_map(value={:?})", value); let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { @@ -1126,7 +1118,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let param_env = tcx.param_env(def_id); let InferOk { value: bounds, obligations } = - infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, &bounds); + infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, bounds); self.obligations.extend(obligations); debug!("instantiate_opaque_types: bounds={:?}", bounds); @@ -1174,7 +1166,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // Change the predicate to refer to the type variable, // which will be the concrete type instead of the opaque type. // This also instantiates nested instances of `impl Trait`. - let predicate = self.instantiate_opaque_types_in_map(&predicate); + let predicate = self.instantiate_opaque_types_in_map(predicate); let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 93a0073588..6ab16886ed 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -304,11 +304,8 @@ impl AutoTraitFinder<'tcx> { // Call `infcx.resolve_vars_if_possible` to see if we can // get rid of any inference variables. - let obligation = infcx.resolve_vars_if_possible(&Obligation::new( - dummy_cause.clone(), - new_env, - pred, - )); + let obligation = + infcx.resolve_vars_if_possible(Obligation::new(dummy_cause.clone(), new_env, pred)); let result = select.select(&obligation); match &result { @@ -627,7 +624,7 @@ impl AutoTraitFinder<'tcx> { fresh_preds.insert(self.clean_pred(select.infcx(), obligation.predicate)); // Resolve any inference variables that we can, to help selection succeed - let predicate = select.infcx().resolve_vars_if_possible(&obligation.predicate); + let predicate = select.infcx().resolve_vars_if_possible(obligation.predicate); // We only add a predicate as a user-displayable bound if // it involves a generic parameter, and doesn't contain diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index adc8ae5908..026ab41444 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -37,7 +37,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { obligation: PredicateObligation<'tcx>, ) { assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(&obligation); + let obligation = infcx.resolve_vars_if_possible(obligation); self.obligations.insert(obligation); } @@ -80,11 +80,11 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { // We iterate over all obligations, and record if we are able // to unambiguously prove at least one obligation. for obligation in self.obligations.drain(..) { - let obligation = infcx.resolve_vars_if_possible(&obligation); + let obligation = infcx.resolve_vars_if_possible(obligation); let environment = obligation.param_env.caller_bounds(); let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values); + let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values); match infcx.tcx.evaluate_goal(canonical_goal) { Ok(response) => { @@ -100,7 +100,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { Ok(infer_ok) => next_round.extend( infer_ok.obligations.into_iter().map(|obligation| { assert!(!infcx.is_in_snapshot()); - infcx.resolve_vars_if_possible(&obligation) + infcx.resolve_vars_if_possible(obligation) }), ), diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 3cb6ec8626..657d5c123e 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -25,7 +25,7 @@ pub fn codegen_fulfill_obligation<'tcx>( (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), ) -> Result, ErrorReported> { // Remove any references to regions; this helps improve caching. - let trait_ref = tcx.erase_regions(&trait_ref); + let trait_ref = tcx.erase_regions(trait_ref); // We expect the input to be fully normalized. debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); debug!( @@ -89,7 +89,7 @@ pub fn codegen_fulfill_obligation<'tcx>( debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source); + let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); info!("Cache miss: {:?} => {:?}", trait_ref, impl_source); Ok(impl_source) @@ -110,7 +110,7 @@ pub fn codegen_fulfill_obligation<'tcx>( fn drain_fulfillment_cx_or_panic( infcx: &InferCtxt<'_, 'tcx>, fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T, + result: T, ) -> T where T: TypeFoldable<'tcx>, @@ -128,5 +128,5 @@ where } let result = infcx.resolve_vars_if_possible(result); - infcx.tcx.erase_regions(&result) + infcx.tcx.erase_regions(result) } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index c53c65c00b..9324d55ac1 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -103,7 +103,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>( }; let Normalized { value: mut header, obligations } = - traits::normalize(selcx, param_env, ObligationCause::dummy(), &header); + traits::normalize(selcx, param_env, ObligationCause::dummy(), header); header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); header @@ -162,7 +162,8 @@ fn overlap_within_probe( let opt_failing_obligation = a_impl_header .predicates .iter() - .chain(&b_impl_header.predicates) + .copied() + .chain(b_impl_header.predicates) .map(|p| infcx.resolve_vars_if_possible(p)) .map(|p| Obligation { cause: ObligationCause::dummy(), @@ -188,7 +189,7 @@ fn overlap_within_probe( } } - let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header); + let impl_header = selcx.infcx().resolve_vars_if_possible(a_impl_header); let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index e1721a5a88..fdb2361ba0 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -78,7 +78,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const(tcx, ct, |node| match node { + walk_abstract_const::(tcx, ct, |node| match node { Node::Leaf(leaf) => { let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { @@ -574,19 +574,19 @@ pub(super) fn try_unify_abstract_consts<'tcx>( // on `ErrorReported`. } -pub fn walk_abstract_const<'tcx, F>( +pub fn walk_abstract_const<'tcx, R, F>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F, -) -> ControlFlow<()> +) -> ControlFlow where - F: FnMut(Node<'tcx>) -> ControlFlow<()>, + F: FnMut(Node<'tcx>) -> ControlFlow, { - fn recurse<'tcx>( + fn recurse<'tcx, R>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<()>, - ) -> ControlFlow<()> { + f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow, + ) -> ControlFlow { let root = ct.root(); f(root)?; match root { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 2d57c39f7c..9feba7bfc4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { where T: fmt::Display + TypeFoldable<'tcx>, { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate.clone()); let mut err = struct_span_err!( self.tcx.sess, obligation.cause.span, @@ -200,6 +200,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &obligation.predicate, &obligation.cause.code, &mut vec![], + &mut Default::default(), ); err.emit(); @@ -213,7 +214,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// we do not suggest increasing the overflow limit, which is not /// going to help). fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { - let cycle = self.resolve_vars_if_possible(&cycle.to_owned()); + let cycle = self.resolve_vars_if_possible(cycle.to_owned()); assert!(!cycle.is_empty()); debug!("report_overflow_error_cycle: cycle={:?}", cycle); @@ -259,7 +260,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(trait_predicate, _) => { let trait_predicate = bound_predicate.rebind(trait_predicate); - let trait_predicate = self.resolve_vars_if_possible(&trait_predicate); + let trait_predicate = self.resolve_vars_if_possible(trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { return; @@ -414,17 +415,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(enclosing_scope_span, s.as_str()); } - self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_remove_reference(&obligation, &mut err, &trait_ref); - self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); + self.suggest_dereferences(&obligation, &mut err, trait_ref, points_at_arg); + self.suggest_fn_call(&obligation, &mut err, trait_ref, points_at_arg); + self.suggest_remove_reference(&obligation, &mut err, trait_ref); + self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref); self.note_version_mismatch(&mut err, &trait_ref); if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { - self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); + self.suggest_await_before_try(&mut err, &obligation, trait_ref, span); } - if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { + if self.suggest_impl_trait(&mut err, span, &obligation, trait_ref) { err.emit(); return; } @@ -487,7 +488,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_change_mut( &obligation, &mut err, - &trait_ref, + trait_ref, points_at_arg, ); } @@ -533,7 +534,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::PredicateAtom::RegionOutlives(predicate) => { let predicate = bound_predicate.rebind(predicate); - let predicate = self.resolve_vars_if_possible(&predicate); + let predicate = self.resolve_vars_if_possible(predicate); let err = self .region_outlives_predicate(&obligation.cause, predicate) .err() @@ -549,7 +550,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } ty::PredicateAtom::Projection(..) | ty::PredicateAtom::TypeOutlives(..) => { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate); struct_span_err!( self.tcx.sess, span, @@ -671,9 +672,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { - let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref); - let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref); + OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => { + let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); + let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); if expected_trait_ref.self_ty().references_error() { return; @@ -1035,7 +1036,7 @@ trait InferCtxtPrivExt<'tcx> { fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx>; @@ -1157,7 +1158,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>, ) { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate); if predicate.references_error() { return; @@ -1178,7 +1179,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let (data, _) = self.replace_bound_vars_with_fresh_vars( obligation.cause.span, infer::LateBoundRegionConversionTime::HigherRankedType, - &bound_predicate.rebind(data), + bound_predicate.rebind(data), ); let mut obligations = vec![]; let normalized_ty = super::normalize_projection_type( @@ -1309,10 +1310,20 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return None; } } + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { + return None; + } Some(imp) }) .collect(), - None => all_impls.map(|def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect(), + None => all_impls + .filter_map(|def_id| { + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { + return None; + } + self.tcx.impl_trait_ref(def_id) + }) + .collect(), } } @@ -1343,7 +1354,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // Sort impl candidates so that ordering is consistent for UI tests. let mut normalized_impl_candidates = - impl_candidates.iter().map(normalize).collect::>(); + impl_candidates.iter().copied().map(normalize).collect::>(); // Sort before taking the `..end` range, // because the ordering of `impl_candidates` may not be deterministic: @@ -1364,7 +1375,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> Option<(String, Option)> { match code { &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), None => { @@ -1414,7 +1425,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx> { assert!(!new_self_ty.has_escaping_bound_vars()); @@ -1441,7 +1452,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // ambiguous impls. The latter *ought* to be a // coherence violation, so we don't report it here. - let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; debug!( @@ -1673,7 +1684,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { &mut selcx, param_env, ObligationCause::dummy(), - &cleaned_pred, + cleaned_pred, ) .value; @@ -1700,6 +1711,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { &obligation.predicate, &obligation.cause.code, &mut vec![], + &mut Default::default(), ); self.suggest_unsized_bound_if_applicable(err, obligation); } @@ -1808,7 +1820,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, ) -> bool { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) { return true; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 0f5aad5af1..69f66f6e6b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> Option { let tcx = self.tcx; let param_env = obligation.param_env; - let trait_ref = tcx.erase_late_bound_regions(&trait_ref); + let trait_ref = tcx.erase_late_bound_regions(trait_ref); let trait_self_ty = trait_ref.self_ty(); let mut self_match_impls = vec![]; @@ -219,8 +219,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } if let ty::Dynamic(traits, _) = self_ty.kind() { - for t in traits.skip_binder() { - if let ty::ExistentialPredicate::Trait(trait_ref) = t { + for t in traits.iter() { + if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1c6e661782..79fea83a66 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -7,6 +7,7 @@ use crate::autoderef::Autoderef; use crate::infer::InferCtxt; use crate::traits::normalize_projection_type; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style}; use rustc_hir as hir; @@ -49,7 +50,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, points_at_arg: bool, ); @@ -64,7 +65,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, points_at_arg: bool, ); @@ -81,14 +82,14 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, ); fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, points_at_arg: bool, ); @@ -97,7 +98,7 @@ pub trait InferCtxtExt<'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, ); fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option; @@ -107,7 +108,7 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, ) -> bool; fn point_at_returns_when_relevant( @@ -158,6 +159,7 @@ pub trait InferCtxtExt<'tcx> { predicate: &T, cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<&ty::TyS<'tcx>>, + seen_requirements: &mut FxHashSet, ) where T: fmt::Display; @@ -168,7 +170,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, span: Span, ); } @@ -252,27 +254,21 @@ fn suggest_restriction( let pred = trait_ref.without_const().to_predicate(tcx).to_string(); let pred = pred.replace(&impl_trait_str, &type_param_name); let mut sugg = vec![ + // Find the last of the generic parameters contained within the span of + // the generics match generics .params .iter() - .filter(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - _ => true, - }) - .last() + .map(|p| p.bounds_span().unwrap_or(p.span)) + .filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none()) + .max_by_key(|span| span.hi()) { // `fn foo(t: impl Trait)` // ^ suggest `` here None => (generics.span, format!("<{}>", type_param)), // `fn foo
(t: impl Trait)` // ^^^ suggest `` here - Some(param) => ( - param.bounds_span().unwrap_or(param.span).shrink_to_hi(), - format!(", {}", type_param), - ), + Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)), }, // `fn foo(t: impl Trait)` // ^ suggest `where ::A: Bound` @@ -462,7 +458,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, points_at_arg: bool, ) { // It only make sense when suggesting dereferences for arguments @@ -475,7 +471,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let real_trait_ref = match &obligation.cause.code { ObligationCauseCode::ImplDerivedObligation(cause) | ObligationCauseCode::DerivedObligation(cause) - | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref, + | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref, _ => trait_ref, }; let real_ty = match real_trait_ref.self_ty().no_bound_vars() { @@ -556,7 +552,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, points_at_arg: bool, ) { let self_ty = match trait_ref.self_ty().no_bound_vars() { @@ -734,7 +730,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, ) { let span = obligation.cause.span; @@ -797,7 +793,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, points_at_arg: bool, ) { let span = obligation.cause.span; @@ -832,7 +828,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let new_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, - &trait_ref, + trait_ref, suggested_ty, ); let suggested_ty_would_satisfy_obligation = self @@ -869,7 +865,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, ) { let is_empty_tuple = |ty: ty::Binder>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty()); @@ -919,7 +915,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, ) -> bool { match obligation.cause.code.peel_derives() { // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. @@ -976,12 +972,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .returns .iter() .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) - .map(|ty| self.resolve_vars_if_possible(&ty)); + .map(|ty| self.resolve_vars_if_possible(ty)); let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold( (None, true, true), |(last_ty, mut same, only_never_return): (std::option::Option>, bool, bool), ty| { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); same &= !matches!(ty.kind(), ty::Error(_)) && last_ty.map_or(true, |last_ty| { @@ -1133,7 +1129,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); for expr in &visitor.returns { if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) { - let ty = self.resolve_vars_if_possible(&returned_ty); + let ty = self.resolve_vars_if_possible(returned_ty); err.span_label(expr.span, &format!("this returned value is of type `{}`", ty)); } } @@ -1149,9 +1145,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx> { crate fn build_fn_sig_string<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) -> String { - let inputs = trait_ref.substs.type_at(1); + let inputs = trait_ref.skip_binder().substs.type_at(1); let sig = if let ty::Tuple(inputs) = inputs.kind() { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), @@ -1169,7 +1165,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { abi::Abi::Rust, ) }; - ty::Binder::bind(sig).to_string() + trait_ref.rebind(sig).to_string() } let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); @@ -1181,17 +1177,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if argument_is_closure { "closure" } else { "function" } ); - let found_str = format!( - "expected signature of `{}`", - build_fn_sig_string(self.tcx, found.skip_binder()) - ); + let found_str = format!("expected signature of `{}`", build_fn_sig_string(self.tcx, found)); err.span_label(span, found_str); let found_span = found_span.unwrap_or(span); - let expected_str = format!( - "found signature of `{}`", - build_fn_sig_string(self.tcx, expected_ref.skip_binder()) - ); + let expected_str = + format!("found signature of `{}`", build_fn_sig_string(self.tcx, expected_ref)); err.span_label(found_span, expected_str); err @@ -1406,7 +1397,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Look for a type inside the generator interior that matches the target type to get // a span. - let target_ty_erased = self.tcx.erase_regions(&target_ty); + let target_ty_erased = self.tcx.erase_regions(target_ty); let ty_matches = |ty| -> bool { // Careful: the regions for types that appear in the // generator interior are not generally known, so we @@ -1420,8 +1411,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // generator frame. Bound regions are preserved by // `erase_regions` and so we must also call // `erase_late_bound_regions`. - let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(ty)); - let ty_erased = self.tcx.erase_regions(&ty_erased); + let ty_erased = self.tcx.erase_late_bound_regions(ty); + let ty_erased = self.tcx.erase_regions(ty_erased); let eq = ty::TyS::same_type(ty_erased, target_ty_erased); debug!( "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ @@ -1437,8 +1428,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) { interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| { let upvar_ty = typeck_results.node_type(*upvar_id); - let upvar_ty = self.resolve_vars_if_possible(&upvar_ty); - if ty_matches(&upvar_ty) { + let upvar_ty = self.resolve_vars_if_possible(upvar_ty); + if ty_matches(ty::Binder::dummy(upvar_ty)) { Some(GeneratorInteriorOrUpvar::Upvar(upvar.span)) } else { None @@ -1446,31 +1437,33 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); }; - typeck_results - .generator_interior_types - .iter() - .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty)) - .map(|cause| { - // Check to see if any awaited expressions have the target type. - let from_awaited_ty = visitor - .awaits - .into_iter() - .map(|id| hir.expect_expr(id)) - .find(|await_expr| { - let ty = typeck_results.expr_ty_adjusted(&await_expr); - debug!( - "maybe_note_obligation_cause_for_async_await: await_expr={:?}", - await_expr - ); - ty_matches(ty) - }) - .map(|expr| expr.span); - let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = - cause; + // The generator interior types share the same binders + if let Some(cause) = + typeck_results.generator_interior_types.as_ref().skip_binder().iter().find( + |ty::GeneratorInteriorTypeCause { ty, .. }| { + ty_matches(typeck_results.generator_interior_types.rebind(ty)) + }, + ) + { + // Check to see if any awaited expressions have the target type. + let from_awaited_ty = visitor + .awaits + .into_iter() + .map(|id| hir.expect_expr(id)) + .find(|await_expr| { + let ty = typeck_results.expr_ty_adjusted(&await_expr); + debug!( + "maybe_note_obligation_cause_for_async_await: await_expr={:?}", + await_expr + ); + ty_matches(ty::Binder::dummy(ty)) + }) + .map(|expr| expr.span); + let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause; - interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span)); - interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty)); - }); + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span)); + interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty)); + }; debug!( "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \ @@ -1787,6 +1780,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &obligation.predicate, next_code.unwrap(), &mut Vec::new(), + &mut Default::default(), ); } @@ -1796,6 +1790,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { predicate: &T, cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<&ty::TyS<'tcx>>, + seen_requirements: &mut FxHashSet, ) where T: fmt::Display, { @@ -2010,7 +2005,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.note("shared static variables must have a type that implements `Sync`"); } ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); let ty = parent_trait_ref.skip_binder().self_ty(); if parent_trait_ref.references_error() { err.cancel(); @@ -2025,8 +2020,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = *data.parent_code { - let parent_trait_ref = - self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); let ty = parent_trait_ref.skip_binder().self_ty(); matches!(ty.kind(), ty::Generator(..)) || matches!(ty.kind(), ty::Closure(..)) @@ -2051,18 +2045,44 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &parent_predicate, &data.parent_code, obligated_types, + seen_requirements, ) }); } } ObligationCauseCode::ImplDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let mut parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); + let parent_def_id = parent_trait_ref.def_id(); err.note(&format!( "required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref.print_only_trait_path(), parent_trait_ref.skip_binder().self_ty() )); - let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + + let mut parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + let mut data = data; + let mut count = 0; + seen_requirements.insert(parent_def_id); + while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code { + // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`. + let child_trait_ref = self.resolve_vars_if_possible(child.parent_trait_ref); + let child_def_id = child_trait_ref.def_id(); + if seen_requirements.insert(child_def_id) { + break; + } + count += 1; + data = child; + parent_predicate = child_trait_ref.without_const().to_predicate(tcx); + parent_trait_ref = child_trait_ref; + } + if count > 0 { + err.note(&format!("{} redundant requirements hidden", count)); + err.note(&format!( + "required because of the requirements on the impl of `{}` for `{}`", + parent_trait_ref.print_only_trait_path(), + parent_trait_ref.skip_binder().self_ty() + )); + } // #74711: avoid a stack overflow ensure_sufficient_stack(|| { self.note_obligation_cause_code( @@ -2070,11 +2090,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &parent_predicate, &data.parent_code, obligated_types, + seen_requirements, ) }); } ObligationCauseCode::DerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref); let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); // #74711: avoid a stack overflow ensure_sufficient_stack(|| { @@ -2083,20 +2104,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &parent_predicate, &data.parent_code, obligated_types, + seen_requirements, ) }); } ObligationCauseCode::CompareImplMethodObligation { .. } => { err.note(&format!( - "the requirement `{}` appears on the impl method \ - but not on the corresponding trait method", + "the requirement `{}` appears on the impl method but not on the corresponding \ + trait method", predicate )); } ObligationCauseCode::CompareImplTypeObligation { .. } => { err.note(&format!( - "the requirement `{}` appears on the associated impl type \ - but not on the corresponding associated trait type", + "the requirement `{}` appears on the associated impl type but not on the \ + corresponding associated trait type", predicate )); } @@ -2132,7 +2154,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder>, + trait_ref: ty::Binder>, span: Span, ) { debug!( @@ -2150,13 +2172,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); + let self_ty = self.resolve_vars_if_possible(trait_ref.self_ty()); // Do not check on infer_types to avoid panic in evaluate_obligation. if self_ty.has_infer_types() { return; } - let self_ty = self.tcx.erase_regions(&self_ty); + let self_ty = self.tcx.erase_regions(self_ty); let impls_future = self.tcx.type_implements_trait(( future_trait, @@ -2197,7 +2219,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!( "suggest_await_before_try: normalized_projection_type {:?}", - self.resolve_vars_if_possible(&normalized_ty) + self.resolve_vars_if_possible(normalized_ty) ); let try_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 538c14c6b7..a04f816b0f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -202,7 +202,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { ) { // this helps to reduce duplicate errors, as well as making // debug output much nicer to read and so on. - let obligation = infcx.resolve_vars_if_possible(&obligation); + let obligation = infcx.resolve_vars_if_possible(obligation); debug!(?obligation, "register_predicate_obligation"); @@ -298,7 +298,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { if !change { debug!( "process_predicate: pending obligation {:?} still stalled on {:?}", - self.selcx.infcx().resolve_vars_if_possible(&pending_obligation.obligation), + self.selcx.infcx().resolve_vars_if_possible(pending_obligation.obligation.clone()), pending_obligation.stalled_on ); return ProcessResult::Unchanged; @@ -338,14 +338,14 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { if obligation.predicate.has_infer_types_or_consts() { obligation.predicate = - self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); + self.selcx.infcx().resolve_vars_if_possible(obligation.predicate); } debug!(?obligation, ?obligation.cause, "process_obligation"); let infcx = self.selcx.infcx(); - match obligation.predicate.kind() { + match *obligation.predicate.kind() { ty::PredicateKind::ForAll(binder) => match binder.skip_binder() { // Evaluation will discard candidates using the leak check. // This means we need to pass it the bound version of our @@ -384,9 +384,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { bug!("TypeWellFormedFromEnv is only used for Chalk") } }, - &ty::PredicateKind::Atom(atom) => match atom { - ty::PredicateAtom::Trait(ref data, _) => { - let trait_obligation = obligation.with(Binder::dummy(*data)); + ty::PredicateKind::Atom(atom) => match atom { + ty::PredicateAtom::Trait(data, _) => { + let trait_obligation = obligation.with(Binder::dummy(data)); self.process_trait_obligation( obligation, @@ -639,7 +639,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { debug!( "process_predicate: pending obligation {:?} now stalled on {:?}", - infcx.resolve_vars_if_possible(obligation), + infcx.resolve_vars_if_possible(obligation.clone()), stalled_on ); @@ -684,7 +684,7 @@ fn trait_ref_infer_vars<'a, 'tcx>( ) -> Vec> { selcx .infcx() - .resolve_vars_if_possible(&trait_ref) + .resolve_vars_if_possible(trait_ref) .skip_binder() .substs .iter() diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index e23f5a583b..cedd1aa54b 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -50,7 +50,7 @@ pub fn can_type_implement_copy( let span = tcx.def_span(field.did); let cause = ObligationCause::dummy_with_span(span); let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) { + match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push(field); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c93087a18c..2fb9b3cd5d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -97,13 +97,13 @@ impl Default for SkipLeakCheck { /// The mode that trait queries run in. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum TraitQueryMode { - // Standard/un-canonicalized queries get accurate - // spans etc. passed in and hence can do reasonable - // error reporting on their own. + /// Standard/un-canonicalized queries get accurate + /// spans etc. passed in and hence can do reasonable + /// error reporting on their own. Standard, - // Canonicalized queries get dummy spans and hence - // must generally propagate errors to - // pre-canonicalization callsites. + /// Canonicalized queries get dummy spans and hence + /// must generally propagate errors to + /// pre-canonicalization callsites. Canonical, } @@ -223,7 +223,7 @@ fn do_normalize_predicates<'tcx>( // we move over to lazy normalization *anyway*. let fulfill_cx = FulfillmentContext::new_ignoring_regions(); let predicates = - match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) { + match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) { Ok(predicates) => predicates, Err(errors) => { infcx.report_fulfillment_errors(&errors, None, false); @@ -243,7 +243,7 @@ fn do_normalize_predicates<'tcx>( RegionckMode::default(), ); - let predicates = match infcx.fully_resolve(&predicates) { + let predicates = match infcx.fully_resolve(predicates) { Ok(predicates) => predicates, Err(fixup_err) => { // If we encounter a fixup error, it means that some type @@ -384,7 +384,7 @@ pub fn fully_normalize<'a, 'tcx, T>( mut fulfill_cx: FulfillmentContext<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> Result>> where T: TypeFoldable<'tcx>, @@ -404,7 +404,7 @@ where debug!("fully_normalize: select_all_or_error start"); fulfill_cx.select_all_or_error(infcx)?; debug!("fully_normalize: select_all_or_error complete"); - let resolved_value = infcx.resolve_vars_if_possible(&normalized_value); + let resolved_value = infcx.resolve_vars_if_possible(normalized_value); debug!("fully_normalize: resolved_value={:?}", resolved_value); Ok(resolved_value) } @@ -424,7 +424,7 @@ pub fn impossible_predicates<'tcx>( let mut fulfill_cx = FulfillmentContext::new(); let cause = ObligationCause::dummy(); let Normalized { value: predicates, obligations } = - normalize(&mut selcx, param_env, cause.clone(), &predicates); + normalize(&mut selcx, param_env, cause.clone(), predicates); for obligation in obligations { fulfill_cx.register_predicate_obligation(&infcx, obligation); } @@ -435,7 +435,7 @@ pub fn impossible_predicates<'tcx>( fulfill_cx.select_all_or_error(&infcx).is_err() }); - debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result); + debug!("impossible_predicates = {:?}", result); result } @@ -494,7 +494,7 @@ fn vtable_methods<'tcx>( // erase them if they appear, so that we get the type // at some particular call site. let substs = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs); + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs); // It's possible that the method relies on where-clauses that // do not hold for this particular set of type parameters. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 32e0991733..8b6e30f34f 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -418,11 +418,11 @@ fn virtual_call_violation_for_method<'tcx>( } for (i, &input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { - if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { return Some(MethodViolationCode::ReferencesSelfInput(i)); } } - if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) { + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { return Some(MethodViolationCode::ReferencesSelfOutput); } @@ -446,7 +446,7 @@ fn virtual_call_violation_for_method<'tcx>( } let receiver_ty = - tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0])); + tcx.liberate_late_bound_regions(method.def_id, sig.map_bound(|sig| sig.inputs()[0])); // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. // However, this is already considered object-safe. We allow it as a special case here. @@ -551,8 +551,9 @@ fn object_ty_for_trait<'tcx>( let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - let trait_predicate = - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), + )); let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) .flat_map(|super_trait_ref| { @@ -569,24 +570,19 @@ fn object_ty_for_trait<'tcx>( let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { // We *can* get bound lifetimes here in cases like // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. - // - // binder moved to (*)... - let super_trait_ref = super_trait_ref.skip_binder(); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), - item_def_id: item.def_id, - substs: super_trait_ref.substs, + super_trait_ref.map_bound(|super_trait_ref| { + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), + item_def_id: item.def_id, + substs: super_trait_ref.substs, + }) }) }); - let existential_predicates = - tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); + let existential_predicates = tcx + .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let object_ty = tcx.mk_dynamic( - // (*) ... binder re-introduced here - ty::Binder::bind(existential_predicates), - lifetime, - ); + let object_ty = tcx.mk_dynamic(existential_predicates, lifetime); debug!("object_ty_for_trait: object_ty=`{}`", object_ty); @@ -771,7 +767,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Param(_) => { if t == self.tcx.types.self_param { @@ -812,7 +810,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow { // First check if the type of this constant references `Self`. self.visit_ty(ct.ty)?; @@ -844,7 +842,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<()> { + fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow { if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() { // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 170110a54a..f22b5b9661 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -168,7 +168,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( let infcx = selcx.infcx(); infcx.commit_if_ok(|_snapshot| { let placeholder_predicate = - infcx.replace_bound_vars_with_placeholders(&obligation.predicate); + infcx.replace_bound_vars_with_placeholders(obligation.predicate); let placeholder_obligation = obligation.with(placeholder_predicate); let result = project_and_unify_type(selcx, &placeholder_obligation)?; @@ -232,7 +232,7 @@ pub fn normalize<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, - value: &T, + value: T, ) -> Normalized<'tcx, T> where T: TypeFoldable<'tcx>, @@ -246,7 +246,7 @@ pub fn normalize_to<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, - value: &T, + value: T, obligations: &mut Vec>, ) -> T where @@ -261,7 +261,7 @@ pub fn normalize_with_depth<'a, 'b, 'tcx, T>( param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, depth: usize, - value: &T, + value: T, ) -> Normalized<'tcx, T> where T: TypeFoldable<'tcx>, @@ -277,7 +277,7 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, depth: usize, - value: &T, + value: T, obligations: &mut Vec>, ) -> T where @@ -309,7 +309,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } } - fn fold>(&mut self, value: &T) -> T { + fn fold>(&mut self, value: T) -> T { let value = self.selcx.infcx().resolve_vars_if_possible(value); if !value.has_projections() { value } else { value.fold_with(self) } @@ -365,7 +365,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } } - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { + ty::Projection(data) if !data.has_escaping_bound_vars() => { // This is kind of hacky -- we need to be able to // handle normalization within binders because // otherwise we wind up a need to normalize when doing @@ -381,7 +381,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { let normalized_ty = normalize_projection_type( self.selcx, self.param_env, - *data, + data, self.cause.clone(), self.depth, &mut self.obligations, @@ -474,7 +474,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ) -> Result>, InProgress> { let infcx = selcx.infcx(); - let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); + let projection_ty = infcx.resolve_vars_if_possible(projection_ty); let cache_key = ProjectionCacheKey::new(projection_ty); // FIXME(#20304) For now, I am caching here, which is good, but it @@ -569,7 +569,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( depth + 1, &mut projected_obligations, ); - let normalized_ty = normalizer.fold(&projected_ty); + let normalized_ty = normalizer.fold(projected_ty); debug!(?normalized_ty, ?depth); @@ -736,14 +736,9 @@ fn project_type<'cx, 'tcx>( if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); - match selcx.query_mode() { - super::TraitQueryMode::Standard => { - selcx.infcx().report_overflow_error(&obligation, true); - } - super::TraitQueryMode::Canonical => { - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); - } - } + // This should really be an immediate error, but some existing code + // relies on being able to recover from this. + return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); } let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); @@ -960,7 +955,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { @@ -1006,7 +1001,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // type. // // NOTE: This should be kept in sync with the similar code in - // `rustc_ty::instance::resolve_associated_item()`. + // `rustc_ty_utils::instance::resolve_associated_item()`. let node_item = assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) .map_err(|ErrorReported| ())?; @@ -1022,8 +1017,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( if obligation.param_env.reveal() == Reveal::All { // NOTE(eddyb) inference variables can resolve to parameters, so // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = - selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); + let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(poly_trait_ref); !poly_trait_ref.still_further_specializable() } else { debug!( @@ -1201,7 +1195,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &gen_sig, + gen_sig, ); debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate"); @@ -1257,7 +1251,9 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>( ty: self_ty.discriminant_ty(tcx), }; - confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false) + // We get here from `poly_project_and_unify_type` which replaces bound vars + // with placeholders, so dummy is okay here. + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( @@ -1272,7 +1268,7 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &sig, + sig, ); confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) @@ -1291,7 +1287,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &closure_sig, + closure_sig, ); debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); @@ -1345,7 +1341,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars( cause.span, LateBoundRegionConversionTime::HigherRankedType, - &poly_cache_entry, + poly_cache_entry, ); let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); @@ -1358,7 +1354,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &cache_trait_ref, + cache_trait_ref, &mut nested_obligations, ) }) @@ -1454,7 +1450,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &predicate, + predicate, nested, ); nested.push(Obligation::with_depth( @@ -1535,7 +1531,7 @@ impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> { // from a specific call to `opt_normalize_projection_type` - if // there's no precise match, the original cache entry is "stranded" // anyway. - infcx.resolve_vars_if_possible(&predicate.projection_ty), + infcx.resolve_vars_if_possible(predicate.projection_ty), ) }) } diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 8212823a6d..f05582f061 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -40,10 +40,10 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { } let mut orig_values = OriginalQueryValues::default(); - let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); + let c_ty = self.infcx.canonicalize_query(self.param_env.and(ty), &mut orig_values); let span = self.cause.span; debug!("c_ty = {:?}", c_ty); - if let Ok(result) = &tcx.dropck_outlives(c_ty) { + if let Ok(result) = tcx.dropck_outlives(c_ty) { if result.is_proven() { if let Ok(InferOk { value, obligations }) = self.infcx.instantiate_query_response_and_region_obligations( @@ -53,7 +53,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { result, ) { - let ty = self.infcx.resolve_vars_if_possible(&ty); + let ty = self.infcx.resolve_vars_if_possible(ty); let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); return InferOk { value: kinds, obligations }; } diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 0569f6217d..b83a4cd1e5 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -65,7 +65,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { ) -> Result { let mut _orig_values = OriginalQueryValues::default(); let c_pred = self - .canonicalize_query(&obligation.param_env.and(obligation.predicate), &mut _orig_values); + .canonicalize_query(obligation.param_env.and(obligation.predicate), &mut _orig_values); // Run canonical query. If overflow occurs, rerun from scratch but this time // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 42a598ce3a..33cd509cbb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -19,7 +19,7 @@ use super::NoSolution; pub use rustc_middle::traits::query::NormalizationResult; pub trait AtExt<'tcx> { - fn normalize(&self, value: &T) -> Result, NoSolution> + fn normalize(&self, value: T) -> Result, NoSolution> where T: TypeFoldable<'tcx>; } @@ -38,7 +38,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// normalizing, but for now should be used only when we actually /// know that normalization will succeed, since error reporting /// and other details are still "under development". - fn normalize(&self, value: &T) -> Result, NoSolution> + fn normalize(&self, value: T) -> Result, NoSolution> where T: TypeFoldable<'tcx>, { @@ -49,7 +49,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { self.param_env, ); if !value.has_projections() { - return Ok(Normalized { value: value.clone(), obligations: vec![] }); + return Ok(Normalized { value, obligations: vec![] }); } let mut normalizer = QueryNormalizer { @@ -97,6 +97,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.infcx.tcx } + #[instrument(skip(self))] fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if !ty.has_projections() { return ty; @@ -145,7 +146,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } } - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { + ty::Projection(data) if !data.has_escaping_bound_vars() => { // This is kind of hacky -- we need to be able to // handle normalization within binders because // otherwise we wind up a need to normalize when doing @@ -165,7 +166,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // so we cannot canonicalize it. let c_data = self .infcx - .canonicalize_hr_query_hack(&self.param_env.and(*data), &mut orig_values); + .canonicalize_hr_query_hack(self.param_env.and(data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); match tcx.normalize_projection_ty(c_data) { @@ -180,7 +181,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.cause, self.param_env, &orig_values, - &result, + result, ) { Ok(InferOk { value: result, obligations }) => { debug!("QueryNormalizer: result = {:#?}", result); diff --git a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs index a42409515d..f5fa52c915 100644 --- a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs @@ -51,7 +51,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { debug!("implied_outlives_bounds(ty = {:?})", ty); let mut orig_values = OriginalQueryValues::default(); - let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); + let key = self.canonicalize_query(param_env.and(ty), &mut orig_values); let result = match self.tcx.implied_outlives_bounds(key) { Ok(r) => r, Err(NoSolution) => { @@ -68,7 +68,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { &ObligationCause::misc(span, body_id), param_env, &orig_values, - &result, + result, ); debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); let result = match result { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 915e8ae4a7..1688539165 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -96,7 +96,7 @@ fn scrape_region_constraints<'tcx, R>( region_obligations .iter() .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)) - .map(|(ty, r)| (infcx.resolve_vars_if_possible(&ty), r)), + .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)), ®ion_constraint_data, ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index ed6c6d0cc0..130ffa1a33 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -81,16 +81,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { // like the subtype query, which go awry around // `'static` otherwise. let mut canonical_var_values = OriginalQueryValues::default(); - let canonical_self = - infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); + let old_param_env = query_key.param_env; + let canonical_self = infcx.canonicalize_hr_query_hack(query_key, &mut canonical_var_values); let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; - let param_env = query_key.param_env; - let InferOk { value, obligations } = infcx .instantiate_nll_query_response_and_region_obligations( &ObligationCause::dummy(), - param_env, + old_param_env, &canonical_var_values, canonical_result, output_query_region_constraints, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index b0bfb4ad17..ca3369b8f1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -229,7 +229,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: obligation.param_env, cause: obligation.cause.clone(), recursion_depth: obligation.recursion_depth, - predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate), + predicate: self.infcx().resolve_vars_if_possible(obligation.predicate), }; if obligation.predicate.skip_binder().self_ty().is_ty_var() { @@ -350,19 +350,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Micro-optimization: filter out predicates relating to different traits. let matching_bounds = - all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + all_bounds.filter(|p| p.value.def_id() == stack.obligation.predicate.def_id()); // Keep only those bounds which may apply, and propagate overflow if it occurs. - let mut param_candidates = vec![]; for bound in matching_bounds { - let wc = self.evaluate_where_clause(stack, bound)?; + let wc = self.evaluate_where_clause(stack, bound.value)?; if wc.may_apply() { - param_candidates.push(ParamCandidate(bound)); + candidates.vec.push(ParamCandidate(bound)); } } - candidates.vec.extend(param_candidates); - Ok(()) } @@ -607,7 +604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The code below doesn't care about regions, and the // self-ty here doesn't escape this probe, so just erase // any LBR. - let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); + let self_ty = self.tcx().erase_late_bound_regions(obligation.self_ty()); let poly_trait_ref = match self_ty.kind() { ty::Dynamic(ref data, ..) => { if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { @@ -642,9 +639,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?poly_trait_ref, "assemble_candidates_from_object_ty"); - let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); + self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); // Count only those upcast versions that match the trait-ref // we are looking for. Specifically, do not only check for the diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 9cfb744dc0..030c29171a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,6 +8,7 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; +use rustc_hir::Constness; use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; @@ -55,8 +56,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param); - Ok(ImplSource::Param(obligations)) + let obligations = self.confirm_param_candidate(obligation, param.value); + Ok(ImplSource::Param(obligations, param.constness)) } ImplCandidate(impl_def_id) => { @@ -70,7 +71,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ProjectionCandidate(idx) => { let obligations = self.confirm_projection_candidate(obligation, idx)?; - Ok(ImplSource::Param(obligations)) + // FIXME(jschievink): constness + Ok(ImplSource::Param(obligations, Constness::NotConst)) } ObjectCandidate(idx) => { @@ -106,7 +108,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This indicates something like `Trait + Send: Send`. In this case, we know that // this holds because that's what the object type is telling us, and there's really // no additional obligations to prove and no types in particular to unify, etc. - Ok(ImplSource::Param(Vec::new())) + Ok(ImplSource::Param(Vec::new(), Constness::NotConst)) } BuiltinUnsizeCandidate => { @@ -126,7 +128,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); let placeholder_trait_predicate = - self.infcx().replace_bound_vars_with_placeholders(&trait_predicate); + self.infcx().replace_bound_vars_with_placeholders(trait_predicate); let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let (def_id, substs) = match *placeholder_self_ty.kind() { ty::Projection(proj) => (proj.item_def_id, proj.substs), @@ -144,14 +146,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &candidate, + candidate, &mut obligations, ); obligations.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate) + .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -163,7 +165,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &predicate, + predicate, &mut obligations, ); obligations.push(Obligation::with_depth( @@ -257,10 +259,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> ImplSourceAutoImplData> { debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate"); - let types = obligation.predicate.map_bound(|inner| { - let self_ty = self.infcx.shallow_resolve(inner.self_ty()); - self.constituent_types_for_ty(self_ty) - }); + let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); + let types = self.constituent_types_for_ty(self_ty); self.vtable_auto_impl(obligation, trait_def_id, types) } @@ -285,8 +285,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_obligations: Vec> = self.infcx.commit_unconditionally(|_| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = - self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); + let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); let cause = obligation.derived_cause(ImplDerivedObligation); self.impl_or_trait_obligations( cause, @@ -370,29 +369,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); - let trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate); + let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); - let data = match self_ty.kind() { - ty::Dynamic(data, ..) => { - self.infcx - .replace_bound_vars_with_fresh_vars( - obligation.cause.span, - HigherRankedType, - data, - ) - .0 - } + let data = match *self_ty.kind() { + ty::Dynamic(data, ..) => data, _ => span_bug!(obligation.cause.span, "object candidate with non-object"), }; - let object_trait_ref = data - .principal() - .unwrap_or_else(|| { - span_bug!(obligation.cause.span, "object candidate with no principal") - }) - .with_self_ty(self.tcx(), self_ty); + let object_trait_ref = data.principal().unwrap_or_else(|| { + span_bug!(obligation.cause.span, "object candidate with no principal") + }); + let object_trait_ref = self + .infcx + .replace_bound_vars_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + object_trait_ref, + ) + .0; + let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); let mut nested = vec![]; @@ -416,7 +412,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &unnormalized_upcast_trait_ref, + unnormalized_upcast_trait_ref, &mut nested, ); @@ -442,12 +438,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &super_trait, + super_trait, &mut nested, ); nested.push(Obligation::new( obligation.cause.clone(), - obligation.param_env.clone(), + obligation.param_env, normalized_super_trait, )); } @@ -480,12 +476,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &subst_bound, + subst_bound, &mut nested, ); nested.push(Obligation::new( obligation.cause.clone(), - obligation.param_env.clone(), + obligation.param_env, normalized_bound, )); } @@ -520,7 +516,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_ref, + trait_ref, ) }); @@ -541,8 +537,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate"); self.infcx.commit_unconditionally(|_| { - let predicate = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; @@ -584,7 +579,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_ref, + trait_ref, ) }); @@ -627,7 +622,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_ref, + trait_ref, ) }); @@ -712,15 +707,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { // See `assemble_candidates_for_unsizing` for more info. - let existential_predicates = data_a.map_bound(|data_a| { - let iter = data_a - .principal() - .map(ty::ExistentialPredicate::Trait) - .into_iter() - .chain(data_a.projection_bounds().map(ty::ExistentialPredicate::Projection)) - .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); - tcx.mk_existential_predicates(iter) - }); + let iter = data_a + .principal() + .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain( + data_b + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ); + let existential_predicates = tcx.mk_poly_existential_predicates(iter); let source_trait = tcx.mk_dynamic(existential_predicates, r_b); // Require that the traits involved in this upcast are **equal**; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ea5c12a989..f1c86eab09 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -31,6 +31,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::Constness; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; @@ -290,10 +291,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - pub(super) fn query_mode(&self) -> TraitQueryMode { - self.query_mode - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -836,11 +833,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// - it also appears in the backtrace at some position `X`, /// - all the predicates at positions `X..` between `X` and the top are /// also defaulted traits. - pub fn coinductive_match(&mut self, cycle: I) -> bool + pub fn coinductive_match(&mut self, mut cycle: I) -> bool where I: Iterator>, { - let mut cycle = cycle; cycle.all(|predicate| self.coinductive_predicate(predicate)) } @@ -1023,7 +1019,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let obligation = &stack.obligation; - let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); // Okay to skip binder because of the nature of the // trait-ref-is-knowable check, which does not care about @@ -1142,9 +1138,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> smallvec::SmallVec<[usize; 2]> { - let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); + self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); debug!( ?placeholder_trait_predicate, "match_projection_obligation_against_definition_bounds" @@ -1224,7 +1220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &trait_bound, + trait_bound, ) }); self.infcx @@ -1270,17 +1266,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &data.map_bound_ref(|data| data.projection_ty), + data.map_bound(|data| data.projection_ty), &mut nested_obligations, ) }) } else { - data.map_bound_ref(|data| data.projection_ty) + data.map_bound(|data| data.projection_ty) }; // FIXME(generic_associated_types): Compare the whole projections let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx())); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation_poly_trait_ref, data_poly_trait_ref) @@ -1339,7 +1335,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true, (_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false, - (ParamCandidate(..), ParamCandidate(..)) => false, + (ParamCandidate(other), ParamCandidate(victim)) => { + if other.value == victim.value && victim.constness == Constness::NotConst { + // Drop otherwise equivalent non-const candidates in favor of const candidates. + true + } else { + false + } + } // Global bounds from the where clause should be ignored // here (see issue #50825). Otherwise, we have a where @@ -1358,11 +1361,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitAliasCandidate(..) | ObjectCandidate(_) | ProjectionCandidate(_), - ) => !is_global(cand), + ) => !is_global(&cand.value), (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(cand) + is_global(&cand.value) } ( ImplCandidate(_) @@ -1377,7 +1380,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(cand) && other.evaluation.must_apply_modulo_regions() + is_global(&cand.value) && other.evaluation.must_apply_modulo_regions() } (ProjectionCandidate(i), ProjectionCandidate(j)) @@ -1645,8 +1648,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` - fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { - match *t.kind() { + fn constituent_types_for_ty(&self, t: ty::Binder>) -> ty::Binder>> { + match *t.skip_binder().kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -1657,7 +1660,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never - | ty::Char => Vec::new(), + | ty::Char => ty::Binder::dummy(Vec::new()), ty::Placeholder(..) | ty::Dynamic(..) @@ -1670,44 +1673,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - vec![element_ty] + t.rebind(vec![element_ty]) } - ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], + ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]), ty::Tuple(ref tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - tys.iter().map(|k| k.expect_ty()).collect() + t.rebind(tys.iter().map(|k| k.expect_ty()).collect()) } ty::Closure(_, ref substs) => { let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); - vec![ty] + t.rebind(vec![ty]) } ty::Generator(_, ref substs, _) => { let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); let witness = substs.as_generator().witness(); - vec![ty].into_iter().chain(iter::once(witness)).collect() + t.rebind(vec![ty].into_iter().chain(iter::once(witness)).collect()) } ty::GeneratorWitness(types) => { - // This is sound because no regions in the witness can refer to - // the binder outside the witness. So we'll effectivly reuse - // the implicit binder around the witness. - types.skip_binder().to_vec() + debug_assert!(!types.has_escaping_bound_vars()); + types.map_bound(|types| types.to_vec()) } // For `PhantomData`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), + ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()), - ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(), + ty::Adt(def, substs) => { + t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect()) + } ty::Opaque(def_id, substs) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] + t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)]) } } } @@ -1735,13 +1738,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy` types + .as_ref() .skip_binder() // binder moved -\ .iter() .flat_map(|ty| { - let ty: ty::Binder> = ty::Binder::bind(ty); // <----/ + let ty: ty::Binder> = types.rebind(ty); // <----/ self.infcx.commit_unconditionally(|_| { - let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(&ty); + let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -1749,7 +1753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env, cause.clone(), recursion_depth, - &placeholder_ty, + placeholder_ty, ) }); let placeholder_obligation = predicate_for_trait_def( @@ -1811,7 +1815,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let placeholder_obligation = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + self.infcx().replace_bound_vars_with_placeholders(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); @@ -1825,7 +1829,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - &impl_trait_ref, + impl_trait_ref, ) }); @@ -2032,7 +2036,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env, cause.clone(), recursion_depth, - &predicate.subst(tcx, substs), + predicate.subst(tcx, substs), &mut obligations, ); obligations.push(Obligation { @@ -2368,13 +2372,9 @@ impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> { type Item = &'o TraitObligationStack<'o, 'tcx>; fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - match self.head { - Some(o) => { - *self = o.previous; - Some(o) - } - None => None, - } + let o = self.head?; + *self = o.previous; + Some(o) } } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 4d81a3baa0..0133a961c1 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -158,7 +158,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, FulfillmentContext::new(), ObligationCause::dummy(), penv, - &impl1_trait_ref, + impl1_trait_ref, ) { Ok(impl1_trait_ref) => impl1_trait_ref, Err(err) => { @@ -247,7 +247,7 @@ fn fulfill_implication<'a, 'tcx>( // Now resolve the *substitution* we built for the target earlier, replacing // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_vars_if_possible(&target_substs)) + Ok(infcx.resolve_vars_if_possible(target_substs)) } } }) @@ -498,8 +498,8 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option for (p, _) in predicates { if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { - if Some(poly_trait_ref.def_id()) == sized_trait { - types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder()); + if Some(poly_trait_ref.value.def_id()) == sized_trait { + types_without_default_bounds.remove(poly_trait_ref.value.self_ty().skip_binder()); continue; } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index ce0d3ef8a6..3d20a8d5cf 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -55,9 +55,7 @@ pub fn search_for_structural_match_violation<'tcx>( ) -> Option> { // FIXME: we should instead pass in an `infcx` from the outside. tcx.infer_ctxt().enter(|infcx| { - let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() }; - ty.visit_with(&mut search); - search.found + ty.visit_with(&mut Search { infcx, span, seen: FxHashSet::default() }).break_value() }) } @@ -116,9 +114,6 @@ struct Search<'a, 'tcx> { infcx: InferCtxt<'a, 'tcx>, - /// Records first ADT that does not implement a structural-match trait. - found: Option>, - /// Tracks ADTs previously encountered during search, so that /// we will not recur on them again. seen: FxHashSet, @@ -135,38 +130,33 @@ impl Search<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = NonStructuralMatchTy<'tcx>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { debug!("Search visiting ty: {:?}", ty); let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { - self.found = Some(NonStructuralMatchTy::Param); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Param); } ty::Dynamic(..) => { - self.found = Some(NonStructuralMatchTy::Dynamic); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Dynamic); } ty::Foreign(_) => { - self.found = Some(NonStructuralMatchTy::Foreign); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Foreign); } ty::Opaque(..) => { - self.found = Some(NonStructuralMatchTy::Opaque); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Opaque); } ty::Projection(..) => { - self.found = Some(NonStructuralMatchTy::Projection); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Projection); } ty::Generator(..) | ty::GeneratorWitness(..) => { - self.found = Some(NonStructuralMatchTy::Generator); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Generator); } ty::Closure(..) => { - self.found = Some(NonStructuralMatchTy::Closure); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Closure); } ty::RawPtr(..) => { // structural-match ignores substructure of @@ -206,8 +196,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. - ty.super_visit_with(self); - return ControlFlow::CONTINUE; + return ty.super_visit_with(self); } ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { bug!("unexpected type during structural-match checking: {:?}", ty); @@ -227,8 +216,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { if !self.type_marked_structural(ty) { debug!("Search found ty: {:?}", ty); - self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); - return ControlFlow::BREAK; + return ControlFlow::Break(NonStructuralMatchTy::Adt(&adt_def)); } // structural-match does not care about the @@ -244,20 +232,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // even though we skip super_visit_with, we must recur on // fields of ADT. let tcx = self.tcx(); - for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) { + adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| { let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); - - if ty.visit_with(self).is_break() { - // found an ADT without structural-match; halt visiting! - assert!(self.found.is_some()); - return ControlFlow::BREAK; - } - } - - // Even though we do not want to recur on substs, we do - // want our caller to continue its own search. - ControlFlow::CONTINUE + ty.visit_with(self) + }) } } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index f626bb0b7e..8888ea2c84 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -6,7 +6,7 @@ use smallvec::SmallVec; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; pub use rustc_infer::traits::util::*; @@ -125,7 +125,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { pred.subst_supertrait(tcx, &trait_ref) .to_opt_poly_trait_ref() - .map(|trait_ref| item.clone_and_push(trait_ref, *span)) + .map(|trait_ref| item.clone_and_push(trait_ref.value, *span)) }); debug!("expand_trait_aliases: items={:?}", items.clone()); @@ -182,7 +182,7 @@ impl Iterator for SupertraitDefIds<'tcx> { .predicates .iter() .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref()) - .map(|trait_ref| trait_ref.def_id()) + .map(|trait_ref| trait_ref.value.def_id()) .filter(|&super_def_id| visited.insert(super_def_id)), ); Some(def_id) @@ -205,12 +205,12 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>( let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref); + super::normalize(selcx, param_env, ObligationCause::dummy(), impl_trait_ref); let predicates = selcx.tcx().predicates_of(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); + super::normalize(selcx, param_env, ObligationCause::dummy(), predicates); let impl_obligations = predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates); @@ -333,11 +333,12 @@ pub fn closure_trait_ref_and_return_type( TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), }; + debug_assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), }; - ty::Binder::bind((trait_ref, sig.skip_binder().output())) + sig.map_bound(|sig| (trait_ref, sig.output())) } pub fn generator_trait_ref_and_outputs( @@ -346,11 +347,12 @@ pub fn generator_trait_ref_and_outputs( self_ty: Ty<'tcx>, sig: ty::PolyGenSig<'tcx>, ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { + debug_assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]), }; - ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) + sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty)) } pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 496dff6c5b..3f58fd72f4 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { param_env, cause.clone(), self.recursion_depth, - &obligation.predicate, + obligation.predicate, &mut obligations, ); obligation.predicate = normalized_predicate; @@ -294,7 +294,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let mut cause = cause.clone(); if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() { let derived_cause = traits::DerivedObligationCause { - parent_trait_ref, + parent_trait_ref: parent_trait_ref.value, parent_code: Rc::new(obligation.cause.code.clone()), }; cause.make_mut().code = @@ -706,7 +706,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn from_object_ty( &mut self, ty: Ty<'tcx>, - data: ty::Binder<&'tcx ty::List>>, + data: &'tcx ty::List>>, region: ty::Region<'tcx>, ) { // Imagine a type like this: @@ -769,7 +769,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// `infer::required_region_bounds`, see that for more information. pub fn object_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, - existential_predicates: ty::Binder<&'tcx ty::List>>, + existential_predicates: &'tcx ty::List>>, ) -> Vec> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index c5a46b1003..1893d74335 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -227,7 +227,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( &self.interner, self.interner.tcx, - &sig.inputs_and_output().subst(self.interner.tcx, bound_vars), + sig.inputs_and_output().subst(self.interner.tcx, bound_vars), ); let argument_types = inputs_and_output[..inputs_and_output.len() - 1] @@ -461,7 +461,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t ) -> Arc>> { let bound_vars = ty::fold::shift_vars( self.interner.tcx, - &bound_vars_for_item(self.interner.tcx, opaque_ty_id.0), + bound_vars_for_item(self.interner.tcx, opaque_ty_id.0), 1, ); let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars); @@ -648,7 +648,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t /// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked /// var bound at index `0`. For types, we use a `BoundVar` index equal to -/// the type parameter index. For regions, we use the `BoundRegion::BrNamed` +/// the type parameter index. For regions, we use the `BoundRegionKind::BrNamed` /// variant (which has a `DefId`). fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { InternalSubsts::for_item(tcx, def_id, |param, substs| match param.kind { @@ -662,12 +662,10 @@ fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { )) .into(), - ty::GenericParamDefKind::Lifetime => tcx - .mk_region(ty::RegionKind::ReLateBound( - ty::INNERMOST, - ty::BoundRegion::BrAnon(substs.len() as u32), - )) - .into(), + ty::GenericParamDefKind::Lifetime => { + let br = ty::BoundRegion { kind: ty::BrAnon(substs.len() as u32) }; + tcx.mk_region(ty::RegionKind::ReLateBound(ty::INNERMOST, br)).into() + } ty::GenericParamDefKind::Const => tcx .mk_const(ty::Const { diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index c4e2c7f839..8aa68e533a 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -35,9 +35,7 @@ use rustc_ast::ast; use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{ - self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor, -}; +use rustc_middle::ty::{self, Binder, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::def_id::DefId; use chalk_ir::{FnSig, ForeignDefId}; @@ -86,7 +84,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { @@ -141,7 +139,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi let (predicate, binders, _named_regions) = collect_bound_vars( interner, interner.tcx, - &self.bound_atom_with_opt_escaping(interner.tcx), + self.bound_atom_with_opt_escaping(interner.tcx), ); let value = match predicate { @@ -293,7 +291,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { } ty::FnPtr(sig) => { let (inputs_and_outputs, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output()); + collect_bound_vars(interner, interner.tcx, sig.inputs_and_output()); chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders: binders.len(interner), sig: sig.lower_into(interner), @@ -444,15 +442,15 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t ReEarlyBound(_) => { panic!("Should have already been substituted."); } - ReLateBound(db, br) => match br { - ty::BoundRegion::BrAnon(var) => { + ReLateBound(db, br) => match br.kind { + ty::BoundRegionKind::BrAnon(var) => { chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( chalk_ir::DebruijnIndex::new(db.as_u32()), - *var as usize, + var as usize, )) .intern(interner) } - ty::BoundRegion::BrNamed(_def_id, _name) => unimplemented!(), + ty::BoundRegionKind::BrNamed(_def_id, _name) => unimplemented!(), ty::BrEnv => unimplemented!(), }, ReFree(_) => unimplemented!(), @@ -477,13 +475,13 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime ty::RegionKind::ReLateBound( ty::DebruijnIndex::from_u32(var.debruijn.depth()), - ty::BoundRegion::BrAnon(var.index as u32), + ty::BoundRegion { kind: ty::BrAnon(var.index as u32) }, ), chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), chalk_ir::LifetimeData::Placeholder(p) => { ty::RegionKind::RePlaceholder(ty::Placeholder { universe: ty::UniverseIndex::from_usize(p.ui.counter), - name: ty::BoundRegion::BrAnon(p.idx as u32), + name: ty::BoundRegionKind::BrAnon(p.idx as u32), }) } chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic, @@ -578,7 +576,7 @@ impl<'tcx> LowerInto<'tcx, Option { @@ -615,7 +613,7 @@ impl<'tcx> LowerInto<'tcx, Option LowerInto<'tcx, chalk_ir::Binders>>> - for Binder<&'tcx ty::List>> + for &'tcx ty::List>> { fn lower_into( self, @@ -627,48 +625,53 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders>]> // This means that any variables that are escaping `self` need to be // shifted in by one so that they are still escaping. - let shifted_predicates = ty::fold::shift_vars(interner.tcx, &self, 1); + let predicates = ty::fold::shift_vars(interner.tcx, self, 1); - let (predicates, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &shifted_predicates); let self_ty = interner.tcx.mk_ty(ty::Bound( // This is going to be wrapped in a binder ty::DebruijnIndex::from_usize(1), ty::BoundTy { var: ty::BoundVar::from_usize(0), kind: ty::BoundTyKind::Anon }, )); - let where_clauses = predicates.into_iter().map(|predicate| match predicate { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { - chalk_ir::Binders::new( + let where_clauses = predicates.into_iter().map(|predicate| { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, predicate); + match predicate { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { + chalk_ir::Binders::new( + binders.clone(), + chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { + trait_id: chalk_ir::TraitId(def_id), + substitution: interner + .tcx + .mk_substs_trait(self_ty, substs) + .lower_into(interner), + }), + ) + } + ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new( + binders.clone(), + chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { + alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { + associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id), + substitution: interner + .tcx + .mk_substs_trait(self_ty, predicate.substs) + .lower_into(interner), + }), + ty: predicate.ty.lower_into(interner), + }), + ), + ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( binders.clone(), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), substitution: interner .tcx - .mk_substs_trait(self_ty, substs) + .mk_substs_trait(self_ty, &[]) .lower_into(interner), }), - ) + ), } - ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { - alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id), - substitution: interner - .tcx - .mk_substs_trait(self_ty, predicate.substs) - .lower_into(interner), - }), - ty: predicate.ty.lower_into(interner), - }), - ), - ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { - trait_id: chalk_ir::TraitId(def_id), - substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner), - }), - ), }); // Binder for the bound variable representing the concrete underlying type. @@ -707,7 +710,7 @@ impl<'tcx> LowerInto<'tcx, Option Some(chalk_ir::Binders::new( @@ -800,7 +803,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound } /// To collect bound vars, we have to do two passes. In the first pass, we -/// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then +/// collect all `BoundRegionKind`s and `ty::Bound`s. In the second pass, we then /// replace `BrNamed` into `BrAnon`. The two separate passes are important, /// since we can only replace `BrNamed` with `BrAnon`s with indices *after* all /// "real" `BrAnon`s. @@ -808,10 +811,10 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound /// It's important to note that because of prior substitution, we may have /// late-bound regions, even outside of fn contexts, since this is the best way /// to prep types for chalk lowering. -crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( +crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>( interner: &RustInterner<'tcx>, tcx: TyCtxt<'tcx>, - ty: &'a Binder, + ty: Binder, ) -> (T, chalk_ir::VariableKinds>, BTreeMap) { let mut bound_vars_collector = BoundVarsCollector::new(); ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); @@ -824,7 +827,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( .collect(); let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters); - let new_ty = ty.as_ref().skip_binder().fold_with(&mut bound_var_substitutor); + let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor); for var in named_parameters.values() { parameters.insert(*var, chalk_ir::VariableKind::Lifetime); @@ -833,7 +836,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( (0..parameters.len()).for_each(|i| { parameters .get(&(i as u32)) - .or_else(|| bug!("Skipped bound var index: ty={:?}, parameters={:?}", ty, parameters)); + .or_else(|| bug!("Skipped bound var index: parameters={:?}", parameters)); }); let binders = @@ -859,14 +862,14 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<()> { + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { match self.parameters.entry(bound_ty.var.as_u32()) { @@ -886,16 +889,16 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br { - ty::BoundRegion::BrNamed(def_id, _name) => { - if self.named_parameters.iter().find(|d| *d == def_id).is_none() { - self.named_parameters.push(*def_id); + ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { + ty::BoundRegionKind::BrNamed(def_id, _name) => { + if self.named_parameters.iter().find(|d| **d == def_id).is_none() { + self.named_parameters.push(def_id); } } - ty::BoundRegion::BrAnon(var) => match self.parameters.entry(*var) { + ty::BoundRegionKind::BrAnon(var) => match self.parameters.entry(var) { Entry::Vacant(entry) => { entry.insert(chalk_ir::VariableKind::Lifetime); } @@ -921,7 +924,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } } -/// This is used to replace `BoundRegion::BrNamed` with `BoundRegion::BrAnon`. +/// This is used to replace `BoundRegionKind::BrNamed` with `BoundRegionKind::BrAnon`. /// Note: we assume that we will always have room for more bound vars. (i.e. we /// won't ever hit the `u32` limit in `BrAnon`s). struct NamedBoundVarSubstitutor<'a, 'tcx> { @@ -941,7 +944,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { self.tcx } - fn fold_binder>(&mut self, t: &Binder) -> Binder { + fn fold_binder>(&mut self, t: Binder) -> Binder { self.binder_index.shift_in(1); let result = t.super_fold_with(self); self.binder_index.shift_out(1); @@ -950,20 +953,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br { - ty::BoundRegion::BrNamed(def_id, _name) => { - match self.named_parameters.get(def_id) { - Some(idx) => { - return self.tcx.mk_region(RegionKind::ReLateBound( - *index, - BoundRegion::BrAnon(*idx), - )); - } - None => panic!("Missing `BrNamed`."), + ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { + ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { + Some(idx) => { + let new_br = ty::BoundRegion { kind: ty::BrAnon(*idx) }; + return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)); } - } + None => panic!("Missing `BrNamed`."), + }, ty::BrEnv => unimplemented!(), - ty::BoundRegion::BrAnon(_) => {} + ty::BrAnon(_) => {} }, _ => (), }; @@ -1001,7 +1000,7 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { self.tcx } - fn fold_binder>(&mut self, t: &Binder) -> Binder { + fn fold_binder>(&mut self, t: Binder) -> Binder { self.binder_index.shift_in(1); let result = t.super_fold_with(self); self.binder_index.shift_out(1); @@ -1039,17 +1038,15 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { // FIXME(chalk) - jackh726 - this currently isn't hit in any tests. // This covers any region variables in a goal, right? ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) { - Some(idx) => self.tcx.mk_region(RegionKind::ReLateBound( - self.binder_index, - BoundRegion::BrAnon(*idx), - )), + Some(idx) => { + let br = ty::BoundRegion { kind: ty::BrAnon(*idx) }; + self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) + } None => { let idx = self.named_regions.len() as u32; + let br = ty::BoundRegion { kind: ty::BrAnon(idx) }; self.named_regions.insert(_re.def_id, idx); - self.tcx.mk_region(RegionKind::ReLateBound( - self.binder_index, - BoundRegion::BrAnon(idx), - )) + self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) } }, @@ -1076,7 +1073,7 @@ impl PlaceholdersCollector { } impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Placeholder(p) if p.universe == self.universe_index => { self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); @@ -1088,10 +1085,10 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { match r { ty::RePlaceholder(p) if p.universe == self.universe_index => { - if let ty::BoundRegion::BrAnon(anon) = p.name { + if let ty::BoundRegionKind::BrAnon(anon) = p.name { self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); } } diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index b117e28875..f3a55fec9e 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -44,7 +44,7 @@ crate fn evaluate_goal<'tcx>( let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { universe: ty::UniverseIndex::ROOT, - name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), + name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), })); let mut params_substitutor = diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 6cffa6d02a..2827163d85 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -106,7 +106,7 @@ fn dropck_outlives<'tcx>( // do not themselves define a destructor", more or less. We have // to push them onto the stack to be expanded. for ty in constraints.dtorck_types.drain(..) { - match infcx.at(&cause, param_env).normalize(&ty) { + match infcx.at(&cause, param_env).normalize(ty) { Ok(Normalized { value: ty, obligations }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index c44fd1d585..97017fbf2e 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -115,7 +115,7 @@ fn compute_implied_outlives_bounds<'tcx>( } ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = infcx.resolve_vars_if_possible(&ty_a); + let ty_a = infcx.resolve_vars_if_possible(ty_a); let mut components = smallvec![]; tcx.push_outlives_components(ty_a, &mut components); implied_bounds_from_components(r_b, components) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 3e7c9ac62e..4841e4286a 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; +use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable}; use rustc_trait_selection::traits::query::normalize::AtExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; use std::sync::atomic::Ordering; @@ -21,7 +21,7 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>( tcx.sess.perf_stats.normalize_generic_arg_after_erasing_regions.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::dummy(); - match infcx.at(&cause, param_env).normalize(&value) { + match infcx.at(&cause, param_env).normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { // We don't care about the `obligations`; they are // always only region relations, and we are about to @@ -31,8 +31,14 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>( None, ); - let normalized_value = infcx.resolve_vars_if_possible(&normalized_value); - infcx.tcx.erase_regions(&normalized_value) + let resolved_value = infcx.resolve_vars_if_possible(normalized_value); + // It's unclear when `resolve_vars` would have an effect in a + // fresh `InferCtxt`. If this assert does trigger, it will give + // us a test case. + debug_assert_eq!(normalized_value, resolved_value); + let erased = infcx.tcx.erase_regions(resolved_value); + debug_assert!(!erased.needs_infer(), "{:?}", erased); + erased } Err(NoSolution) => bug!("could not fully normalize `{:?}`", value), } diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 139ed6dcd3..0addde5c44 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -70,7 +70,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { DUMMY_SP, hir::CRATE_HIR_ID, self.param_env, - &value, + value, ) .into_value_registering_obligations(self.infcx, self.fulfill_cx) } @@ -184,7 +184,7 @@ where { let (param_env, Normalize { value }) = key.into_parts(); let Normalized { value, obligations } = - infcx.at(&ObligationCause::dummy(), param_env).normalize(&value)?; + infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?; fulfill_cx.register_predicate_obligations(infcx, obligations); Ok(value) } diff --git a/compiler/rustc_ty/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml similarity index 95% rename from compiler/rustc_ty/Cargo.toml rename to compiler/rustc_ty_utils/Cargo.toml index acb011b2dc..5020437bcf 100644 --- a/compiler/rustc_ty/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] authors = ["The Rust Project Developers"] -name = "rustc_ty" +name = "rustc_ty_utils" version = "0.0.0" edition = "2018" diff --git a/compiler/rustc_ty/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs similarity index 100% rename from compiler/rustc_ty/src/common_traits.rs rename to compiler/rustc_ty_utils/src/common_traits.rs diff --git a/compiler/rustc_ty/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs similarity index 98% rename from compiler/rustc_ty/src/instance.rs rename to compiler/rustc_ty_utils/src/instance.rs index 220f4cec74..cf2c6efb47 100644 --- a/compiler/rustc_ty/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -51,7 +51,7 @@ fn inner_resolve_instance<'tcx>( resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) } else { let ty = tcx.type_of(def.def_id_for_type_of()); - let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); + let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty); let def = match *item_type.kind() { ty::FnDef(..) @@ -146,7 +146,7 @@ fn resolve_associated_item<'tcx>( substs, leaf_def.defining_node, ); - infcx.tcx.erase_regions(&substs) + infcx.tcx.erase_regions(substs) }); // Since this is a trait item, we need to see if the item is either a trait default item @@ -172,7 +172,7 @@ fn resolve_associated_item<'tcx>( return Ok(None); } - let substs = tcx.erase_regions(&substs); + let substs = tcx.erase_regions(substs); // Check if we just resolved an associated `const` declaration from // a `trait` to an associated `const` definition in an `impl`, where @@ -192,7 +192,7 @@ fn resolve_associated_item<'tcx>( && leaf_def.item.def_id.is_local() { let normalized_type_of = |def_id, substs| { - tcx.subst_and_normalize_erasing_regions(substs, param_env, &tcx.type_of(def_id)) + tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id)) }; let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs); @@ -264,7 +264,7 @@ fn resolve_associated_item<'tcx>( assert_eq!(name, sym::clone_from); // Use the default `fn clone_from` from `trait Clone`. - let substs = tcx.erase_regions(&rcvr_substs); + let substs = tcx.erase_regions(rcvr_substs); Some(ty::Instance::new(def_id, substs)) } } else { diff --git a/compiler/rustc_ty/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs similarity index 100% rename from compiler/rustc_ty/src/lib.rs rename to compiler/rustc_ty_utils/src/lib.rs diff --git a/compiler/rustc_ty/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs similarity index 94% rename from compiler/rustc_ty/src/needs_drop.rs rename to compiler/rustc_ty_utils/src/needs_drop.rs index 0356bcec54..64f82817d3 100644 --- a/compiler/rustc_ty/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -94,20 +94,16 @@ where _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), ty::Closure(_, substs) => { - for upvar_ty in substs.as_closure().upvar_tys() { - queue_type(self, upvar_ty); - } + queue_type(self, substs.as_closure().tupled_upvars_ty()); } ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); - for upvar_ty in substs.upvar_tys() { - queue_type(self, upvar_ty); - } + queue_type(self, substs.tupled_upvars_ty()); let witness = substs.witness(); let interior_tys = match witness.kind() { - ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), + &ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), _ => { tcx.sess.delay_span_bug( tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP), diff --git a/compiler/rustc_ty/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs similarity index 99% rename from compiler/rustc_ty/src/ty.rs rename to compiler/rustc_ty_utils/src/ty.rs index 2562140bb5..aa1de6d51c 100644 --- a/compiler/rustc_ty/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -309,7 +309,7 @@ fn well_formed_types_in_env<'tcx>( InherentImpl, Fn, Other, - }; + } let node_kind = match node { Node::TraitItem(item) => match item.kind { @@ -363,7 +363,7 @@ fn well_formed_types_in_env<'tcx>( // well-formed. NodeKind::Fn => { let fn_sig = tcx.fn_sig(def_id); - let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); + let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml new file mode 100644 index 0000000000..d50451b779 --- /dev/null +++ b/compiler/rustc_type_ir/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rustc_type_ir" +version = "0.0.0" +authors = ["The Rust Project Developers"] +edition = "2018" + +[lib] +doctest = false + +[dependencies] +bitflags = "1.2.1" +rustc_index = { path = "../rustc_index" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs new file mode 100644 index 0000000000..37abb4496a --- /dev/null +++ b/compiler/rustc_type_ir/src/lib.rs @@ -0,0 +1,204 @@ +#![feature(never_type)] +#![feature(const_panic)] +#![feature(control_flow_enum)] + +#[macro_use] +extern crate bitflags; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + +bitflags! { + /// Flags that we track on types. These flags are propagated upwards + /// through the type during type construction, so that we can quickly check + /// whether the type has various kinds of types in it without recursing + /// over the type itself. + pub struct TypeFlags: u32 { + // Does this have parameters? Used to determine whether substitution is + // required. + /// Does this have `Param`? + const HAS_TY_PARAM = 1 << 0; + /// Does this have `ReEarlyBound`? + const HAS_RE_PARAM = 1 << 1; + /// Does this have `ConstKind::Param`? + const HAS_CT_PARAM = 1 << 2; + + const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits + | TypeFlags::HAS_RE_PARAM.bits + | TypeFlags::HAS_CT_PARAM.bits; + + /// Does this have `Infer`? + const HAS_TY_INFER = 1 << 3; + /// Does this have `ReVar`? + const HAS_RE_INFER = 1 << 4; + /// Does this have `ConstKind::Infer`? + const HAS_CT_INFER = 1 << 5; + + /// Does this have inference variables? Used to determine whether + /// inference is required. + const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_RE_INFER.bits + | TypeFlags::HAS_CT_INFER.bits; + + /// Does this have `Placeholder`? + const HAS_TY_PLACEHOLDER = 1 << 6; + /// Does this have `RePlaceholder`? + const HAS_RE_PLACEHOLDER = 1 << 7; + /// Does this have `ConstKind::Placeholder`? + const HAS_CT_PLACEHOLDER = 1 << 8; + + /// `true` if there are "names" of regions and so forth + /// that are local to a particular fn/inferctxt + const HAS_FREE_LOCAL_REGIONS = 1 << 9; + + /// `true` if there are "names" of types and regions and so forth + /// that are local to a particular fn + const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits + | TypeFlags::HAS_CT_PARAM.bits + | TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_CT_INFER.bits + | TypeFlags::HAS_TY_PLACEHOLDER.bits + | TypeFlags::HAS_CT_PLACEHOLDER.bits + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; + + /// Does this have `Projection`? + const HAS_TY_PROJECTION = 1 << 10; + /// Does this have `Opaque`? + const HAS_TY_OPAQUE = 1 << 11; + /// Does this have `ConstKind::Unevaluated`? + const HAS_CT_PROJECTION = 1 << 12; + + /// Could this type be normalized further? + const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits + | TypeFlags::HAS_TY_OPAQUE.bits + | TypeFlags::HAS_CT_PROJECTION.bits; + + /// Is an error type/const reachable? + const HAS_ERROR = 1 << 13; + + /// Does this have any region that "appears free" in the type? + /// Basically anything but `ReLateBound` and `ReErased`. + const HAS_FREE_REGIONS = 1 << 14; + + /// Does this have any `ReLateBound` regions? Used to check + /// if a global bound is safe to evaluate. + const HAS_RE_LATE_BOUND = 1 << 15; + + /// Does this have any `ReErased` regions? + const HAS_RE_ERASED = 1 << 16; + + /// Does this value have parameters/placeholders/inference variables which could be + /// replaced later, in a way that would change the results of `impl` specialization? + const STILL_FURTHER_SPECIALIZABLE = 1 << 17; + } +} + +rustc_index::newtype_index! { + /// A [De Bruijn index][dbi] is a standard means of representing + /// regions (and perhaps later types) in a higher-ranked setting. In + /// particular, imagine a type like this: + /// + /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) + /// ^ ^ | | | + /// | | | | | + /// | +------------+ 0 | | + /// | | | + /// +----------------------------------+ 1 | + /// | | + /// +----------------------------------------------+ 0 + /// + /// In this type, there are two binders (the outer fn and the inner + /// fn). We need to be able to determine, for any given region, which + /// fn type it is bound by, the inner or the outer one. There are + /// various ways you can do this, but a De Bruijn index is one of the + /// more convenient and has some nice properties. The basic idea is to + /// count the number of binders, inside out. Some examples should help + /// clarify what I mean. + /// + /// Let's start with the reference type `&'b isize` that is the first + /// argument to the inner function. This region `'b` is assigned a De + /// Bruijn index of 0, meaning "the innermost binder" (in this case, a + /// fn). The region `'a` that appears in the second argument type (`&'a + /// isize`) would then be assigned a De Bruijn index of 1, meaning "the + /// second-innermost binder". (These indices are written on the arrows + /// in the diagram). + /// + /// What is interesting is that De Bruijn index attached to a particular + /// variable will vary depending on where it appears. For example, + /// the final type `&'a char` also refers to the region `'a` declared on + /// the outermost fn. But this time, this reference is not nested within + /// any other binders (i.e., it is not an argument to the inner fn, but + /// rather the outer one). Therefore, in this case, it is assigned a + /// De Bruijn index of 0, because the innermost binder in that location + /// is the outer fn. + /// + /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index + pub struct DebruijnIndex { + DEBUG_FORMAT = "DebruijnIndex({})", + const INNERMOST = 0, + } +} + +impl DebruijnIndex { + /// Returns the resulting index when this value is moved into + /// `amount` number of new binders. So, e.g., if you had + /// + /// for<'a> fn(&'a x) + /// + /// and you wanted to change it to + /// + /// for<'a> fn(for<'b> fn(&'a x)) + /// + /// you would need to shift the index for `'a` into a new binder. + #[must_use] + pub fn shifted_in(self, amount: u32) -> DebruijnIndex { + DebruijnIndex::from_u32(self.as_u32() + amount) + } + + /// Update this index in place by shifting it "in" through + /// `amount` number of binders. + pub fn shift_in(&mut self, amount: u32) { + *self = self.shifted_in(amount); + } + + /// Returns the resulting index when this value is moved out from + /// `amount` number of new binders. + #[must_use] + pub fn shifted_out(self, amount: u32) -> DebruijnIndex { + DebruijnIndex::from_u32(self.as_u32() - amount) + } + + /// Update in place by shifting out from `amount` binders. + pub fn shift_out(&mut self, amount: u32) { + *self = self.shifted_out(amount); + } + + /// Adjusts any De Bruijn indices so as to make `to_binder` the + /// innermost binder. That is, if we have something bound at `to_binder`, + /// it will now be bound at INNERMOST. This is an appropriate thing to do + /// when moving a region out from inside binders: + /// + /// ``` + /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) + /// // Binder: D3 D2 D1 ^^ + /// ``` + /// + /// Here, the region `'a` would have the De Bruijn index D3, + /// because it is the bound 3 binders out. However, if we wanted + /// to refer to that region `'a` in the second argument (the `_`), + /// those two binders would not be in scope. In that case, we + /// might invoke `shift_out_to_binder(D3)`. This would adjust the + /// De Bruijn index of `'a` to D1 (the innermost binder). + /// + /// If we invoke `shift_out_to_binder` and the region is in fact + /// bound by one of the binders we are shifting out of, that is an + /// error (and should fail an assertion failure). + pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { + self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32()) + } +} + +impl HashStable for DebruijnIndex { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.as_u32().hash_stable(ctx, hasher); + } +} diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index 685243f54c..b04acd9660 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -1,11 +1,11 @@ use crate::astconv::AstConv; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty; use rustc_session::parse::feature_err; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; @@ -180,7 +180,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .collect(); if let (Some(suggested_name), true) = ( - find_best_match_for_name(all_candidate_names.iter(), assoc_name.name, None), + find_best_match_for_name(&all_candidate_names, assoc_name.name, None), assoc_name.span != DUMMY_SP, ) { err.span_suggestion( diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 3bfb2d3f1b..b7e77f389f 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -1,12 +1,13 @@ use crate::astconv::{ - AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, + AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + GenericArgCountResult, GenericArgPosition, }; use crate::errors::AssocTypeBindingNotAllowed; use rustc_ast::ast::ParamKindOrd; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::{GenericArg, GenericArgs}; +use rustc_hir::GenericArg; use rustc_middle::ty::{ self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt, }; @@ -22,6 +23,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { sess: &Session, arg: &GenericArg<'_>, kind: &'static str, + possible_ordering_error: bool, help: Option<&str>, ) { let mut err = struct_span_err!( @@ -42,14 +44,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // the match is non-exhaustive. _ => bug!("invalid generic parameter kind {}", kind), }; + + if let ParamKindOrd::Const { .. } = kind_ord { + if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg { + err.help("const arguments cannot yet be inferred with `_`"); + } + } + let arg_ord = match arg { GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, GenericArg::Type(_) => ParamKindOrd::Type, GenericArg::Const(_) => ParamKindOrd::Const { unordered }, }; + if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. })) + && matches!(kind_ord, ParamKindOrd::Const { .. }) + { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + err.multipart_suggestion( + "if this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); + } + // This note is only true when generic parameters are strictly ordered by their kind. - if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { + if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { let (first, last) = if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; err.note(&format!("{} arguments must be provided before {} arguments", first, last)); @@ -90,20 +114,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// instantiate a `GenericArg`. /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then /// creates a suitable inference variable. - pub fn create_substs_for_generic_args<'b>( + pub fn create_substs_for_generic_args<'a>( tcx: TyCtxt<'tcx>, def_id: DefId, parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option>, arg_count: GenericArgCountResult, - args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), - mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, - mut inferred_kind: impl FnMut( - Option<&[subst::GenericArg<'tcx>]>, - &GenericParamDef, - bool, - ) -> subst::GenericArg<'tcx>, + ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>, ) -> SubstsRef<'tcx> { // Collect the segments of the path; we need to substitute arguments // for parameters throughout the entire path (wherever there are @@ -142,7 +160,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { substs.push( self_ty .map(|ty| ty.into()) - .unwrap_or_else(|| inferred_kind(None, param, true)), + .unwrap_or_else(|| ctx.inferred_kind(None, param, true)), ); params.next(); } @@ -151,10 +169,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Check whether this segment takes generic arguments and the user has provided any. - let (generic_args, infer_args) = args_for_def_id(def_id); + let (generic_args, infer_args) = ctx.args_for_def_id(def_id); - let mut args = - generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable(); + let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()); + let mut args = args_iter.clone().peekable(); // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. // If we later encounter a lifetime, we know that the arguments were provided in the @@ -173,7 +191,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { - substs.push(provided_kind(param, arg)); + substs.push(ctx.provided_kind(param, arg)); args.next(); params.next(); } @@ -184,7 +202,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. - substs.push(inferred_kind(None, param, infer_args)); + substs.push(ctx.inferred_kind(None, param, infer_args)); force_infer_lt = Some(arg); params.next(); } @@ -221,8 +239,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Const => { ParamKindOrd::Const { unordered: tcx - .sess - .features_untracked() + .features() .const_generics, } } @@ -242,6 +259,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.sess, arg, kind.descr(), + !args_iter.clone().is_sorted_by_key(|arg| match arg { + GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, + GenericArg::Type(_) => ParamKindOrd::Type, + GenericArg::Const(_) => ParamKindOrd::Const { + unordered: tcx.features().const_generics, + }, + }), Some(&format!( "reorder the arguments: {}: `<{}>`", param_types_present @@ -293,7 +317,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert_eq!(kind, "lifetime"); let provided = force_infer_lt.expect("lifetimes ought to have been inferred"); - Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None); + Self::generic_arg_mismatch_err(tcx.sess, provided, kind, false, None); } break; @@ -302,7 +326,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. - substs.push(inferred_kind(Some(&substs), param, infer_args)); + substs.push(ctx.inferred_kind(Some(&substs), param, infer_args)); params.next(); } @@ -351,6 +375,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // that lifetimes will proceed types. So it suffices to check the number of each generic // arguments in order to validate them with respect to the generic parameters. let param_counts = def.own_counts(); + let named_type_param_count = param_counts.types - has_self as usize; let arg_counts = args.own_counts(); let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; @@ -389,11 +414,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // For kinds without defaults (e.g.., lifetimes), `required == permitted`. // For other kinds (i.e., types), `permitted` may be greater than `required`. if required <= provided && provided <= permitted { - return Ok(()); + return true; } if silent { - return Err((0i32, None)); + return false; } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -409,25 +434,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (required, "") }; - let (spans, label) = if required == permitted && provided > permitted { + let (spans, labels) = if provided > permitted { // In the case when the user has provided too many arguments, // we want to point to the unexpected arguments. - let spans: Vec = args.args[offset + permitted..offset + provided] + let (spans, labels): (Vec, Vec) = args.args + [offset + permitted..offset + provided] .iter() - .map(|arg| arg.span()) - .collect(); + .map(|arg| (arg.span(), format!("unexpected {} argument", arg.short_descr()))) + .unzip(); unexpected_spans.extend(spans.clone()); - (spans, format!("unexpected {} argument", kind)) + (spans, labels) } else { ( vec![span], - format!( + vec![format!( "expected {}{} {} argument{}", quantifier, bound, kind, pluralize!(bound), - ), + )], ) }; @@ -439,105 +465,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ), DiagnosticId::Error("E0107".into()), ); - for span in spans { + for (span, label) in spans.into_iter().zip(labels) { err.span_label(span, label.as_str()); } - - assert_ne!(bound, provided); - Err((bound as i32 - provided as i32, Some(err))) + err.emit(); + false }; let mut unexpected_spans = vec![]; - let mut lifetime_count_correct = Ok(()); - if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { - lifetime_count_correct = check_kind_count( - "lifetime", - param_counts.lifetimes, - param_counts.lifetimes, - arg_counts.lifetimes, - 0, - &mut unexpected_spans, - explicit_late_bound == ExplicitLateBound::Yes, - ); - } - - // FIXME(const_generics:defaults) - let mut const_count_correct = Ok(()); - if !infer_args || arg_counts.consts > param_counts.consts { - const_count_correct = check_kind_count( - "const", - param_counts.consts, - param_counts.consts, - arg_counts.consts, - arg_counts.lifetimes + arg_counts.types, - &mut unexpected_spans, - false, - ); - } - - // Note that type errors are currently be emitted *after* const errors. - let mut type_count_correct = Ok(()); - if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize - { - type_count_correct = check_kind_count( - "type", - param_counts.types - defaults.types - has_self as usize, - param_counts.types - has_self as usize, - arg_counts.types, - arg_counts.lifetimes, - &mut unexpected_spans, - false, - ); - } - - // Emit a help message if it's possible that a type could be surrounded in braces - if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct { - if let Err((_, Some(ref mut type_err))) = type_count_correct { - let possible_matches = args.args[arg_counts.lifetimes..] - .iter() - .filter(|arg| { - matches!( - arg, - GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }) - ) - }) - .take(c_mismatch.max(0) as usize); - for arg in possible_matches { - let suggestions = vec![ - (arg.span().shrink_to_lo(), String::from("{ ")), - (arg.span().shrink_to_hi(), String::from(" }")), - ]; - type_err.multipart_suggestion( - "If this generic argument was intended as a const parameter, \ - try surrounding it with braces:", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } - } + let lifetime_count_correct = check_kind_count( + "lifetime", + if infer_lifetimes { 0 } else { param_counts.lifetimes }, + param_counts.lifetimes, + arg_counts.lifetimes, + 0, + &mut unexpected_spans, + explicit_late_bound == ExplicitLateBound::Yes, + ); - let emit_correct = - |correct: Result<(), (_, Option>)>| match correct { - Ok(()) => Ok(()), - Err((_, None)) => Err(()), - Err((_, Some(mut err))) => { - err.emit(); - Err(()) - } - }; + let kind_str = if param_counts.consts + arg_counts.consts == 0 { + "type" + } else if named_type_param_count + arg_counts.types == 0 { + "const" + } else { + "generic" + }; - let arg_count_correct = emit_correct(lifetime_count_correct) - .and(emit_correct(const_count_correct)) - .and(emit_correct(type_count_correct)); + let arg_count_correct = check_kind_count( + kind_str, + if infer_args { + 0 + } else { + param_counts.consts + named_type_param_count - defaults.types + }, + param_counts.consts + named_type_param_count, + arg_counts.consts + arg_counts.types, + arg_counts.lifetimes, + &mut unexpected_spans, + false, + ); GenericArgCountResult { explicit_late_bound, - correct: arg_count_correct.map_err(|()| GenericArgCountMismatch { - reported: Some(ErrorReported), - invalid_args: unexpected_spans, - }), + correct: if lifetime_count_correct && arg_count_correct { + Ok(()) + } else { + Err(GenericArgCountMismatch { + reported: Some(ErrorReported), + invalid_args: unexpected_spans, + }) + }, } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 07e523af3e..38d33e5586 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -13,7 +13,6 @@ use crate::errors::{ }; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError}; use rustc_hir as hir; @@ -26,6 +25,7 @@ use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -165,6 +165,23 @@ pub struct GenericArgCountResult { pub correct: Result<(), GenericArgCountMismatch>, } +pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { + fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool); + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx>; + + fn inferred_kind( + &mut self, + substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + infer_args: bool, + ) -> subst::GenericArg<'tcx>; +} + impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( &self, @@ -179,11 +196,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(rl::Region::LateBound(debruijn, id, _)) => { let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReLateBound(debruijn, ty::BrNamed(id, name))) + let br = ty::BoundRegion { kind: ty::BrNamed(id, name) }; + tcx.mk_region(ty::ReLateBound(debruijn, br)) } Some(rl::Region::LateBoundAnon(debruijn, index)) => { - tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index))) + let br = ty::BoundRegion { kind: ty::BrAnon(index) }; + tcx.mk_region(ty::ReLateBound(debruijn, br)) } Some(rl::Region::EarlyBound(index, id, _)) => { @@ -320,82 +339,111 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { infer_args, ); + // Skip processing if type has no generic parameters. + // Traits always have `Self` as a generic parameter, which means they will not return early + // here and so associated type bindings will be handled regardless of whether there are any + // non-`Self` generic parameters. + if generic_params.params.len() == 0 { + return (tcx.intern_substs(&[]), vec![], arg_count); + } + let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - let default_needs_object_self = |param: &ty::GenericParamDef| { - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if is_object && has_default { - let default_ty = tcx.at(span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; + + struct SubstsForAstPathCtxt<'a, 'tcx> { + astconv: &'a (dyn AstConv<'tcx> + 'a), + def_id: DefId, + generic_args: &'a GenericArgs<'a>, + span: Span, + missing_type_params: Vec, + inferred_params: Vec, + infer_args: bool, + is_object: bool, + } + + impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { + fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { + let tcx = self.astconv.tcx(); + if let GenericParamDefKind::Type { has_default, .. } = param.kind { + if self.is_object && has_default { + let default_ty = tcx.at(self.span).type_of(param.def_id); + let self_param = tcx.types.self_param; + if default_ty.walk().any(|arg| arg == self_param.into()) { + // There is no suitable inference default for a type parameter + // that references self, in an object type. + return true; + } } } - } - false - }; + false + } + } - let mut missing_type_params = vec![]; - let mut inferred_params = vec![]; - let substs = Self::create_substs_for_generic_args( - tcx, - def_id, - parent_substs, - self_ty.is_some(), - self_ty, - arg_count.clone(), - // Provide the generic args, and whether types should be inferred. - |did| { - if did == def_id { - (Some(generic_args), infer_args) + impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { + fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) { + if did == self.def_id { + (Some(self.generic_args), self.infer_args) } else { // The last component of this tuple is unimportant. (None, false) } - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.ast_region_to_region(<, Some(param)).into() - } - (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { - if *has_default { - tcx.check_optional_stability( - param.def_id, - Some(arg.id()), - arg.span(), - |_, _| { - // Default generic parameters may not be marked - // with stability attributes, i.e. when the - // default parameter was defined at the same time - // as the rest of the type. As such, we ignore missing - // stability attributes. + } + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx> { + let tcx = self.astconv.tcx(); + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + self.astconv.ast_region_to_region(<, Some(param)).into() + } + (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { + if has_default { + tcx.check_optional_stability( + param.def_id, + Some(arg.id()), + arg.span(), + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. + }, + ) + } + if let (hir::TyKind::Infer, false) = + (&ty.kind, self.astconv.allow_ty_infer()) + { + self.inferred_params.push(ty.span); + tcx.ty_error().into() + } else { + self.astconv.ast_ty_to_ty(&ty).into() + } + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + ty::Const::from_opt_const_arg_anon_const( + tcx, + ty::WithOptConstParam { + did: tcx.hir().local_def_id(ct.value.hir_id), + const_param_did: Some(param.def_id), }, ) + .into() } - if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { - inferred_params.push(ty.span); - tcx.ty_error().into() - } else { - self.ast_ty_to_ty(&ty).into() - } - } - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - ty::Const::from_opt_const_arg_anon_const( - tcx, - ty::WithOptConstParam { - did: tcx.hir().local_def_id(ct.value.hir_id), - const_param_did: Some(param.def_id), - }, - ) - .into() + _ => unreachable!(), } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { + } + + fn inferred_kind( + &mut self, + substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + infer_args: bool, + ) -> subst::GenericArg<'tcx> { + let tcx = self.astconv.tcx(); match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), GenericParamDefKind::Type { has_default, .. } => { @@ -407,48 +455,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // other type parameters may reference `Self` in their // defaults. This will lead to an ICE if we are not // careful! - if default_needs_object_self(param) { - missing_type_params.push(param.name.to_string()); + if self.default_needs_object_self(param) { + self.missing_type_params.push(param.name.to_string()); tcx.ty_error().into() } else { // This is a default type parameter. - self.normalize_ty( - span, - tcx.at(span).type_of(param.def_id).subst_spanned( - tcx, - substs.unwrap(), - Some(span), - ), - ) - .into() + self.astconv + .normalize_ty( + self.span, + tcx.at(self.span).type_of(param.def_id).subst_spanned( + tcx, + substs.unwrap(), + Some(self.span), + ), + ) + .into() } } else if infer_args { // No type parameters were provided, we can infer all. - let param = - if !default_needs_object_self(param) { Some(param) } else { None }; - self.ty_infer(param, span).into() + let param = if !self.default_needs_object_self(param) { + Some(param) + } else { + None + }; + self.astconv.ty_infer(param, self.span).into() } else { // We've already errored above about the mismatch. tcx.ty_error().into() } } GenericParamDefKind::Const => { - let ty = tcx.at(span).type_of(param.def_id); + let ty = tcx.at(self.span).type_of(param.def_id); // FIXME(const_generics:defaults) if infer_args { // No const parameters were provided, we can infer all. - self.ct_infer(ty, Some(param), span).into() + self.astconv.ct_infer(ty, Some(param), self.span).into() } else { // We've already errored above about the mismatch. tcx.const_error(ty).into() } } } - }, + } + } + + let mut substs_ctx = SubstsForAstPathCtxt { + astconv: self, + def_id, + span, + generic_args, + missing_type_params: vec![], + inferred_params: vec![], + infer_args, + is_object, + }; + let substs = Self::create_substs_for_generic_args( + tcx, + def_id, + parent_substs, + self_ty.is_some(), + self_ty, + arg_count.clone(), + &mut substs_ctx, ); self.complain_about_missing_type_params( - missing_type_params, + substs_ctx.missing_type_params, def_id, span, generic_args.args.is_empty(), @@ -753,34 +825,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ast_bounds: &[hir::GenericBound<'_>], bounds: &mut Bounds<'tcx>, ) { - let mut trait_bounds = Vec::new(); - let mut region_bounds = Vec::new(); - let constness = self.default_constness_for_trait_bounds(); for ast_bound in ast_bounds { match *ast_bound { hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - trait_bounds.push((b, constness)) + self.instantiate_poly_trait_ref(b, constness, param_ty, bounds); } hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { - trait_bounds.push((b, Constness::NotConst)) + self.instantiate_poly_trait_ref(b, Constness::NotConst, param_ty, bounds); } hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self .instantiate_lang_item_trait_ref( lang_item, span, hir_id, args, param_ty, bounds, ), - hir::GenericBound::Outlives(ref l) => region_bounds.push(l), + hir::GenericBound::Outlives(ref l) => bounds + .region_bounds + .push((ty::Binder::bind(self.ast_region_to_region(l, None)), l.span)), } } - - for (bound, constness) in trait_bounds { - let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds); - } - - bounds.region_bounds.extend( - region_bounds.into_iter().map(|r| (self.ast_region_to_region(r, None), r.span)), - ); } /// Translates a list of bounds from the HIR into the `Bounds` data structure. @@ -1193,22 +1256,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) }); - // Calling `skip_binder` is okay because the predicates are re-bound. - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder())); - let auto_trait_predicates = auto_traits - .into_iter() - .map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())); + let regular_trait_predicates = existential_trait_refs.map(|trait_ref| { + trait_ref.map_bound(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref)) + }); + let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + }); let mut v = regular_trait_predicates .chain(auto_trait_predicates) .chain( existential_projections - .map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())), + .map(|x| x.map_bound(|x| ty::ExistentialPredicate::Projection(x))), ) .collect::>(); - v.sort_by(|a, b| a.stable_cmp(tcx, b)); + v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); v.dedup(); - let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter())); + let existential_predicates = tcx.mk_poly_existential_predicates(v.into_iter()); // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { @@ -1302,7 +1365,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { || { traits::transitive_bounds( tcx, - predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()), + predicates.iter().filter_map(|(p, _)| { + p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) + }), ) }, || param_name.to_string(), @@ -1515,7 +1580,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); if let Some(suggested_name) = find_best_match_for_name( - adt_def.variants.iter().map(|variant| &variant.ident.name), + &adt_def + .variants + .iter() + .map(|variant| variant.ident.name) + .collect::>(), assoc_ident.name, None, ) { @@ -2228,8 +2297,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn validate_late_bound_regions( &self, - constrained_regions: FxHashSet, - referenced_regions: FxHashSet, + constrained_regions: FxHashSet, + referenced_regions: FxHashSet, generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>, ) { for br in referenced_regions.difference(&constrained_regions) { @@ -2264,7 +2333,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn compute_object_lifetime_bound( &self, span: Span, - existential_predicates: ty::Binder<&'tcx ty::List>>, + existential_predicates: &'tcx ty::List>>, ) -> Option> // if None, use the default { let tcx = self.tcx(); diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 683707470f..7ba90ad881 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -26,7 +26,7 @@ pub struct Bounds<'tcx> { /// A list of region bounds on the (implicit) self type. So if you /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but /// the `T` is not explicitly included). - pub region_bounds: Vec<(ty::Region<'tcx>, Span)>, + pub region_bounds: Vec<(ty::Binder>, Span)>, /// A list of trait bounds. So if you had `T: Debug` this would be /// `T: Debug`. Note that the self-type is explicit here. @@ -67,22 +67,22 @@ impl<'tcx> Bounds<'tcx> { sized_predicate .into_iter() + .chain(self.region_bounds.iter().map(|&(region_bound, span)| { + ( + region_bound + .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound)) + .to_predicate(tcx), + span, + ) + })) + .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { + let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); + (predicate, span) + })) .chain( - self.region_bounds + self.projection_bounds .iter() - .map(|&(region_bound, span)| { - let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::bind(outlives).to_predicate(tcx), span) - }) - .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { - let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); - (predicate, span) - })) - .chain( - self.projection_bounds - .iter() - .map(|&(projection, span)| (projection.to_predicate(tcx), span)), - ), + .map(|&(projection, span)| (projection.to_predicate(tcx), span)), ) .collect() } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index e8eea65137..6467e04407 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -31,7 +31,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => (false, false, false), }; - // Type check the descriminant and get its type. + // Type check the discriminant and get its type. let scrutinee_ty = if force_scrutinee_bool { // Here we want to ensure: // @@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(60707): Consider removing hack with principled solution. self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {}) } else { - self.demand_scrutinee_type(arms, scrut) + self.demand_scrutinee_type(scrut, arms_contain_ref_bindings(arms), arms.is_empty()) }; // If there are no arms, that is a diverging match; a special case. @@ -98,7 +98,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.diverges.set(Diverges::Maybe); match g { hir::Guard::If(e) => { - self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}) + self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); + } + hir::Guard::IfLet(pat, e) => { + let scrutinee_ty = self.demand_scrutinee_type( + e, + pat.contains_explicit_ref_binding(), + false, + ); + self.check_pat_top(&pat, scrutinee_ty, None, true); } }; } @@ -131,7 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { id, self.body_id, self.param_env, - &ty, + ty, arm.body.span, ); let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty(); @@ -450,8 +458,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn demand_scrutinee_type( &self, - arms: &'tcx [hir::Arm<'tcx>], scrut: &'tcx hir::Expr<'tcx>, + contains_ref_bindings: Option, + no_arms: bool, ) -> Ty<'tcx> { // Not entirely obvious: if matches may create ref bindings, we want to // use the *precise* type of the scrutinee, *not* some supertype, as @@ -505,17 +514,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // (once introduced) is populated by the time we get here. // // See #44848. - let contains_ref_bindings = arms - .iter() - .filter_map(|a| a.pat.contains_explicit_ref_binding()) - .max_by_key(|m| match *m { - hir::Mutability::Mut => 1, - hir::Mutability::Not => 0, - }); - if let Some(m) = contains_ref_bindings { self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m)) - } else if arms.is_empty() { + } else if no_arms { self.check_expr(scrut) } else { // ...but otherwise we want to use any supertype of the @@ -546,3 +547,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +fn arms_contain_ref_bindings(arms: &'tcx [hir::Arm<'tcx>]) -> Option { + arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m { + hir::Mutability::Mut => 1, + hir::Mutability::Not => 0, + }) +} diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index a38fb9642b..22e287320d 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( call_expr.span, infer::FnCall, - &closure_sig, + closure_sig, ) .0; let adjustments = self.adjust_steps(autoderef); @@ -389,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // In that case, we check each argument against "error" in order to // set up all the node type bindings. ( - ty::Binder::bind(self.tcx.mk_fn_sig( + ty::Binder::dummy(self.tcx.mk_fn_sig( self.err_args(arg_exprs.len()).into_iter(), self.tcx.ty_error(), false, @@ -407,8 +407,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // previously appeared within a `Binder<>` and hence would not // have been normalized before. let fn_sig = - self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, &fn_sig).0; - let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig); + self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig).0; + let fn_sig = self.normalize_associated_types_in(call_expr.span, fn_sig); // Call the generic checker. let expected_arg_tys = self.expected_inputs_for_expected_output( diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 5c2bdb86f7..36240a9b41 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Result>, ErrorReported> { debug!("pointer_kind({:?}, {:?})", t, span); - let t = self.resolve_vars_if_possible(&t); + let t = self.resolve_vars_if_possible(t); if t.references_error() { return Err(ErrorReported); @@ -377,12 +377,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Check `impl From for self.cast_ty {}` for accurate suggestion: if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) { - let ty = fcx.resolve_vars_if_possible(&self.cast_ty); + let ty = fcx.resolve_vars_if_possible(self.cast_ty); // Erase regions to avoid panic in `prove_value` when calling // `type_implements_trait`. - let ty = fcx.tcx.erase_regions(&ty); - let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty); - let expr_ty = fcx.tcx.erase_regions(&expr_ty); + let ty = fcx.tcx.erase_regions(ty); + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let expr_ty = fcx.tcx.erase_regions(expr_ty); let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]); // Check for infer types because cases like `Option<{integer}>` would // panic otherwise. @@ -471,7 +471,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_ty, E0620, "cast to unsized type: `{}` as `{}`", - fcx.resolve_vars_if_possible(&self.expr_ty), + fcx.resolve_vars_if_possible(self.expr_ty), tstr ); match self.expr_ty.kind() { @@ -607,7 +607,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Attempt a coercion to a fn pointer type. let f = fcx.normalize_associated_types_in( self.expr.span, - &self.expr_ty.fn_sig(fcx.tcx), + self.expr_ty.fn_sig(fcx.tcx), ); let res = fcx.try_coerce( self.expr, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 70d94ef869..d235ad21c7 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -75,7 +75,7 @@ pub(super) fn check_fn<'a, 'tcx>( let declared_ret_ty = fn_sig.output(); let revealed_ret_ty = - fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); + fcx.instantiate_opaque_types_from_value(fn_id, declared_ret_ty, decl.output.span()); debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fcx.ret_type_span = Some(decl.output.span()); @@ -94,6 +94,37 @@ pub(super) fn check_fn<'a, 'tcx>( fn_maybe_err(tcx, span, fn_sig.abi); + if fn_sig.abi == Abi::RustCall { + let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 }; + + let err = || { + let item = match tcx.hir().get(fn_id) { + Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header), + Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(header, ..), .. + }) => Some(header), + // Closures are RustCall, but they tuple their arguments, so shouldn't be checked + Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => None, + node => bug!("Item being checked wasn't a function/closure: {:?}", node), + }; + + if let Some(header) = item { + tcx.sess.span_err(header.span, "A function with the \"rust-call\" ABI must take a single non-self argument that is a tuple") + } + }; + + if fn_sig.inputs().len() != expected_args { + err() + } else { + // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on + // This will probably require wide-scale changes to support a TupleKind obligation + // We can't resolve this without knowing the type of the param + if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) { + err() + } + } + } + if body.generator_kind.is_some() && can_be_generator.is_some() { let yield_ty = fcx .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); @@ -157,7 +188,6 @@ pub(super) fn check_fn<'a, 'tcx>( // possible cases. fcx.check_expr(&body.value); fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); } else { fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); fcx.check_return_expr(&body.value); @@ -431,39 +461,25 @@ pub(super) fn check_opaque<'tcx>( /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result /// in "inheriting lifetimes". +#[instrument(skip(tcx, span))] pub(super) fn check_opaque_for_inheriting_lifetimes( tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span, ) { let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); - debug!( - "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", - def_id, span, item - ); + debug!(?item, ?span); - #[derive(Debug)] - struct ProhibitOpaqueVisitor<'tcx> { - opaque_identity_ty: Ty<'tcx>, - generics: &'tcx ty::Generics, - ty: Option>, - }; - - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { - debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); - if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() { - self.ty = Some(t); - return ControlFlow::BREAK; - } - ControlFlow::CONTINUE - } + struct FoundParentLifetime; + struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { + type BreakTy = FoundParentLifetime; - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { - debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + debug!("FindParentLifetimeVisitor: r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - if *index < self.generics.parent_count as u32 { - return ControlFlow::BREAK; + if *index < self.0.parent_count as u32 { + return ControlFlow::Break(FoundParentLifetime); } else { return ControlFlow::CONTINUE; } @@ -472,9 +488,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Unevaluated(..) = c.val { - // FIXME(#72219) We currenctly don't detect lifetimes within substs + // FIXME(#72219) We currently don't detect lifetimes within substs // which would violate this check. Even though the particular substitution is not used // within the const, this should still be fixed. return ControlFlow::CONTINUE; @@ -483,6 +499,26 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( } } + #[derive(Debug)] + struct ProhibitOpaqueVisitor<'tcx> { + opaque_identity_ty: Ty<'tcx>, + generics: &'tcx ty::Generics, + } + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { + type BreakTy = Ty<'tcx>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); + if t == self.opaque_identity_ty { + ControlFlow::CONTINUE + } else { + t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics)) + .map_break(|FoundParentLifetime| t) + } + } + } + if let ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, .. @@ -494,18 +530,17 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), ), generics: tcx.generics_of(def_id), - ty: None, }; let prohibit_opaque = tcx .explicit_item_bounds(def_id) .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor).is_break()); + .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); debug!( "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", prohibit_opaque, visitor ); - if prohibit_opaque { + if let Some(ty) = prohibit_opaque.break_value() { let is_async = match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { hir::OpaqueTyOrigin::AsyncFn => true, @@ -525,14 +560,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { if snippet == "Self" { - if let Some(ty) = visitor.ty { - err.span_suggestion( - span, - "consider spelling out the type instead", - format!("{:?}", ty), - Applicability::MaybeIncorrect, - ); - } + err.span_suggestion( + span, + "consider spelling out the type instead", + format!("{:?}", ty), + Applicability::MaybeIncorrect, + ); } } err.emit(); @@ -601,7 +634,7 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = traits::ObligationCause::misc(span, hir_id); let (_, opaque_type_map) = inh.register_infer_ok_obligations( - infcx.instantiate_opaque_types(def_id, hir_id, param_env, &opaque_ty, span), + infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span), ); for (def_id, opaque_defn) in opaque_type_map { @@ -716,20 +749,22 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { let generics = tcx.generics_of(def_id); check_type_params_are_used(tcx, &generics, pty_ty); } - hir::ItemKind::ForeignMod(ref m) => { - check_abi(tcx, it.span, m.abi); + hir::ItemKind::ForeignMod { abi, items } => { + check_abi(tcx, it.span, abi); - if m.abi == Abi::RustIntrinsic { - for item in m.items { + if abi == Abi::RustIntrinsic { + for item in items { + let item = tcx.hir().foreign_item(item.id); intrinsic::check_intrinsic_type(tcx, item); } - } else if m.abi == Abi::PlatformIntrinsic { - for item in m.items { + } else if abi == Abi::PlatformIntrinsic { + for item in items { + let item = tcx.hir().foreign_item(item.id); intrinsic::check_platform_intrinsic_type(tcx, item); } } else { - for item in m.items { - let def_id = tcx.hir().local_def_id(item.hir_id); + for item in items { + let def_id = tcx.hir().local_def_id(item.id.hir_id); let generics = tcx.generics_of(def_id); let own_counts = generics.own_counts(); if generics.params.len() - own_counts.lifetimes != 0 { @@ -761,9 +796,10 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { .emit(); } + let item = tcx.hir().foreign_item(item.id); match item.kind { hir::ForeignItemKind::Fn(ref fn_decl, _, _) => { - require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); + require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { check_static_inhabited(tcx, def_id, item.span); @@ -1065,12 +1101,14 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { match e.kind() { ty::Param(_) => { /* struct(T, T, T, T) is ok */ } _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ } _ => { struct_span_err!( tcx.sess, sp, E0077, - "SIMD vector element type should be machine type" + "SIMD vector element type should be a \ + primitive scalar (integer/float/pointer) type" ) .emit(); return; @@ -1455,7 +1493,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { { struct VisitTypes(Vec); impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Opaque(def, _) => { self.0.push(def); diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 2ba05071c0..7470c1a76a 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -24,7 +24,7 @@ use std::iter; struct ExpectedSig<'tcx> { /// Span that gave us this expectation, if we know that. cause_span: Option, - sig: ty::FnSig<'tcx>, + sig: ty::PolyFnSig<'tcx>, } struct ClosureSignatures<'tcx> { @@ -174,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), ty::FnPtr(sig) => { - let expected_sig = ExpectedSig { cause_span: None, sig: sig.skip_binder() }; + let expected_sig = ExpectedSig { cause_span: None, sig }; (Some(expected_sig), Some(ty::ClosureKind::Fn)) } _ => (None, None), @@ -257,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let input_tys = if is_fn { let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); - let arg_param_ty = self.resolve_vars_if_possible(&arg_param_ty); + let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); match arg_param_ty.kind() { @@ -271,16 +271,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let ret_param_ty = projection.skip_binder().ty; - let ret_param_ty = self.resolve_vars_if_possible(&ret_param_ty); + let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty); - let sig = self.tcx.mk_fn_sig( + let sig = projection.rebind(self.tcx.mk_fn_sig( input_tys.iter(), &ret_param_ty, false, hir::Unsafety::Normal, Abi::Rust, - ); + )); debug!("deduce_sig_from_projection: sig={:?}", sig); Some(ExpectedSig { cause_span, sig }) @@ -374,9 +374,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. - if expected_sig.sig.c_variadic != decl.c_variadic { + if expected_sig.sig.c_variadic() != decl.c_variadic { return self.sig_of_closure_no_expectation(expr_def_id, decl, body); - } else if expected_sig.sig.inputs_and_output.len() != decl.inputs.len() + 1 { + } else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 { return self.sig_of_closure_with_mismatched_number_of_arguments( expr_def_id, decl, @@ -388,19 +388,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a `PolyFnSig`. Note the oddity that late bound // regions appearing free in `expected_sig` are now bound up // in this binder we are creating. - assert!(!expected_sig.sig.has_vars_bound_above(ty::INNERMOST)); - let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig( - expected_sig.sig.inputs().iter().cloned(), - expected_sig.sig.output(), - decl.c_variadic, - hir::Unsafety::Normal, - Abi::RustCall, - )); + assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST)); + let bound_sig = expected_sig.sig.map_bound(|sig| { + self.tcx.mk_fn_sig( + sig.inputs().iter().cloned(), + sig.output(), + sig.c_variadic, + hir::Unsafety::Normal, + Abi::RustCall, + ) + }); // `deduce_expectations_from_expected_type` introduces // late-bound lifetimes defined elsewhere, which we now // anonymize away, so as not to confuse the user. - let bound_sig = self.tcx.anonymize_late_bound_regions(&bound_sig); + let bound_sig = self.tcx.anonymize_late_bound_regions(bound_sig); let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig); @@ -428,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_map_node = hir.get_if_local(expr_def_id).unwrap(); let expected_args: Vec<_> = expected_sig .sig + .skip_binder() .inputs() .iter() .map(|ty| ArgKind::from_expected_ty(ty, None)) @@ -500,7 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (supplied_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars( hir_ty.span, LateBoundRegionConversionTime::FnCall, - &ty::Binder::bind(supplied_ty), + supplied_sig.inputs().rebind(supplied_ty), ); // recreated from (*) above // Check that E' = S'. @@ -513,7 +516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (supplied_output_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars( decl.output.span(), LateBoundRegionConversionTime::FnCall, - &supplied_sig.output(), + supplied_sig.output(), ); let cause = &self.misc(decl.output.span()); let InferOk { value: (), obligations } = self @@ -578,7 +581,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("supplied_sig_of_closure: result={:?}", result); - let c_result = self.inh.infcx.canonicalize_response(&result); + let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); result @@ -619,12 +622,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // where R is the return type we are expecting. This type `T` // will be our output. let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { - if let ty::PredicateAtom::Projection(proj_predicate) = - obligation.predicate.skip_binders() - { + let bound_predicate = obligation.predicate.bound_atom(); + if let ty::PredicateAtom::Projection(proj_predicate) = bound_predicate.skip_binder() { self.deduce_future_output_from_projection( obligation.cause.span, - ty::Binder::bind(proj_predicate), + bound_predicate.rebind(proj_predicate), ) } else { None @@ -683,7 +685,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Extract the type from the projection. Note that there can // be no bound variables in this type because the "self type" // does not have any regions in it. - let output_ty = self.resolve_vars_if_possible(&predicate.ty); + let output_ty = self.resolve_vars_if_possible(predicate.ty); debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty); Some(output_ty) } @@ -704,7 +706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { astconv.ast_ty_to_ty(&output); } - let result = ty::Binder::bind(self.tcx.mk_fn_sig( + let result = ty::Binder::dummy(self.tcx.mk_fn_sig( supplied_arguments, self.tcx.ty_error(), decl.c_variadic, @@ -723,12 +725,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &hir::Body<'_>, bound_sig: ty::PolyFnSig<'tcx>, ) -> ClosureSignatures<'tcx> { - let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, &bound_sig); + let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id, bound_sig); let liberated_sig = self.inh.normalize_associated_types_in( body.value.span, body.value.hir_id, self.param_env, - &liberated_sig, + liberated_sig, ); ClosureSignatures { bound_sig, liberated_sig } } diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 6da3ecde32..0f5f0ab026 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -606,7 +606,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Uncertain or unimplemented. Ok(None) => { if trait_pred.def_id() == unsize_did { - let trait_pred = self.resolve_vars_if_possible(&trait_pred); + let trait_pred = self.resolve_vars_if_possible(trait_pred); let self_ty = trait_pred.skip_binder().self_ty(); let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); @@ -732,7 +732,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let InferOk { value: a_sig, mut obligations } = - self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig); + self.normalize_associated_types_in_as_infer_ok(self.cause.span, a_sig); let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig); let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( @@ -973,8 +973,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { // The signature must match. - let a_sig = self.normalize_associated_types_in(new.span, &a_sig); - let b_sig = self.normalize_associated_types_in(new.span, &b_sig); + let a_sig = self.normalize_associated_types_in(new.span, a_sig); + let b_sig = self.normalize_associated_types_in(new.span, b_sig); let sig = self .at(cause, self.param_env) .trace(prev_ty, new_ty) @@ -1490,7 +1490,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { *sp, &format!( "return type inferred to be `{}` here", - fcx.resolve_vars_if_possible(&expected) + fcx.resolve_vars_if_possible(expected) ), ); } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 4acc7451a2..bb324d0d8b 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -224,11 +224,11 @@ fn compare_predicate_entailment<'tcx>( let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, - &ty::Binder::bind(impl_m_own_bounds.predicates), + ty::Binder::bind(impl_m_own_bounds.predicates), ); for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate); + traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate); inh.register_predicates(obligations); inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate)); @@ -253,17 +253,17 @@ fn compare_predicate_entailment<'tcx>( let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, - &tcx.fn_sig(impl_m.def_id), + tcx.fn_sig(impl_m.def_id), ); let impl_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &impl_sig); + inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); - let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, &tcx.fn_sig(trait_m.def_id)); + let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id)); let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs); let trait_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &trait_sig); + inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -494,12 +494,11 @@ fn compare_self_type<'tcx>( ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.types.self_param, }; - let self_arg_ty = tcx.fn_sig(method.def_id).input(0).skip_binder(); + let self_arg_ty = tcx.fn_sig(method.def_id).input(0); let param_env = ty::ParamEnv::reveal_all(); tcx.infer_ctxt().enter(|infcx| { - let self_arg_ty = - tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(self_arg_ty)); + let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok(); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { ExplicitSelf::ByValue => "self".to_owned(), @@ -968,12 +967,12 @@ crate fn compare_const_impl<'tcx>( // There is no "body" here, so just pass dummy id. let impl_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, &impl_ty); + inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, impl_ty); debug!("compare_const_impl: impl_ty={:?}", impl_ty); let trait_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, &trait_ty); + inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, trait_ty); debug!("compare_const_impl: trait_ty={:?}", trait_ty); @@ -1136,7 +1135,7 @@ fn compare_type_predicate_entailment<'tcx>( for predicate in impl_ty_own_bounds.predicates { let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate); + traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate); inh.register_predicates(obligations); inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate)); @@ -1261,7 +1260,7 @@ pub fn check_type_bounds<'tcx>( &mut selcx, normalize_param_env, normalize_cause.clone(), - &obligation.predicate, + obligation.predicate, ); debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 241803fab1..2728e03171 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -360,14 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option { - if let Some(stripped) = s.strip_prefix(old) { - Some(new.to_string() + stripped) - } else { - None - } - } - /// This function is used to determine potential "simple" improvements or users' errors and /// provide them useful help. For example: /// @@ -398,6 +390,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } + let replace_prefix = |s: &str, old: &str, new: &str| { + s.strip_prefix(old).map(|stripped| new.to_string() + stripped) + }; + let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp); @@ -413,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(&src, "b\"", "\"") { + if let Some(src) = replace_prefix(&src, "b\"", "\"") { return Some(( sp, "consider removing the leading `b`", @@ -427,7 +423,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(&src, "\"", "b\"") { + if let Some(src) = replace_prefix(&src, "\"", "b\"") { return Some(( sp, "consider adding a leading `b`", @@ -552,11 +548,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(&src, "&", "") { + if let Some(src) = src.strip_prefix('&') { return Some(( sp, "consider removing the borrow", - src, + src.to_string(), Applicability::MachineApplicable, )); } @@ -588,22 +584,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let new_prefix = "&mut ".to_owned() + derefs; match mutbl_a { hir::Mutability::Mut => { - if let Some(s) = - self.replace_prefix(&src, "&mut ", &new_prefix) - { - Some((s, Applicability::MachineApplicable)) - } else { - None - } + replace_prefix(&src, "&mut ", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)) } hir::Mutability::Not => { - if let Some(s) = - self.replace_prefix(&src, "&", &new_prefix) - { - Some((s, Applicability::Unspecified)) - } else { - None - } + replace_prefix(&src, "&", &new_prefix) + .map(|s| (s, Applicability::Unspecified)) } } } @@ -611,22 +597,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let new_prefix = "&".to_owned() + derefs; match mutbl_a { hir::Mutability::Mut => { - if let Some(s) = - self.replace_prefix(&src, "&mut ", &new_prefix) - { - Some((s, Applicability::MachineApplicable)) - } else { - None - } + replace_prefix(&src, "&mut ", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)) } hir::Mutability::Not => { - if let Some(s) = - self.replace_prefix(&src, "&", &new_prefix) - { - Some((s, Applicability::MachineApplicable)) - } else { - None - } + replace_prefix(&src, "&", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)) } } } @@ -810,10 +786,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // can be given the suggestion "u32::from(x) > y" rather than // "x > y.try_into().unwrap()". let lhs_expr_and_src = expected_ty_expr.and_then(|expr| { - match self.tcx.sess.source_map().span_to_snippet(expr.span).ok() { - Some(src) => Some((expr, src)), - None => None, - } + self.tcx + .sess + .source_map() + .span_to_snippet(expr.span) + .ok() + .map(|src| (expr, src)) }); let (span, msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) = (lhs_expr_and_src, exp_to_found_is_fallible) diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 5650b2cdd3..ad675f1e38 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -366,8 +366,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { // Anonymizing the LBRs is necessary to solve (Issue #59497). // After we do so, it should be totally fine to skip the binders. - let anon_a = self.tcx.anonymize_late_bound_regions(&a); - let anon_b = self.tcx.anonymize_late_bound_regions(&b); + let anon_a = self.tcx.anonymize_late_bound_regions(a); + let anon_b = self.tcx.anonymize_late_bound_regions(b); self.relate(anon_a.skip_binder(), anon_b.skip_binder())?; Ok(a) diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs index fd6fe1406c..5a5fc893d6 100644 --- a/compiler/rustc_typeck/src/check/expectation.rs +++ b/compiler/rustc_typeck/src/check/expectation.rs @@ -83,9 +83,9 @@ impl<'a, 'tcx> Expectation<'tcx> { fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { match self { NoExpectation => NoExpectation, - ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), - ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), - ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), + ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)), + ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)), + ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)), } } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index af19ad08c1..ec0e039b5d 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -22,7 +22,6 @@ use crate::type_error_struct; use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; use rustc_ast as ast; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; @@ -40,6 +39,7 @@ use rustc_middle::ty::Ty; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{AdtKind, Visibility}; use rustc_span::hygiene::DesugaringKind; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_trait_selection::traits::{self, ObligationCauseCode}; @@ -494,7 +494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( expr.span, infer::LateBoundRegionConversionTime::FnCall, - &fn_sig.input(i), + fn_sig.input(i), ) .0; self.require_type_is_sized_deferred( @@ -514,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .replace_bound_vars_with_fresh_vars( expr.span, infer::LateBoundRegionConversionTime::FnCall, - &fn_sig.output(), + fn_sig.output(), ) .0; self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); @@ -963,9 +963,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. let t_cast = self.to_ty_saving_user_provided_ty(t); - let t_cast = self.resolve_vars_if_possible(&t_cast); + let t_cast = self.resolve_vars_if_possible(t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); - let t_cast = self.resolve_vars_if_possible(&t_cast); + let t_cast = self.resolve_vars_if_possible(t_cast); // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { @@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|f| { self.normalize_associated_types_in( expr.span, - &f.ty(self.tcx, substs), + f.ty(self.tcx, substs), ) }) .collect(); @@ -1248,7 +1248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if no_accessible_remaining_fields { self.report_no_accessible_fields(adt_ty, span); } else { - self.report_missing_field(adt_ty, span, remaining_fields); + self.report_missing_fields(adt_ty, span, remaining_fields); } } @@ -1279,7 +1279,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// error: aborting due to previous error /// ``` - fn report_missing_field( + fn report_missing_fields( &self, adt_ty: Ty<'tcx>, span: Span, @@ -1441,18 +1441,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: Symbol, skip: Vec, ) -> Option { - let names = variant.fields.iter().filter_map(|field| { - // ignore already set fields and private fields from non-local crates - if skip.iter().any(|&x| x == field.ident.name) - || (!variant.def_id.is_local() && field.vis != Visibility::Public) - { - None - } else { - Some(&field.ident.name) - } - }); + let names = variant + .fields + .iter() + .filter_map(|field| { + // ignore already set fields and private fields from non-local crates + if skip.iter().any(|&x| x == field.ident.name) + || (!variant.def_id.is_local() && field.vis != Visibility::Public) + { + None + } else { + Some(field.ident.name) + } + }) + .collect::>(); - find_best_match_for_name(names, field, None) + find_best_match_for_name(&names, field, None) } fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec { @@ -1571,7 +1575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) { let output_ty = match self.infcx.get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; let mut add_label = true; @@ -1925,7 +1929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr } => { self.check_expr_asm_operand(expr, true); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 0bb7b464f1..41a403a010 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1,5 +1,6 @@ use crate::astconv::{ - AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, + AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + GenericArgCountResult, PathSeg, }; use crate::check::callee::{self, DeferredCallResolution}; use crate::check::method::{self, MethodCallee, SelfSource}; @@ -87,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If `ty` is a type variable, see whether we already know what it is. - ty = self.resolve_vars_if_possible(&ty); + ty = self.resolve_vars_if_possible(ty); if !ty.has_infer_types_or_consts() { debug!("resolve_vars_with_obligations: ty={:?}", ty); return ty; @@ -98,7 +99,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // indirect dependencies that don't seem worth tracking // precisely. self.select_obligations_where_possible(false, |_| {}); - ty = self.resolve_vars_if_possible(&ty); + ty = self.resolve_vars_if_possible(ty); debug!("resolve_vars_with_obligations: ty={:?}", ty); ty @@ -133,12 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[inline] pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { - debug!( - "write_ty({:?}, {:?}) in fcx {}", - id, - self.resolve_vars_if_possible(&ty), - self.tag() - ); + debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag()); self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); if ty.references_error() { @@ -194,7 +190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { user_self_ty: None, // not relevant here }; - self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( method.def_id, user_substs, )) @@ -239,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { - let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, )); @@ -325,13 +321,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Basically whenever we are converting from a type scheme into /// the fn body space, we always want to normalize associated /// types as well. This function combines the two. - fn instantiate_type_scheme(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T + fn instantiate_type_scheme(&self, span: Span, substs: SubstsRef<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { + debug!("instantiate_type_scheme(value={:?}, substs={:?})", value, substs); let value = value.subst(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &value); - debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); + let result = self.normalize_associated_types_in(span, value); + debug!("instantiate_type_scheme = {:?}", result); result } @@ -346,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bounds = self.tcx.predicates_of(def_id); let spans: Vec = bounds.predicates.iter().map(|(_, span)| *span).collect(); let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result); + let result = self.normalize_associated_types_in(span, result); debug!( "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", bounds, substs, result, spans, @@ -360,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn instantiate_opaque_types_from_value>( &self, parent_id: hir::HirId, - value: &T, + value: T, value_span: Span, ) -> T { let parent_def_id = self.tcx.hir().local_def_id(parent_id); @@ -388,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { value } - pub(in super::super) fn normalize_associated_types_in(&self, span: Span, value: &T) -> T + pub(in super::super) fn normalize_associated_types_in(&self, span: Span, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -398,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn normalize_associated_types_in_as_infer_ok( &self, span: Span, - value: &T, + value: T, ) -> InferOk<'tcx, T> where T: TypeFoldable<'tcx>, @@ -467,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); if Self::can_contain_user_lifetime_bounds(ty) { - let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); + let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty)); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); } @@ -767,12 +764,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .pending_obligations() .into_iter() .filter_map(move |obligation| { - match obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Projection(data) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) + Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation)) } ty::PredicateAtom::Trait(data, _) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) + Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation)) } ty::PredicateAtom::Subtype(..) => None, ty::PredicateAtom::RegionOutlives(..) => None, @@ -850,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Record all the argument types, with the substitutions // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) + Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()) }) .unwrap_or_default(); debug!( @@ -1203,7 +1201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Res::Local(hid) = res { let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); + let ty = self.normalize_associated_types_in(span, ty); self.write_ty(hir_id, ty); return (ty, res); } @@ -1298,76 +1296,108 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; - let substs = self_ctor_substs.unwrap_or_else(|| { - AstConv::create_substs_for_generic_args( - tcx, - def_id, - &[][..], - has_self, - self_ty, - arg_count, - // Provide the generic args, and whether types should be inferred. - |def_id| { - if let Some(&PathSeg(_, index)) = - path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) - { - // If we've encountered an `impl Trait`-related error, we're just - // going to infer the arguments for better error messages. - if !infer_args_for_err.contains(&index) { - // Check whether the user has provided generic arguments. - if let Some(ref data) = segments[index].args { - return (Some(data), segments[index].infer_args); - } + struct CreateCtorSubstsContext<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + span: Span, + path_segs: &'a [PathSeg], + infer_args_for_err: &'a FxHashSet, + segments: &'a [hir::PathSegment<'a>], + } + impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> { + fn args_for_def_id( + &mut self, + def_id: DefId, + ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { + if let Some(&PathSeg(_, index)) = + self.path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) + { + // If we've encountered an `impl Trait`-related error, we're just + // going to infer the arguments for better error messages. + if !self.infer_args_for_err.contains(&index) { + // Check whether the user has provided generic arguments. + if let Some(ref data) = self.segments[index].args { + return (Some(data), self.segments[index].infer_args); } - return (None, segments[index].infer_args); } + return (None, self.segments[index].infer_args); + } - (None, true) - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { + (None, true) + } + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx> { + match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self, lt, Some(param)).into() + AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.to_ty(ty).into() + self.fcx.to_ty(ty).into() } (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.const_arg_to_const(&ct.value, param.def_id).into() + self.fcx.const_arg_to_const(&ct.value, param.def_id).into() } _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { - match param.kind { - GenericParamDefKind::Lifetime => { - self.re_infer(Some(param), span).unwrap().into() - } - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // If we have a default, then we it doesn't matter that we're not - // inferring the type arguments: we provide the default where any - // is missing. - let default = tcx.type_of(param.def_id); - self.normalize_ty( - span, - default.subst_spanned(tcx, substs.unwrap(), Some(span)), + } + } + + fn inferred_kind( + &mut self, + substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + infer_args: bool, + ) -> subst::GenericArg<'tcx> { + let tcx = self.fcx.tcx(); + match param.kind { + GenericParamDefKind::Lifetime => { + self.fcx.re_infer(Some(param), self.span).unwrap().into() + } + GenericParamDefKind::Type { has_default, .. } => { + if !infer_args && has_default { + // If we have a default, then we it doesn't matter that we're not + // inferring the type arguments: we provide the default where any + // is missing. + let default = tcx.type_of(param.def_id); + self.fcx + .normalize_ty( + self.span, + default.subst_spanned(tcx, substs.unwrap(), Some(self.span)), ) .into() - } else { - // If no type arguments were provided, we have to infer them. - // This case also occurs as a result of some malformed input, e.g. - // a lifetime argument being given instead of a type parameter. - // Using inference instead of `Error` gives better error messages. - self.var_for_def(span, param) - } - } - GenericParamDefKind::Const => { - // FIXME(const_generics:defaults) - // No const parameters were provided, we have to infer them. - self.var_for_def(span, param) + } else { + // If no type arguments were provided, we have to infer them. + // This case also occurs as a result of some malformed input, e.g. + // a lifetime argument being given instead of a type parameter. + // Using inference instead of `Error` gives better error messages. + self.fcx.var_for_def(self.span, param) } } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // No const parameters were provided, we have to infer them. + self.fcx.var_for_def(self.span, param) + } + } + } + } + + let substs = self_ctor_substs.unwrap_or_else(|| { + AstConv::create_substs_for_generic_args( + tcx, + def_id, + &[][..], + has_self, + self_ty, + arg_count, + &mut CreateCtorSubstsContext { + fcx: self, + span, + path_segs: &path_segs, + infer_args_for_err: &infer_args_for_err, + segments, }, ) }); @@ -1381,7 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Substitute the values for the type parameters into the type of // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); + let ty_substituted = self.instantiate_type_scheme(span, &substs, ty); if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { // In the case of `Foo::method` and `>::method`, if `method` @@ -1391,7 +1421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This also occurs for an enum variant on a type alias. let ty = tcx.type_of(impl_def_id); - let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); + let impl_ty = self.instantiate_type_scheme(span, &substs, ty); match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index a820661d84..333bda00db 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -261,9 +261,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // is the missing argument of type `()`? let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() + self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit() } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() + self.resolve_vars_if_possible(fn_inputs[0]).is_unit() } else { false }; @@ -384,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::FnDef(..) => { let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); + let ptr_ty = self.resolve_vars_if_possible(ptr_ty); variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); } _ => {} @@ -927,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|&(i, checked_ty, _)| (i, checked_ty)) .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) .flat_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); // We walk the argument type because the argument's type could have // been `Option`, but the `FulfillmentError` references `T`. if ty.walk().any(|arg| arg == predicate.self_ty().into()) { @@ -989,7 +989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // from `typeck-default-trait-impl-assoc-type.rs`. } else { let ty = AstConv::ast_ty_to_ty(self, hir_ty); - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); if ty == predicate.self_ty() { error.obligation.cause.make_mut().span = hir_ty.span; } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 72c3b233ed..f635e0b6f9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( span, infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), - &poly_trait_ref, + poly_trait_ref, ); let item_substs = >::create_substs_for_associated_item( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index a8ad9f4fdf..17dbf989d6 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -73,8 +73,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return false, }; - let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; - let sig = self.normalize_associated_types_in(expr.span, &sig); + let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig).0; + let sig = self.normalize_associated_types_in(expr.span, sig); if self.can_coerce(sig.output(), expected) { let (mut sugg_call, applicability) = if sig.inputs().is_empty() { (String::new(), Applicability::MachineApplicable) diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index af552389de..825ebc19fa 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -59,16 +59,13 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { let o_ty = self.fcx.to_ty(&ty); let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { - self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) + self.fcx.instantiate_opaque_types_from_value(self.parent_id, o_ty, ty.span) } else { o_ty }; - let c_ty = self - .fcx - .inh - .infcx - .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); + let c_ty = + self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(revealed_ty)); debug!( "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", ty.hir_id, o_ty, revealed_ty, c_ty diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 293a995887..91708465b3 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { }); if let Some(yield_data) = live_across_yield { - let ty = self.fcx.resolve_vars_if_possible(&ty); + let ty = self.fcx.resolve_vars_if_possible(ty); debug!( "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}", expr, scope, ty, self.expr_count, yield_data.span @@ -120,7 +120,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { self.expr_count, expr.map(|e| e.span) ); - let ty = self.fcx.resolve_vars_if_possible(&ty); + let ty = self.fcx.resolve_vars_if_possible(ty); if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { @@ -179,14 +179,15 @@ pub fn resolve_interior<'a, 'tcx>( .filter_map(|mut cause| { // Erase regions and canonicalize late-bound regions to deduplicate as many types as we // can. - let erased = fcx.tcx.erase_regions(&cause.ty); + let erased = fcx.tcx.erase_regions(cause.ty); if captured_tys.insert(erased) { // Replace all regions inside the generator interior with late bound regions. // Note that each region slot in the types gets a new fresh late bound region, // which means that none of the regions inside relate to any other, even if // typeck had previously found constraints that would cause them to be related. - let folded = fcx.tcx.fold_regions(&erased, &mut false, |_, current_depth| { - let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter))); + let folded = fcx.tcx.fold_regions(erased, &mut false, |_, current_depth| { + let br = ty::BoundRegion { kind: ty::BrAnon(counter) }; + let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br)); counter += 1; r }); @@ -204,7 +205,8 @@ pub fn resolve_interior<'a, 'tcx>( let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list)); // Store the generator types and spans into the typeck results for this generator. - visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = type_causes; + visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = + ty::Binder::bind(type_causes); debug!( "types in generator after region replacement {:?}, span = {:?}", @@ -246,6 +248,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { Guard::If(ref e) => { self.visit_expr(e); } + Guard::IfLet(ref pat, ref e) => { + self.visit_pat(pat); + self.visit_expr(e); + } } let mut scope_var_ids = diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 7e580485c3..0011a3fc71 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -156,7 +156,7 @@ impl Inherited<'a, 'tcx> { span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, - value: &T, + value: T, ) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index f40a250200..c3b0fc60b9 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::spec::abi::Abi; @@ -23,10 +23,7 @@ fn equate_intrinsic_type<'tcx>( it: &hir::ForeignItem<'_>, def_id: DefId, n_tps: usize, - abi: Abi, - safety: hir::Unsafety, - inputs: Vec>, - output: Ty<'tcx>, + sig: ty::PolyFnSig<'tcx>, ) { match it.kind { hir::ForeignItemKind::Fn(..) => {} @@ -53,13 +50,7 @@ fn equate_intrinsic_type<'tcx>( return; } - let fty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( - inputs.into_iter(), - output, - false, - safety, - abi, - ))); + let fty = tcx.mk_fn_ptr(sig); let cause = ObligationCause::new(it.span, it.hir_id, ObligationCauseCode::IntrinsicType); require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty); } @@ -116,13 +107,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { - let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let region = tcx + .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrAnon(0) })); + let env_region = + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv })); let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - ( - tcx.mk_ref(tcx.mk_region(env_region), ty::TypeAndMut { ty: va_list_ty, mutbl }), - va_list_ty, - ) + (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) }) }; @@ -286,6 +276,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool) } + sym::const_allocate => { + (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) + } + sym::ptr_offset_from => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) } @@ -316,12 +310,12 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; + let br = ty::BoundRegion { kind: ty::BrAnon(0) }; ( 1, - vec![tcx.mk_imm_ref( - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))), - param(0), - )], + vec![ + tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0)), + ], tcx.mk_projection(discriminant_def_id, tcx.mk_substs([param(0).into()].iter())), ) } @@ -376,7 +370,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { }; (n_tps, inputs, output, unsafety) }; - equate_intrinsic_type(tcx, it, def_id, n_tps, Abi::RustIntrinsic, unsafety, inputs, output) + let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic); + let sig = ty::Binder::bind(sig); + equate_intrinsic_type(tcx, it, def_id, n_tps, sig) } /// Type-check `extern "platform-intrinsic" { ... }` functions. @@ -462,14 +458,13 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) } }; - equate_intrinsic_type( - tcx, - it, - def_id, - n_tps, - Abi::PlatformIntrinsic, - hir::Unsafety::Unsafe, - inputs, + let sig = tcx.mk_fn_sig( + inputs.into_iter(), output, - ) + false, + hir::Unsafety::Unsafe, + Abi::PlatformIntrinsic, + ); + let sig = ty::Binder::dummy(sig); + equate_intrinsic_type(tcx, it, def_id, n_tps, sig) } diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index fd2700b85e..8ef723d590 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -1,6 +1,6 @@ use super::{probe, MethodCallee}; -use crate::astconv::AstConv; +use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt}; use crate::check::{callee, FnCtxt}; use crate::hir::def_id::DefId; use crate::hir::GenericArg; @@ -10,7 +10,7 @@ use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::subst::{self, Subst, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty}; use rustc_span::Span; use rustc_trait_selection::traits; @@ -90,8 +90,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // traits, no trait system method can be called before this point because they // could alter our Self-type, except for normalizing the receiver from the // signature (which is also done during probing). - let method_sig_rcvr = - self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]); + let method_sig_rcvr = self.normalize_associated_types_in(self.span, method_sig.inputs()[0]); debug!( "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}", self_ty, method_sig_rcvr, method_sig, method_predicates @@ -99,7 +98,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs); let (method_sig, method_predicates) = - self.normalize_associated_types_in(self.span, &(method_sig, method_predicates)); + self.normalize_associated_types_in(self.span, (method_sig, method_predicates)); // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(&pick); @@ -229,7 +228,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty); let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id); let upcast_trait_ref = - this.replace_bound_vars_with_fresh_vars(&upcast_poly_trait_ref); + this.replace_bound_vars_with_fresh_vars(upcast_poly_trait_ref); debug!( "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}", original_poly_trait_ref, upcast_trait_ref, trait_def_id @@ -249,10 +248,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.fresh_substs_for_item(self.span, trait_def_id) } - probe::WhereClausePick(ref poly_trait_ref) => { + probe::WhereClausePick(poly_trait_ref) => { // Where clauses can have bound regions in them. We need to instantiate // those to convert from a poly-trait-ref to a trait-ref. - self.replace_bound_vars_with_fresh_vars(&poly_trait_ref).substs + self.replace_bound_vars_with_fresh_vars(poly_trait_ref).substs } } } @@ -307,6 +306,52 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // parameters from the type and those from the method. assert_eq!(generics.parent_count, parent_substs.len()); + struct MethodSubstsCtxt<'a, 'tcx> { + cfcx: &'a ConfirmContext<'a, 'tcx>, + pick: &'a probe::Pick<'tcx>, + seg: &'a hir::PathSegment<'a>, + } + impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> { + fn args_for_def_id( + &mut self, + def_id: DefId, + ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { + if def_id == self.pick.item.def_id { + if let Some(ref data) = self.seg.args { + return (Some(data), false); + } + } + (None, false) + } + + fn provided_kind( + &mut self, + param: &ty::GenericParamDef, + arg: &GenericArg<'_>, + ) -> subst::GenericArg<'tcx> { + match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + AstConv::ast_region_to_region(self.cfcx.fcx, lt, Some(param)).into() + } + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.cfcx.to_ty(ty).into() + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.cfcx.const_arg_to_const(&ct.value, param.def_id).into() + } + _ => unreachable!(), + } + } + + fn inferred_kind( + &mut self, + _substs: Option<&[subst::GenericArg<'tcx>]>, + param: &ty::GenericParamDef, + _infer_args: bool, + ) -> subst::GenericArg<'tcx> { + self.cfcx.var_for_def(self.cfcx.span, param) + } + } AstConv::create_substs_for_generic_args( self.tcx, pick.item.def_id, @@ -314,29 +359,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { false, None, arg_count_correct, - // Provide the generic args, and whether types should be inferred. - |def_id| { - // The last component of the returned tuple here is unimportant. - if def_id == pick.item.def_id { - if let Some(ref data) = seg.args { - return (Some(data), false); - } - } - (None, false) - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into() - } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(), - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.const_arg_to_const(&ct.value, param.def_id).into() - } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |_, param, _| self.var_for_def(self.span, param), + &mut MethodSubstsCtxt { cfcx: self, pick, seg }, ) } @@ -400,7 +423,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // N.B., instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let method_sig = self.replace_bound_vars_with_fresh_vars(&sig); + let method_sig = self.replace_bound_vars_with_fresh_vars(sig); debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); let method_sig = method_sig.subst(self.tcx, all_substs); @@ -506,7 +529,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { upcast_trait_refs.into_iter().next().unwrap() } - fn replace_bound_vars_with_fresh_vars(&self, value: &ty::Binder) -> T + fn replace_bound_vars_with_fresh_vars(&self, value: ty::Binder) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 84bc3979e1..8e13b37469 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scope: ProbeScope, ) -> probe::PickResult<'tcx> { let mode = probe::Mode::MethodCall; - let self_ty = self.resolve_vars_if_possible(&self_ty); + let self_ty = self.resolve_vars_if_possible(self_ty); self.probe_for_name( span, mode, @@ -358,11 +358,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `instantiate_type_scheme` can normalize associated types that // may reference those regions. let fn_sig = tcx.fn_sig(def_id); - let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, &fn_sig).0; + let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0; let fn_sig = fn_sig.subst(self.tcx, substs); let InferOk { value, obligations: o } = - self.normalize_associated_types_in_as_infer_ok(span, &fn_sig); + self.normalize_associated_types_in_as_infer_ok(span, fn_sig); let fn_sig = { obligations.extend(o); value @@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); let InferOk { value, obligations: o } = - self.normalize_associated_types_in_as_infer_ok(span, &bounds); + self.normalize_associated_types_in_as_infer_ok(span, bounds); let bounds = { obligations.extend(o); value diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 713b24e583..891dd8b2f0 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -9,7 +9,6 @@ use crate::hir::def::DefKind; use crate::hir::def_id::DefId; use rustc_ast as ast; -use rustc_ast::util::lev_distance::{find_best_match_for_name, lev_distance}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; @@ -25,9 +24,9 @@ use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{ self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; -use rustc_session::config::nightly_options; use rustc_session::lint; use rustc_span::def_id::LocalDefId; +use rustc_span::lev_distance::{find_best_match_for_name, lev_distance}; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::autoderef::{self, Autoderef}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -309,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut orig_values = OriginalQueryValues::default(); let param_env_and_self_ty = self.infcx.canonicalize_query( - &ParamEnvAnd { param_env: self.param_env, value: self_ty }, + ParamEnvAnd { param_env: self.param_env, value: self_ty }, &mut orig_values, ); @@ -731,7 +730,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); let selcx = &mut traits::SelectionContext::new(self.fcx); let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } = - traits::normalize(selcx, self.param_env, cause, &xform_tys); + traits::normalize(selcx, self.param_env, cause, xform_tys); debug!( "assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}", xform_self_ty, xform_ret_ty @@ -766,16 +765,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ) }); - // It is illegal to invoke a method on a trait instance that - // refers to the `Self` type. An error will be reported by - // `enforce_object_limitations()` if the method refers to the - // `Self` type anywhere other than the receiver. Here, we use - // a substitution that replaces `Self` with the object type - // itself. Hence, a `&self` method will wind up with an - // argument type like `&Trait`. + // It is illegal to invoke a method on a trait instance that refers to + // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error + // will be reported by `object_safety.rs` if the method refers to the + // `Self` type anywhere other than the receiver. Here, we use a + // substitution that replaces `Self` with the object type itself. Hence, + // a `&self` method will wind up with an argument type like `&Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { - let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); + let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); @@ -821,7 +819,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { - let trait_ref = this.erase_late_bound_regions(&poly_trait_ref); + let trait_ref = this.erase_late_bound_regions(poly_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs); @@ -912,7 +910,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let substs = self.fresh_substs_for_item(self.span, method.def_id); let fty = fty.subst(self.tcx, substs); let (fty, _) = - self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, &fty); + self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty); if let Some(self_ty) = self_ty { if self @@ -943,7 +941,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // For trait aliases, assume all super-traits are relevant. let bounds = iter::once(trait_ref.to_poly_trait_ref()); self.elaborate_bounds(bounds, |this, new_trait_ref, item| { - let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); + let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); @@ -1272,7 +1270,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.tcx.def_path_str(stable_pick.item.def_id), )); - if nightly_options::is_nightly_build() { + if self.tcx.sess.is_nightly_build() { for (candidate, feature) in unstable_candidates { diag.help(&format!( "add `#![feature({})]` to the crate attributes to enable `{}`", @@ -1356,7 +1354,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let impl_bounds = self.tcx.predicates_of(impl_def_id); let impl_bounds = impl_bounds.instantiate(self.tcx, substs); let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = - traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds); + traits::normalize(selcx, self.param_env, cause.clone(), impl_bounds); // Convert the bounds into obligations. let impl_obligations = @@ -1367,7 +1365,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .chain(ref_obligations.iter().cloned()); // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations { - let o = self.resolve_vars_if_possible(&o); + let o = self.resolve_vars_if_possible(o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; possibly_unsatisfied_predicates.push((o.predicate, None)); @@ -1393,25 +1391,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { for obligation in impl_source.borrow_nested_obligations() { // Determine exactly which obligation wasn't met, so // that we can give more context in the error. - if !self.predicate_may_hold(&obligation) { - let o = self.resolve_vars_if_possible(obligation); + if !self.predicate_may_hold(obligation) { + let nested_predicate = + self.resolve_vars_if_possible(obligation.predicate); let predicate = - self.resolve_vars_if_possible(&predicate); - let p = if predicate == o.predicate { + self.resolve_vars_if_possible(predicate); + let p = if predicate == nested_predicate { // Avoid "`MyStruct: Foo` which is required by // `MyStruct: Foo`" in E0599. None } else { Some(predicate) }; - possibly_unsatisfied_predicates.push((o.predicate, p)); + possibly_unsatisfied_predicates + .push((nested_predicate, p)); } } } _ => { // Some nested subobligation of this predicate // failed. - let predicate = self.resolve_vars_if_possible(&predicate); + let predicate = self.resolve_vars_if_possible(predicate); possibly_unsatisfied_predicates.push((predicate, None)); } } @@ -1428,7 +1428,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Evaluate those obligations to see if they might possibly hold. for o in sub_obligations { - let o = self.resolve_vars_if_possible(&o); + let o = self.resolve_vars_if_possible(o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; possibly_unsatisfied_predicates.push((o.predicate, None)); @@ -1439,7 +1439,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, probe.xform_ret_ty) { - let xform_ret_ty = self.resolve_vars_if_possible(&xform_ret_ty); + let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty); debug!( "comparing return_ty {:?} with xform ret ty {:?}", return_ty, probe.xform_ret_ty @@ -1537,8 +1537,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Ok(None) } else { let best_name = { - let names = applicable_close_candidates.iter().map(|cand| &cand.ident.name); - find_best_match_for_name(names, self.method_name.unwrap().name, None) + let names = applicable_close_candidates + .iter() + .map(|cand| cand.ident.name) + .collect::>(); + find_best_match_for_name(&names, self.method_name.unwrap().name, None) } .unwrap(); Ok(applicable_close_candidates @@ -1605,7 +1608,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Erase any late-bound regions from the method and substitute // in the values from the substitution. - let xform_fn_sig = self.erase_late_bound_regions(&fn_sig); + let xform_fn_sig = self.erase_late_bound_regions(fn_sig); if generics.params.is_empty() { xform_fn_sig.subst(self.tcx, substs) @@ -1673,7 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// region got replaced with the same variable, which requires a bit more coordination /// and/or tracking the substitution and /// so forth. - fn erase_late_bound_regions(&self, value: &ty::Binder) -> T + fn erase_late_bound_regions(&self, value: ty::Binder) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 46afe4892d..3bf41981ef 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -2,7 +2,6 @@ //! found or is otherwise invalid. use crate::check::FnCtxt; -use rustc_ast::util::lev_distance; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -13,10 +12,12 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::hir::map as hir_map; +use rustc_middle::ty::fast_reject::simplify_type; use rustc_middle::ty::print::with_crate_prefix; use rustc_middle::ty::{ self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; +use rustc_span::lev_distance; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -248,7 +249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) => { let tcx = self.tcx; - let actual = self.resolve_vars_if_possible(&rcvr_ty); + let actual = self.resolve_vars_if_possible(rcvr_ty); let ty_str = self.ty_to_string(actual); let is_method = mode == Mode::MethodCall; let item_kind = if is_method { @@ -619,8 +620,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _) => { - for pred in preds.skip_binder() { - match pred { + for pred in preds.iter() { + match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { bound_spans.push((def_span(tr.def_id), msg.clone())) } @@ -673,9 +674,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter_map(|(pred, parent_pred)| { format_pred(*pred).map(|(p, self_ty)| match parent_pred { - None => format!("`{}`", p), + None => format!("`{}`", &p), Some(parent_pred) => match format_pred(*parent_pred) { - None => format!("`{}`", p), + None => format!("`{}`", &p), Some((parent_p, _)) => { collect_type_param_suggestions(self_ty, parent_pred, &p); format!("`{}`\nwhich is required by `{}`", p, parent_p) @@ -744,7 +745,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if actual.is_enum() { let adt_def = actual.ty_adt_def().expect("enum is not an ADT"); if let Some(suggestion) = lev_distance::find_best_match_for_name( - adt_def.variants.iter().map(|s| &s.ident.name), + &adt_def.variants.iter().map(|s| s.ident.name).collect::>(), item_name.name, None, ) { @@ -870,7 +871,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, ) { let output_ty = match self.infcx.get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true); @@ -1074,19 +1075,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "items from traits can only be used if the trait is implemented and in scope" }); + let candidates_len = candidates.len(); let message = |action| { format!( "the following {traits_define} an item `{name}`, perhaps you need to {action} \ {one_of_them}:", traits_define = - if candidates.len() == 1 { "trait defines" } else { "traits define" }, + if candidates_len == 1 { "trait defines" } else { "traits define" }, action = action, - one_of_them = if candidates.len() == 1 { "it" } else { "one of them" }, + one_of_them = if candidates_len == 1 { "it" } else { "one of them" }, name = item_name, ) }; // Obtain the span for `param` and use it for a structured suggestion. - let mut suggested = false; if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_typeck_results) { @@ -1147,7 +1148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - suggested = true; + return; } Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., bounds, _), @@ -1167,45 +1168,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), Applicability::MaybeIncorrect, ); - suggested = true; + return; } _ => {} } } } - if !suggested { - let action = if let Some(param) = param_type { - format!("restrict type parameter `{}` with", param) - } else { - // FIXME: it might only need to be imported into scope, not implemented. - "implement".to_string() - }; - let mut use_note = true; - if let [trait_info] = &candidates[..] { - if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) { - err.span_note( - self.tcx.sess.source_map().guess_head_span(span), - &format!( - "`{}` defines an item `{}`, perhaps you need to {} it", - self.tcx.def_path_str(trait_info.def_id), - item_name, - action - ), - ); - use_note = false + let (potential_candidates, explicitly_negative) = if param_type.is_some() { + // FIXME: Even though negative bounds are not implemented, we could maybe handle + // cases where a positive bound implies a negative impl. + (candidates, Vec::new()) + } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, true) { + let mut potential_candidates = Vec::new(); + let mut explicitly_negative = Vec::new(); + for candidate in candidates { + // Check if there's a negative impl of `candidate` for `rcvr_ty` + if self + .tcx + .all_impls(candidate.def_id) + .filter(|imp_did| { + self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative + }) + .any(|imp_did| { + let imp = self.tcx.impl_trait_ref(imp_did).unwrap(); + let imp_simp = simplify_type(self.tcx, imp.self_ty(), true); + imp_simp.map(|s| s == simp_rcvr_ty).unwrap_or(false) + }) + { + explicitly_negative.push(candidate); + } else { + potential_candidates.push(candidate); } } - if use_note { + (potential_candidates, explicitly_negative) + } else { + // We don't know enough about `recv_ty` to make proper suggestions. + (candidates, Vec::new()) + }; + + let action = if let Some(param) = param_type { + format!("restrict type parameter `{}` with", param) + } else { + // FIXME: it might only need to be imported into scope, not implemented. + "implement".to_string() + }; + match &potential_candidates[..] { + [] => {} + [trait_info] if trait_info.def_id.is_local() => { + let span = self.tcx.hir().span_if_local(trait_info.def_id).unwrap(); + err.span_note( + self.tcx.sess.source_map().guess_head_span(span), + &format!( + "`{}` defines an item `{}`, perhaps you need to {} it", + self.tcx.def_path_str(trait_info.def_id), + item_name, + action + ), + ); + } + trait_infos => { let mut msg = message(action); - for (i, trait_info) in candidates.iter().enumerate() { + for (i, trait_info) in trait_infos.iter().enumerate() { msg.push_str(&format!( "\ncandidate #{}: `{}`", i + 1, self.tcx.def_path_str(trait_info.def_id), )); } - err.note(&msg[..]); + err.note(&msg); + } + } + match &explicitly_negative[..] { + [] => {} + [trait_info] => { + let msg = format!( + "the trait `{}` defines an item `{}`, but is explicitely unimplemented", + self.tcx.def_path_str(trait_info.def_id), + item_name + ); + err.note(&msg); + } + trait_infos => { + let mut msg = format!( + "the following traits define an item `{}`, but are explicitely unimplemented:", + item_name + ); + for trait_info in trait_infos { + msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id))); + } + err.note(&msg); } } } @@ -1308,6 +1360,8 @@ fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits }); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 169ad0df3a..8177b363a5 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -108,7 +108,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{HirIdMap, Node}; +use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -270,7 +270,7 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { /// If this `DefId` is a "primary tables entry", returns /// `Some((body_id, header, decl))` with information about -/// it's body-id, fn-header and fn-decl (if any). Otherwise, +/// its body-id, fn-header and fn-decl (if any). Otherwise, /// returns `None`. /// /// If this function returns `Some`, then `typeck_results(def_id)` will @@ -362,7 +362,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet(tcx: TyCtxt<'tcx>, val: &T) -> T +fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: T) -> T where T: TypeFoldable<'tcx>, { @@ -510,15 +510,15 @@ fn typeck_with_fallback<'tcx>( check_abi(tcx, span, fn_sig.abi()); // Compute the fty from point of view of inside the fn. - let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), &fn_sig); + let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = inh.normalize_associated_types_in( body.value.span, body_id.hir_id, param_env, - &fn_sig, + fn_sig, ); - let fn_sig = fixup_opaque_types(tcx, &fn_sig); + let fn_sig = fixup_opaque_types(tcx, fn_sig); let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; fcx @@ -543,11 +543,11 @@ fn typeck_with_fallback<'tcx>( _ => fallback(), }); - let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); + let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); let revealed_ty = if tcx.features().impl_trait_in_bindings { - fcx.instantiate_opaque_types_from_value(id, &expected_type, body.value.span) + fcx.instantiate_opaque_types_from_value(id, expected_type, body.value.span) } else { expected_type }; @@ -1134,6 +1134,7 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { } fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} + fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {} } fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 247b525672..9ab056c0d7 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -503,8 +503,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.tcx.has_typeck_results(def_id) { return false; } - // We're emitting a suggestion, so we can just ignore regions - let fn_sig = self.tcx.fn_sig(def_id).skip_binder(); + // FIXME: Instead of exiting early when encountering bound vars in + // the function signature, consider keeping the binder here and + // propagating it downwards. + let fn_sig = if let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() { + fn_sig + } else { + return false; + }; let other_ty = if let FnDef(def_id, _) = *other_ty.kind() { if !self.tcx.has_typeck_results(def_id) { @@ -660,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method.sig.output() } Err(()) => { - let actual = self.resolve_vars_if_possible(&operand_ty); + let actual = self.resolve_vars_if_possible(operand_ty); if !actual.references_error() { let mut err = struct_span_err!( self.tcx.sess, @@ -983,7 +989,7 @@ fn suggest_constraining_param( struct TypeParamVisitor<'tcx>(Vec>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if let ty::Param(_) = ty.kind() { self.0.push(ty); } diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index fa7898f03e..5fc573a57a 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1,7 +1,6 @@ use crate::check::FnCtxt; use rustc_ast as ast; -use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -13,6 +12,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable}; use rustc_span::hygiene::DesugaringKind; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; use rustc_trait_selection::traits::{ObligationCause, Pattern}; @@ -463,7 +463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Now that we know the types can be unified we find the unified type // and use it to type the entire expression. - let common_type = self.resolve_vars_if_possible(&lhs_ty.or(rhs_ty).unwrap_or(expected)); + let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected)); // Subtyping doesn't matter here, as the value is some kind of scalar. let demand_eqtype = |x, y| { @@ -1174,7 +1174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut unmentioned_err = None; - // Report an error if incorrect number of the fields were specified. + // Report an error if an incorrect number of fields was specified. if adt.is_union() { if fields.len() != 1 { tcx.sess @@ -1185,12 +1185,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - let no_accessible_unmentioned_fields = unmentioned_fields - .iter() - .find(|(field, _)| { - field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) - }) - .is_none(); + let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| { + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + }); if no_accessible_unmentioned_fields { unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); @@ -1302,8 +1299,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); if plural == "" { - let input = unmentioned_fields.iter().map(|(_, field)| &field.name); - let suggested_name = find_best_match_for_name(input, ident.name, None); + let input = + unmentioned_fields.iter().map(|(_, field)| field.name).collect::>(); + let suggested_name = find_best_match_for_name(&input, ident.name, None); if let Some(suggested_name) = suggested_name { err.span_suggestion( ident.span, diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 7b31b9f391..b8b98cef76 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -229,7 +229,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// of b will be `&.i32` and then `*b` will require that `` be bigger than the let and /// the `*b` expression, so we will effectively resolve `` to be the block B. pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_vars_if_possible(&unresolved_ty) + self.resolve_vars_if_possible(unresolved_ty) } /// Try to resolve the type for the given node. diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index e9dfef718f..0f084c5c11 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -39,10 +39,21 @@ use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::UpvarRegion; -use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; +use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind}; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc_span::sym; use rustc_span::{Span, Symbol}; -use std::collections::hash_map::Entry; + +/// Describe the relationship between the paths of two places +/// eg: +/// - `foo` is ancestor of `foo.bar.baz` +/// - `foo.bar.baz` is an descendant of `foo.bar` +/// - `foo.bar` and `foo.baz` are divergent +enum PlaceAncestryRelation { + Ancestor, + Descendant, + Divergent, +} impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { @@ -111,40 +122,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; - if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { - let mut closure_captures: FxIndexMap = - FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default()); - for (&var_hir_id, _) in upvars.iter() { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: closure_def_id.expect_local(), - }; - debug!("seed upvar_id {:?}", upvar_id); - // Adding the upvar Id to the list of Upvars, which will be added - // to the map for the closure at the end of the for loop. - closure_captures.insert(var_hir_id, upvar_id); - - let capture_kind = match capture_clause { - hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None), - hir::CaptureBy::Ref => { - let origin = UpvarRegion(upvar_id, span); - let upvar_region = self.next_region_var(origin); - let upvar_borrow = - ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; - ty::UpvarCapture::ByRef(upvar_borrow) - } - }; + let local_def_id = closure_def_id.expect_local(); - self.typeck_results.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); - } - // Add the vector of upvars to the map keyed with the closure id. - // This gives us an easier access to them without having to call - // tcx.upvars again.. - if !closure_captures.is_empty() { - self.typeck_results - .borrow_mut() - .closure_captures - .insert(closure_def_id, closure_captures); + let mut capture_information: FxIndexMap, ty::CaptureInfo<'tcx>> = + Default::default(); + if !self.tcx.features().capture_disjoint_fields { + if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { + for (&var_hir_id, _) in upvars.iter() { + let place = self.place_for_root_variable(local_def_id, var_hir_id); + + debug!("seed place {:?}", place); + + let upvar_id = ty::UpvarId::new(var_hir_id, local_def_id); + let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span); + let info = ty::CaptureInfo { expr_id: None, capture_kind }; + + capture_information.insert(place, info); + } } } @@ -153,9 +147,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut delegate = InferBorrowKind { fcx: self, closure_def_id, + closure_span: span, + capture_clause, current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM, current_origin: None, - adjust_upvar_captures: ty::UpvarCaptureMap::default(), + capture_information, }; euv::ExprUseVisitor::new( &mut delegate, @@ -166,6 +162,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .consume_body(body); + debug!( + "For closure={:?}, capture_information={:#?}", + closure_def_id, delegate.capture_information + ); + self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span); + if let Some(closure_substs) = infer_kind { // Unify the (as yet unbound) type variable in the closure // substs with the kind we inferred. @@ -182,7 +184,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - self.typeck_results.borrow_mut().upvar_capture_map.extend(delegate.adjust_upvar_captures); + self.compute_min_captures(closure_def_id, delegate); + self.log_closure_min_capture_info(closure_def_id, span); + + self.min_captures_to_closure_captures_bridge(closure_def_id); // Now that we've analyzed the closure, we know how each // variable is borrowed, and we know what traits the closure @@ -197,7 +202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inference algorithm will reject it). // Equate the type variables for the upvars with the actual types. - let final_upvar_tys = self.final_upvar_tys(closure_hir_id); + let final_upvar_tys = self.final_upvar_tys(closure_def_id); debug!( "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", closure_hir_id, substs, final_upvar_tys @@ -217,39 +222,325 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Returns a list of `Ty`s for each upvar. - fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec> { + fn final_upvar_tys(&self, closure_id: DefId) -> Vec> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the // local crate or were inlined into it along with some function. // This may change if abstract return types of some sort are // implemented. let tcx = self.tcx; - let closure_def_id = tcx.hir().local_def_id(closure_id); - - tcx.upvars_mentioned(closure_def_id) - .iter() - .flat_map(|upvars| { - upvars.iter().map(|(&var_hir_id, _)| { - let upvar_ty = self.node_ty(var_hir_id); - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: closure_def_id, - }; - let capture = self.typeck_results.borrow().upvar_capture(upvar_id); - debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture); + self.typeck_results + .borrow() + .closure_min_captures_flattened(closure_id) + .map(|captured_place| { + let upvar_ty = captured_place.place.ty(); + let capture = captured_place.info.capture_kind; - match capture { - ty::UpvarCapture::ByValue(_) => upvar_ty, - ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( - borrow.region, - ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, - ), - } - }) + debug!( + "place={:?} upvar_ty={:?} capture={:?}", + captured_place.place, upvar_ty, capture + ); + + match capture { + ty::UpvarCapture::ByValue(_) => upvar_ty, + ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( + borrow.region, + ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, + ), + } }) .collect() } + + /// Bridge for closure analysis + /// ---------------------------- + /// + /// For closure with DefId `c`, the bridge converts structures required for supporting RFC 2229, + /// to structures currently used in the compiler for handling closure captures. + /// + /// For example the following structure will be converted: + /// + /// closure_min_captures + /// foo -> [ {foo.x, ImmBorrow}, {foo.y, MutBorrow} ] + /// bar -> [ {bar.z, ByValue}, {bar.q, MutBorrow} ] + /// + /// to + /// + /// 1. closure_captures + /// foo -> UpvarId(foo, c), bar -> UpvarId(bar, c) + /// + /// 2. upvar_capture_map + /// UpvarId(foo,c) -> MutBorrow, UpvarId(bar, c) -> ByValue + fn min_captures_to_closure_captures_bridge(&self, closure_def_id: DefId) { + let mut closure_captures: FxIndexMap = Default::default(); + let mut upvar_capture_map = ty::UpvarCaptureMap::default(); + + if let Some(min_captures) = + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id) + { + for (var_hir_id, min_list) in min_captures.iter() { + for captured_place in min_list { + let place = &captured_place.place; + let capture_info = captured_place.info; + + let upvar_id = match place.base { + PlaceBase::Upvar(upvar_id) => upvar_id, + base => bug!("Expected upvar, found={:?}", base), + }; + + assert_eq!(upvar_id.var_path.hir_id, *var_hir_id); + assert_eq!(upvar_id.closure_expr_id, closure_def_id.expect_local()); + + closure_captures.insert(*var_hir_id, upvar_id); + + let new_capture_kind = + if let Some(capture_kind) = upvar_capture_map.get(&upvar_id) { + // upvar_capture_map only stores the UpvarCapture (CaptureKind), + // so we create a fake capture info with no expression. + let fake_capture_info = + ty::CaptureInfo { expr_id: None, capture_kind: *capture_kind }; + determine_capture_info(fake_capture_info, capture_info).capture_kind + } else { + capture_info.capture_kind + }; + upvar_capture_map.insert(upvar_id, new_capture_kind); + } + } + } + debug!("For closure_def_id={:?}, closure_captures={:#?}", closure_def_id, closure_captures); + debug!( + "For closure_def_id={:?}, upvar_capture_map={:#?}", + closure_def_id, upvar_capture_map + ); + + if !closure_captures.is_empty() { + self.typeck_results + .borrow_mut() + .closure_captures + .insert(closure_def_id, closure_captures); + + self.typeck_results.borrow_mut().upvar_capture_map.extend(upvar_capture_map); + } + } + + /// Analyzes the information collected by `InferBorrowKind` to compute the min number of + /// Places (and corresponding capture kind) that we need to keep track of to support all + /// the required captured paths. + /// + /// Eg: + /// ```rust,no_run + /// struct Point { x: i32, y: i32 } + /// + /// let s: String; // hir_id_s + /// let mut p: Point; // his_id_p + /// let c = || { + /// println!("{}", s); // L1 + /// p.x += 10; // L2 + /// println!("{}" , p.y) // L3 + /// println!("{}", p) // L4 + /// drop(s); // L5 + /// }; + /// ``` + /// and let hir_id_L1..5 be the expressions pointing to use of a captured variable on + /// the lines L1..5 respectively. + /// + /// InferBorrowKind results in a structure like this: + /// + /// ``` + /// { + /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L5, ByValue), + /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> (hir_id_L2, ByRef(MutBorrow)) + /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> (hir_id_L3, ByRef(ImmutBorrow)) + /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L4, ByRef(ImmutBorrow)) + /// ``` + /// + /// After the min capture analysis, we get: + /// ``` + /// { + /// hir_id_s -> [ + /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L4, ByValue) + /// ], + /// hir_id_p -> [ + /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L2, ByRef(MutBorrow)), + /// ], + /// ``` + fn compute_min_captures( + &self, + closure_def_id: DefId, + inferred_info: InferBorrowKind<'_, 'tcx>, + ) { + let mut root_var_min_capture_list: ty::RootVariableMinCaptureList<'_> = Default::default(); + + for (place, capture_info) in inferred_info.capture_information.into_iter() { + let var_hir_id = match place.base { + PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + base => bug!("Expected upvar, found={:?}", base), + }; + + // Arrays are captured in entirety, drop Index projections and projections + // after Index projections. + let first_index_projection = + place.projections.split(|proj| ProjectionKind::Index == proj.kind).next(); + let place = Place { + base_ty: place.base_ty, + base: place.base, + projections: first_index_projection.map_or(Vec::new(), |p| p.to_vec()), + }; + + let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) { + None => { + let min_cap_list = vec![ty::CapturedPlace { place: place, info: capture_info }]; + root_var_min_capture_list.insert(var_hir_id, min_cap_list); + continue; + } + Some(min_cap_list) => min_cap_list, + }; + + // Go through each entry in the current list of min_captures + // - if ancestor is found, update it's capture kind to account for current place's + // capture information. + // + // - if descendant is found, remove it from the list, and update the current place's + // capture information to account for the descendants's capture kind. + // + // We can never be in a case where the list contains both an ancestor and a descendant + // Also there can only be ancestor but in case of descendants there might be + // multiple. + + let mut descendant_found = false; + let mut updated_capture_info = capture_info; + min_cap_list.retain(|possible_descendant| { + match determine_place_ancestry_relation(&place, &possible_descendant.place) { + // current place is ancestor of possible_descendant + PlaceAncestryRelation::Ancestor => { + descendant_found = true; + updated_capture_info = + determine_capture_info(updated_capture_info, possible_descendant.info); + false + } + + _ => true, + } + }); + + let mut ancestor_found = false; + if !descendant_found { + for possible_ancestor in min_cap_list.iter_mut() { + match determine_place_ancestry_relation(&place, &possible_ancestor.place) { + // current place is descendant of possible_ancestor + PlaceAncestryRelation::Descendant => { + ancestor_found = true; + possible_ancestor.info = + determine_capture_info(possible_ancestor.info, capture_info); + + // Only one ancestor of the current place will be in the list. + break; + } + _ => {} + } + } + } + + // Only need to insert when we don't have an ancestor in the existing min capture list + if !ancestor_found { + let captured_place = + ty::CapturedPlace { place: place.clone(), info: updated_capture_info }; + min_cap_list.push(captured_place); + } + } + + debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list); + + if !root_var_min_capture_list.is_empty() { + self.typeck_results + .borrow_mut() + .closure_min_captures + .insert(closure_def_id, root_var_min_capture_list); + } + } + + fn init_capture_kind( + &self, + capture_clause: hir::CaptureBy, + upvar_id: ty::UpvarId, + closure_span: Span, + ) -> ty::UpvarCapture<'tcx> { + match capture_clause { + hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None), + hir::CaptureBy::Ref => { + let origin = UpvarRegion(upvar_id, closure_span); + let upvar_region = self.next_region_var(origin); + let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; + ty::UpvarCapture::ByRef(upvar_borrow) + } + } + } + + fn place_for_root_variable( + &self, + closure_def_id: LocalDefId, + var_hir_id: hir::HirId, + ) -> Place<'tcx> { + let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id); + + Place { + base_ty: self.node_ty(var_hir_id), + base: PlaceBase::Upvar(upvar_id), + projections: Default::default(), + } + } + + fn should_log_capture_analysis(&self, closure_def_id: DefId) -> bool { + self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis) + } + + fn log_capture_analysis_first_pass( + &self, + closure_def_id: rustc_hir::def_id::DefId, + capture_information: &FxIndexMap, ty::CaptureInfo<'tcx>>, + closure_span: Span, + ) { + if self.should_log_capture_analysis(closure_def_id) { + let mut diag = + self.tcx.sess.struct_span_err(closure_span, "First Pass analysis includes:"); + for (place, capture_info) in capture_information { + let capture_str = construct_capture_info_string(self.tcx, place, capture_info); + let output_str = format!("Capturing {}", capture_str); + + let span = capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e)); + diag.span_note(span, &output_str); + } + diag.emit(); + } + } + + fn log_closure_min_capture_info(&self, closure_def_id: DefId, closure_span: Span) { + if self.should_log_capture_analysis(closure_def_id) { + if let Some(min_captures) = + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id) + { + let mut diag = + self.tcx.sess.struct_span_err(closure_span, "Min Capture analysis includes:"); + + for (_, min_captures_for_var) in min_captures { + for capture in min_captures_for_var { + let place = &capture.place; + let capture_info = &capture.info; + + let capture_str = + construct_capture_info_string(self.tcx, place, capture_info); + let output_str = format!("Min Capture {}", capture_str); + + let span = + capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e)); + diag.span_note(span, &output_str); + } + } + diag.emit(); + } + } + } } struct InferBorrowKind<'a, 'tcx> { @@ -258,6 +549,10 @@ struct InferBorrowKind<'a, 'tcx> { // The def-id of the closure whose kind and upvar accesses are being inferred. closure_def_id: DefId, + closure_span: Span, + + capture_clause: hir::CaptureBy, + // The kind that we have inferred that the current closure // requires. Note that we *always* infer a minimal kind, even if // we don't always *use* that in the final result (i.e., sometimes @@ -270,9 +565,31 @@ struct InferBorrowKind<'a, 'tcx> { // variable access that caused us to do so. current_origin: Option<(Span, Symbol)>, - // For each upvar that we access, we track the minimal kind of - // access we need (ref, ref mut, move, etc). - adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, + /// For each Place that is captured by the closure, we track the minimal kind of + /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access. + /// + /// Consider closure where s.str1 is captured via an ImmutableBorrow and + /// s.str2 via a MutableBorrow + /// + /// ```rust,no_run + /// struct SomeStruct { str1: String, str2: String } + /// + /// // Assume that the HirId for the variable definition is `V1` + /// let mut s = SomeStruct { str1: format!("s1"), str2: format!("s2") } + /// + /// let fix_s = |new_s2| { + /// // Assume that the HirId for the expression `s.str1` is `E1` + /// println!("Updating SomeStruct with str1=", s.str1); + /// // Assume that the HirId for the expression `*s.str2` is `E2` + /// s.str2 = new_s2; + /// }; + /// ``` + /// + /// For closure `fix_s`, (at a high level) the map contains + /// + /// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow } + /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow } + capture_information: FxIndexMap, ty::CaptureInfo<'tcx>>, } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { @@ -314,26 +631,15 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { var_name(tcx, upvar_id.var_path.hir_id), ); - let new_capture = ty::UpvarCapture::ByValue(Some(usage_span)); - match self.adjust_upvar_captures.entry(upvar_id) { - Entry::Occupied(mut e) => { - match e.get() { - // We always overwrite `ByRef`, since we require - // that the upvar be available by value. - // - // If we had a previous by-value usage without a specific - // span, use ours instead. Otherwise, keep the first span - // we encountered, since there isn't an obviously better one. - ty::UpvarCapture::ByRef(_) | ty::UpvarCapture::ByValue(None) => { - e.insert(new_capture); - } - _ => {} - } - } - Entry::Vacant(e) => { - e.insert(new_capture); - } - } + let capture_info = ty::CaptureInfo { + expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)), + }; + + let curr_info = self.capture_information[&place_with_id.place]; + let updated_info = determine_capture_info(curr_info, capture_info); + + self.capture_information[&place_with_id.place] = updated_info; } /// Indicates that `place_with_id` is being directly mutated (e.g., assigned @@ -349,7 +655,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id ); - if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + if let PlaceBase::Upvar(_) = place_with_id.place.base { let mut borrow_kind = ty::MutBorrow; for pointer_ty in place_with_id.place.deref_tys() { match pointer_ty.kind() { @@ -363,7 +669,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { _ => (), } } - self.adjust_upvar_deref(upvar_id, self.fcx.tcx.hir().span(diag_expr_id), borrow_kind); + self.adjust_upvar_deref(place_with_id, diag_expr_id, borrow_kind); } } @@ -377,24 +683,20 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id ); - if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + if let PlaceBase::Upvar(_) = place_with_id.place.base { if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { // Raw pointers don't inherit mutability. return; } // for a borrowed pointer to be unique, its base must be unique - self.adjust_upvar_deref( - upvar_id, - self.fcx.tcx.hir().span(diag_expr_id), - ty::UniqueImmBorrow, - ); + self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow); } } fn adjust_upvar_deref( &mut self, - upvar_id: ty::UpvarId, - place_span: Span, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, borrow_kind: ty::BorrowKind, ) { assert!(match borrow_kind { @@ -411,15 +713,16 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { // upvar, then we need to modify the // borrow_kind of the upvar to make sure it // is inferred to mutable if necessary - self.adjust_upvar_borrow_kind(upvar_id, borrow_kind); + self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind); - // also need to be in an FnMut closure since this is not an ImmBorrow - self.adjust_closure_kind( - upvar_id.closure_expr_id, - ty::ClosureKind::FnMut, - place_span, - var_name(tcx, upvar_id.var_path.hir_id), - ); + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + self.adjust_closure_kind( + upvar_id.closure_expr_id, + ty::ClosureKind::FnMut, + tcx.hir().span(diag_expr_id), + var_name(tcx, upvar_id.var_path.hir_id), + ); + } } /// We infer the borrow_kind with which to borrow upvars in a stack closure. @@ -427,37 +730,34 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { /// moving from left to right as needed (but never right to left). /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. - fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) { - let upvar_capture = self - .adjust_upvar_captures - .get(&upvar_id) - .copied() - .unwrap_or_else(|| self.fcx.typeck_results.borrow().upvar_capture(upvar_id)); + fn adjust_upvar_borrow_kind( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + kind: ty::BorrowKind, + ) { + let curr_capture_info = self.capture_information[&place_with_id.place]; + debug!( - "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", - upvar_id, upvar_capture, kind + "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})", + place_with_id, diag_expr_id, curr_capture_info, kind ); - match upvar_capture { - ty::UpvarCapture::ByValue(_) => { - // Upvar is already by-value, the strongest criteria. - } - ty::UpvarCapture::ByRef(mut upvar_borrow) => { - match (upvar_borrow.kind, kind) { - // Take RHS: - (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow) - | (ty::UniqueImmBorrow, ty::MutBorrow) => { - upvar_borrow.kind = kind; - self.adjust_upvar_captures - .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow)); - } - // Take LHS: - (ty::ImmBorrow, ty::ImmBorrow) - | (ty::UniqueImmBorrow, ty::ImmBorrow | ty::UniqueImmBorrow) - | (ty::MutBorrow, _) => {} - } - } - } + if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind { + // It's already captured by value, we don't need to do anything here + return; + } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind { + // Use the same region as the current capture information + // Doesn't matter since only one of the UpvarBorrow will be used. + let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region }; + + let capture_info = ty::CaptureInfo { + expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow), + }; + let updated_info = determine_capture_info(curr_capture_info, capture_info); + self.capture_information[&place_with_id.place] = updated_info; + }; } fn adjust_closure_kind( @@ -501,6 +801,28 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } } } + + fn init_capture_info_for_place( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + ) { + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id); + + let capture_kind = + self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span); + + let expr_id = Some(diag_expr_id); + let capture_info = ty::CaptureInfo { expr_id, capture_kind }; + + debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info); + + self.capture_information.insert(place_with_id.place.clone(), capture_info); + } else { + debug!("Not upvar: {:?}", place_with_id); + } + } } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { @@ -514,7 +836,11 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { "consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})", place_with_id, diag_expr_id, mode ); - self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id, mode); + if !self.capture_information.contains_key(&place_with_id.place) { + self.init_capture_info_for_place(place_with_id, diag_expr_id); + } + + self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id, mode); } fn borrow( @@ -528,6 +854,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id, bk ); + if !self.capture_information.contains_key(&place_with_id.place) { + self.init_capture_info_for_place(place_with_id, diag_expr_id); + } + match bk { ty::ImmBorrow => {} ty::UniqueImmBorrow => { @@ -541,10 +871,175 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id); + + if !self.capture_information.contains_key(&assignee_place.place) { + self.init_capture_info_for_place(assignee_place, diag_expr_id); + } + self.adjust_upvar_borrow_kind_for_mut(assignee_place, diag_expr_id); } } +fn construct_capture_info_string( + tcx: TyCtxt<'_>, + place: &Place<'tcx>, + capture_info: &ty::CaptureInfo<'tcx>, +) -> String { + let variable_name = match place.base { + PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(), + _ => bug!("Capture_information should only contain upvars"), + }; + + let mut projections_str = String::new(); + for (i, item) in place.projections.iter().enumerate() { + let proj = match item.kind { + ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b), + ProjectionKind::Deref => String::from("Deref"), + ProjectionKind::Index => String::from("Index"), + ProjectionKind::Subslice => String::from("Subslice"), + }; + if i != 0 { + projections_str.push_str(","); + } + projections_str.push_str(proj.as_str()); + } + + let capture_kind_str = match capture_info.capture_kind { + ty::UpvarCapture::ByValue(_) => "ByValue".into(), + ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind), + }; + format!("{}[{}] -> {}", variable_name, projections_str, capture_kind_str) +} + fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol { tcx.hir().name(var_hir_id) } + +/// Helper function to determine if we need to escalate CaptureKind from +/// CaptureInfo A to B and returns the escalated CaptureInfo. +/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way) +/// +/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based +/// on the `CaptureInfo` containing an associated expression id. +/// +/// If both the CaptureKind and Expression are considered to be equivalent, +/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize +/// expressions reported back to the user as part of diagnostics based on which appears earlier +/// in the closure. This can be acheived simply by calling +/// `determine_capture_info(existing_info, current_info)`. This works out because the +/// expressions that occur earlier in the closure body than the current expression are processed before. +/// Consider the following example +/// ```rust,no_run +/// struct Point { x: i32, y: i32 } +/// let mut p: Point { x: 10, y: 10 }; +/// +/// let c = || { +/// p.x += 10; +/// // ^ E1 ^ +/// // ... +/// // More code +/// // ... +/// p.x += 10; // E2 +/// // ^ E2 ^ +/// }; +/// ``` +/// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow), +/// and both have an expression associated, however for diagnostics we prefer reporting +/// `E1` since it appears earlier in the closure body. When `E2` is being processed we +/// would've already handled `E1`, and have an existing capture_information for it. +/// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return +/// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics. +fn determine_capture_info( + capture_info_a: ty::CaptureInfo<'tcx>, + capture_info_b: ty::CaptureInfo<'tcx>, +) -> ty::CaptureInfo<'tcx> { + // If the capture kind is equivalent then, we don't need to escalate and can compare the + // expressions. + let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { + (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => { + // We don't need to worry about the spans being ignored here. + // + // The expr_id in capture_info corresponds to the span that is stored within + // ByValue(span) and therefore it gets handled with priortizing based on + // expressions below. + true + } + (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { + ref_a.kind == ref_b.kind + } + (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false, + }; + + if eq_capture_kind { + match (capture_info_a.expr_id, capture_info_b.expr_id) { + (Some(_), _) | (None, None) => capture_info_a, + (None, Some(_)) => capture_info_b, + } + } else { + // We select the CaptureKind which ranks higher based the following priority order: + // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow + match (capture_info_a.capture_kind, capture_info_b.capture_kind) { + (ty::UpvarCapture::ByValue(_), _) => capture_info_a, + (_, ty::UpvarCapture::ByValue(_)) => capture_info_b, + (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { + match (ref_a.kind, ref_b.kind) { + // Take LHS: + (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow) + | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a, + + // Take RHS: + (ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow) + | (ty::UniqueImmBorrow, ty::MutBorrow) => capture_info_b, + + (ty::ImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::UniqueImmBorrow) + | (ty::MutBorrow, ty::MutBorrow) => { + bug!("Expected unequal capture kinds"); + } + } + } + } + } +} + +/// Determines the Ancestry relationship of Place A relative to Place B +/// +/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B +/// `PlaceAncestryRelation::Descendant` implies Place A is descendant of Place B +/// `PlaceAncestryRelation::Divergent` implies neither of them is the ancestor of the other. +fn determine_place_ancestry_relation( + place_a: &Place<'tcx>, + place_b: &Place<'tcx>, +) -> PlaceAncestryRelation { + // If Place A and Place B, don't start off from the same root variable, they are divergent. + if place_a.base != place_b.base { + return PlaceAncestryRelation::Divergent; + } + + // Assume of length of projections_a = n + let projections_a = &place_a.projections; + + // Assume of length of projections_b = m + let projections_b = &place_b.projections; + + let mut same_initial_projections = true; + + for (proj_a, proj_b) in projections_a.iter().zip(projections_b.iter()) { + if proj_a != proj_b { + same_initial_projections = false; + break; + } + } + + if same_initial_projections { + // First min(n, m) projections are the same + // Select Ancestor/Descendant + if projections_b.len() >= projections_a.len() { + PlaceAncestryRelation::Ancestor + } else { + PlaceAncestryRelation::Descendant + } + } else { + PlaceAncestryRelation::Divergent + } +} diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 1e27357ce4..c09f8cce5b 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -156,8 +156,9 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { hir::ItemKind::Const(ref ty, ..) => { check_item_type(tcx, item.hir_id, ty.span, false); } - hir::ItemKind::ForeignMod(ref module) => { - for it in module.items.iter() { + hir::ItemKind::ForeignMod { items, .. } => { + for it in items.iter() { + let it = tcx.hir().foreign_item(it.id); match it.kind { hir::ForeignItemKind::Fn(ref decl, ..) => { check_item_fn(tcx, it.hir_id, it.ident, it.span, decl) @@ -329,7 +330,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { ), ) .note("the only supported types are integers, `bool` and `char`") - .note("more complex types are supported with `#[feature(const_generics)]`") + .help("more complex types are supported with `#[feature(const_generics)]`") .emit() } }; @@ -403,12 +404,12 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in(span, &ty); + let ty = fcx.normalize_associated_types_in(span, ty); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { let sig = fcx.tcx.fn_sig(item.def_id); - let sig = fcx.normalize_associated_types_in(span, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( tcx, @@ -427,7 +428,7 @@ fn check_associated_item( } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in(span, &ty); + let ty = fcx.normalize_associated_types_in(span, ty); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -480,7 +481,7 @@ fn check_type_defn<'tcx, F>( let needs_drop_copy = || { packed && { let ty = variant.fields.last().unwrap().ty; - let ty = fcx.tcx.erase_regions(&ty); + let ty = fcx.tcx.erase_regions(ty); if ty.needs_infer() { fcx_tcx .sess @@ -592,7 +593,7 @@ fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span debug!("check_associated_type_bounds: bounds={:?}", bounds); let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let normalized_bound = fcx.normalize_associated_types_in(span, &bound); + let normalized_bound = fcx.normalize_associated_types_in(span, bound); traits::wf::predicate_obligations( fcx, fcx.param_env, @@ -618,7 +619,7 @@ fn check_item_fn( for_id(tcx, item_id, span).with_fcx(|fcx, tcx| { let def_id = fcx.tcx.hir().local_def_id(item_id); let sig = fcx.tcx.fn_sig(def_id); - let sig = fcx.normalize_associated_types_in(span, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); let mut implied_bounds = vec![]; check_fn_or_method( tcx, @@ -638,7 +639,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo for_id(tcx, item_id, ty_span).with_fcx(|fcx, tcx| { let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in(ty_span, &ty); + let item_ty = fcx.normalize_associated_types_in(ty_span, ty); let mut forbid_unsized = true; if allow_foreign_ty { @@ -680,7 +681,7 @@ fn check_impl<'tcx>( // won't hold). let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); let trait_ref = - fcx.normalize_associated_types_in(ast_trait_ref.path.span, &trait_ref); + fcx.normalize_associated_types_in(ast_trait_ref.path.span, trait_ref); let obligations = traits::wf::trait_obligations( fcx, fcx.param_env, @@ -695,7 +696,7 @@ fn check_impl<'tcx>( } None => { let self_ty = fcx.tcx.type_of(item_def_id); - let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty); + let self_ty = fcx.normalize_associated_types_in(item.span, self_ty); fcx.register_wf_obligation( self_ty.into(), ast_self_ty.span, @@ -800,18 +801,20 @@ fn check_where_clauses<'tcx, 'fcx>( params: FxHashSet, } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let ty::Param(param) = t.kind() { self.params.insert(param.index); } t.super_visit_with(self) } - fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { ControlFlow::BREAK } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Param(param) = c.val { self.params.insert(param.index); } @@ -845,7 +848,7 @@ fn check_where_clauses<'tcx, 'fcx>( // Note the subtle difference from how we handle `predicates` // below: there, we are not trying to prove those predicates // to be *true* but merely *well-formed*. - let pred = fcx.normalize_associated_types_in(sp, &pred); + let pred = fcx.normalize_associated_types_in(sp, pred); let cause = traits::ObligationCause::new(sp, fcx.body_id, traits::ItemObligation(def_id)); traits::Obligation::new(cause, fcx.param_env, pred) @@ -856,12 +859,12 @@ fn check_where_clauses<'tcx, 'fcx>( if let Some((mut return_ty, span)) = return_ty { if return_ty.has_infer_types_or_consts() { fcx.select_obligations_where_possible(false, |_| {}); - return_ty = fcx.resolve_vars_if_possible(&return_ty); + return_ty = fcx.resolve_vars_if_possible(return_ty); } check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty); } - let predicates = fcx.normalize_associated_types_in(span, &predicates); + let predicates = fcx.normalize_associated_types_in(span, predicates); debug!("check_where_clauses: predicates={:?}", predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); @@ -885,8 +888,8 @@ fn check_fn_or_method<'fcx, 'tcx>( def_id: DefId, implied_bounds: &mut Vec>, ) { - let sig = fcx.normalize_associated_types_in(span, &sig); - let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); + let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) { fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation); @@ -1063,19 +1066,19 @@ fn check_method_receiver<'fcx, 'tcx>( let span = fn_sig.decl.inputs[0].span; let sig = fcx.tcx.fn_sig(method.def_id); - let sig = fcx.normalize_associated_types_in(span, &sig); - let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig); + let sig = fcx.normalize_associated_types_in(span, sig); + let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, sig); debug!("check_method_receiver: sig={:?}", sig); - let self_ty = fcx.normalize_associated_types_in(span, &self_ty); - let self_ty = fcx.tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(self_ty)); + let self_ty = fcx.normalize_associated_types_in(span, self_ty); + let self_ty = fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_ty)); let receiver_ty = sig.inputs()[0]; - let receiver_ty = fcx.normalize_associated_types_in(span, &receiver_ty); + let receiver_ty = fcx.normalize_associated_types_in(span, receiver_ty); let receiver_ty = - fcx.tcx.liberate_late_bound_regions(method.def_id, &ty::Binder::bind(receiver_ty)); + fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(receiver_ty)); if fcx.tcx.features().arbitrary_self_types { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { @@ -1307,7 +1310,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) { let pred = obligation.predicate; // Match the existing behavior. if pred.is_global() && !pred.has_late_bound_regions() { - let pred = fcx.normalize_associated_types_in(span, &pred); + let pred = fcx.normalize_associated_types_in(span, pred); let obligation = traits::Obligation::new( traits::ObligationCause::new(span, id, traits::TrivialBound), empty_env, @@ -1343,6 +1346,10 @@ impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) { Visitor::visit_impl_item(&mut self.clone(), impl_item); } + + fn visit_foreign_item(&self, foreign_item: &'tcx hir::ForeignItem<'tcx>) { + Visitor::visit_foreign_item(&mut self.clone(), foreign_item) + } } impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { @@ -1405,8 +1412,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|field| { let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id)); - let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty); - let field_ty = self.resolve_vars_if_possible(&field_ty); + let field_ty = self.normalize_associated_types_in(field.ty.span, field_ty); + let field_ty = self.resolve_vars_if_possible(field_ty); debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty); AdtField { ty: field_ty, span: field.ty.span } }) @@ -1429,7 +1436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec> { match self.tcx.impl_trait_ref(impl_def_id) { - Some(ref trait_ref) => { + Some(trait_ref) => { // Trait impl: take implied bounds from all types that // appear in the trait reference. let trait_ref = self.normalize_associated_types_in(span, trait_ref); @@ -1439,7 +1446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => { // Inherent impl: take implied bounds from the `self` type. let self_ty = self.tcx.type_of(impl_def_id); - let self_ty = self.normalize_associated_types_in(span, &self_ty); + let self_ty = self.normalize_associated_types_in(span, self_ty); vec![self_ty] } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 9c22459e27..7c9cfe69fc 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -55,6 +55,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), } wbcx.visit_body(body); + wbcx.visit_min_capture_map(); wbcx.visit_upvar_capture_map(); wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); @@ -88,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /////////////////////////////////////////////////////////////////////////// -// The Writeback context. This visitor walks the AST, checking the +// The Writeback context. This visitor walks the HIR, checking the // fn-specific typeck results to find references to types or regions. It // resolves those regions to remove inference variables and writes the // final result back into the master typeck results in the tcx. Here and @@ -139,7 +140,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { match e.kind { hir::ExprKind::Unary(hir::UnOp::UnNeg | hir::UnOp::UnNot, ref inner) => { let inner_ty = self.fcx.node_ty(inner.hir_id); - let inner_ty = self.fcx.resolve_vars_if_possible(&inner_ty); + let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty); if inner_ty.is_scalar() { let mut typeck_results = self.fcx.typeck_results.borrow_mut(); @@ -150,10 +151,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { hir::ExprKind::Binary(ref op, ref lhs, ref rhs) | hir::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => { let lhs_ty = self.fcx.node_ty(lhs.hir_id); - let lhs_ty = self.fcx.resolve_vars_if_possible(&lhs_ty); + let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty); let rhs_ty = self.fcx.node_ty(rhs.hir_id); - let rhs_ty = self.fcx.resolve_vars_if_possible(&rhs_ty); + let rhs_ty = self.fcx.resolve_vars_if_possible(rhs_ty); if lhs_ty.is_scalar() && rhs_ty.is_scalar() { let mut typeck_results = self.fcx.typeck_results.borrow_mut(); @@ -194,7 +195,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut typeck_results = self.fcx.typeck_results.borrow_mut(); // All valid indexing looks like this; might encounter non-valid indexes at this point. - let base_ty = typeck_results.expr_ty_adjusted_opt(&base).map(|t| t.kind()); + let base_ty = typeck_results + .expr_ty_adjusted_opt(&base) + .map(|t| self.fcx.resolve_vars_if_possible(t).kind()); if base_ty.is_none() { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base // that isn't in the type table. We assume more relevant errors have already been @@ -212,7 +215,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { &format!("bad index {:?} for base: `{:?}`", index, base), ) }); - let index_ty = self.fcx.resolve_vars_if_possible(&index_ty); + let index_ty = self.fcx.resolve_vars_if_possible(index_ty); if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize { // Remove the method call record @@ -316,19 +319,50 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { intravisit::walk_local(self, l); let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty; - let var_ty = self.resolve(&var_ty, &l.span); + let var_ty = self.resolve(var_ty, &l.span); self.write_ty_to_typeck_results(l.hir_id, var_ty); } fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { intravisit::walk_ty(self, hir_ty); let ty = self.fcx.node_ty(hir_ty.hir_id); - let ty = self.resolve(&ty, &hir_ty.span); + let ty = self.resolve(ty, &hir_ty.span); self.write_ty_to_typeck_results(hir_ty.hir_id, ty); } } impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { + fn visit_min_capture_map(&mut self) { + let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher( + self.fcx.typeck_results.borrow().closure_min_captures.len(), + Default::default(), + ); + for (closure_def_id, root_min_captures) in + self.fcx.typeck_results.borrow().closure_min_captures.iter() + { + let mut root_var_map_wb = ty::RootVariableMinCaptureList::with_capacity_and_hasher( + root_min_captures.len(), + Default::default(), + ); + for (var_hir_id, min_list) in root_min_captures.iter() { + let min_list_wb = min_list + .iter() + .map(|captured_place| { + let locatable = captured_place.info.expr_id.unwrap_or( + self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()), + ); + + self.resolve(captured_place.clone(), &locatable) + }) + .collect(); + root_var_map_wb.insert(*var_hir_id, min_list_wb); + } + min_captures_wb.insert(*closure_def_id, root_var_map_wb); + } + + self.typeck_results.closure_min_captures = min_captures_wb; + } + fn visit_upvar_capture_map(&mut self) { for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { @@ -435,7 +469,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_opaque_types(&mut self, span: Span) { for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() { let hir_id = self.tcx().hir().local_def_id_to_hir_id(def_id.expect_local()); - let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id); + let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id); debug_assert!(!instantiated_ty.has_escaping_bound_vars()); @@ -525,13 +559,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // Resolve the type of the node with id `node_id` let n_ty = self.fcx.node_ty(hir_id); - let n_ty = self.resolve(&n_ty, &span); + let n_ty = self.resolve(n_ty, &span); self.write_ty_to_typeck_results(hir_id, n_ty); debug!("node {:?} has type {:?}", hir_id, n_ty); // Resolve any substitutions if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) { - let substs = self.resolve(&substs, &span); + let substs = self.resolve(substs, &span); debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); assert!(!substs.needs_infer() && !substs.has_placeholders()); self.typeck_results.node_substs_mut().insert(hir_id, substs); @@ -546,7 +580,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } Some(adjustment) => { - let resolved_adjustment = self.resolve(&adjustment, &span); + let resolved_adjustment = self.resolve(adjustment, &span); debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment); } @@ -561,7 +595,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } Some(adjustment) => { - let resolved_adjustment = self.resolve(&adjustment, &span); + let resolved_adjustment = self.resolve(adjustment, &span); debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment); } @@ -573,7 +607,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (&local_id, fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() { + for (&local_id, &fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; let fn_sig = self.resolve(fn_sig, &hir_id); self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig); @@ -587,12 +621,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { for (&local_id, ftys) in fcx_typeck_results.fru_field_types().iter() { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - let ftys = self.resolve(ftys, &hir_id); + let ftys = self.resolve(ftys.clone(), &hir_id); self.typeck_results.fru_field_types_mut().insert(hir_id, ftys); } } - fn resolve(&mut self, x: &T, span: &dyn Locatable) -> T + fn resolve(&mut self, x: T, span: &dyn Locatable) -> T where T: TypeFoldable<'tcx>, { @@ -684,8 +718,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match self.infcx.fully_resolve(&t) { - Ok(t) => self.infcx.tcx.erase_regions(&t), + match self.infcx.fully_resolve(t) { + Ok(t) => self.infcx.tcx.erase_regions(t), Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_type_error(t); @@ -701,8 +735,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match self.infcx.fully_resolve(&ct) { - Ok(ct) => self.infcx.tcx.erase_regions(&ct), + match self.infcx.fully_resolve(ct) { + Ok(ct) => self.infcx.tcx.erase_regions(ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); self.report_const_error(ct); diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs index 4fda8932e2..31121ece89 100644 --- a/compiler/rustc_typeck/src/check_unused.rs +++ b/compiler/rustc_typeck/src/check_unused.rs @@ -35,6 +35,8 @@ impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } struct CheckVisitor<'tcx> { @@ -225,4 +227,6 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 373acb95c9..0c1578498b 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -44,8 +44,8 @@ struct InherentCollect<'tcx> { impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { - let ty = match item.kind { - hir::ItemKind::Impl { of_trait: None, ref self_ty, .. } => self_ty, + let (ty, assoc_items) = match item.kind { + hir::ItemKind::Impl { of_trait: None, ref self_ty, items, .. } => (self_ty, items), _ => return, }; @@ -70,6 +70,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "bool", "bool", item.span, + assoc_items, ); } ty::Char => { @@ -80,6 +81,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "char", "char", item.span, + assoc_items, ); } ty::Str => { @@ -90,6 +92,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "str", "str", item.span, + assoc_items, ); } ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => { @@ -100,6 +103,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "slice_u8", "[u8]", item.span, + assoc_items, ); } ty::Slice(_) => { @@ -110,6 +114,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "slice", "[T]", item.span, + assoc_items, ); } ty::Array(_, _) => { @@ -120,6 +125,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "array", "[T; N]", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not }) @@ -132,6 +138,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "const_slice_ptr", "*const [T]", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut }) @@ -144,6 +151,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "mut_slice_ptr", "*mut [T]", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => { @@ -154,6 +162,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "const_ptr", "*const T", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => { @@ -164,6 +173,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "mut_ptr", "*mut T", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I8) => { @@ -174,6 +184,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i8", "i8", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I16) => { @@ -184,6 +195,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i16", "i16", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I32) => { @@ -194,6 +206,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i32", "i32", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I64) => { @@ -204,6 +217,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i64", "i64", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I128) => { @@ -214,6 +228,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i128", "i128", item.span, + assoc_items, ); } ty::Int(ast::IntTy::Isize) => { @@ -224,6 +239,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "isize", "isize", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U8) => { @@ -234,6 +250,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u8", "u8", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U16) => { @@ -244,6 +261,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u16", "u16", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U32) => { @@ -254,6 +272,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u32", "u32", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U64) => { @@ -264,6 +283,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u64", "u64", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U128) => { @@ -274,6 +294,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u128", "u128", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::Usize) => { @@ -284,6 +305,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "usize", "usize", item.span, + assoc_items, ); } ty::Float(ast::FloatTy::F32) => { @@ -294,6 +316,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "f32", "f32", item.span, + assoc_items, ); } ty::Float(ast::FloatTy::F64) => { @@ -304,6 +327,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "f64", "f64", item.span, + assoc_items, ); } ty::Error(_) => {} @@ -334,6 +358,8 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } impl InherentCollect<'tcx> { @@ -367,6 +393,7 @@ impl InherentCollect<'tcx> { lang: &str, ty: &str, span: Span, + assoc_items: &[hir::ImplItemRef<'_>], ) { match (lang_def_id, lang_def_id2) { (Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => { @@ -376,6 +403,32 @@ impl InherentCollect<'tcx> { // OK } _ => { + let to_implement = if assoc_items.len() == 0 { + String::new() + } else { + let plural = assoc_items.len() > 1; + let assoc_items_kind = { + let item_types = assoc_items.iter().map(|x| x.kind); + if item_types.clone().all(|x| x == hir::AssocItemKind::Const) { + "constant" + } else if item_types + .clone() + .all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } }) + { + "method" + } else { + "associated item" + } + }; + + format!( + " to implement {} {}{}", + if plural { "these" } else { "this" }, + assoc_items_kind, + if plural { "s" } else { "" } + ) + }; + struct_span_err!( self.tcx.sess, span, @@ -385,7 +438,7 @@ impl InherentCollect<'tcx> { lang, ty ) - .span_help(span, "consider using a trait to implement these methods") + .help(&format!("consider using a trait{}", to_implement)) .emit(); } } diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index ce157f809e..50d8867432 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -1,10 +1,13 @@ +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Symbol; use rustc_trait_selection::traits::{self, SkipLeakCheck}; use smallvec::SmallVec; +use std::collections::hash_map::Entry; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); @@ -33,12 +36,9 @@ impl InherentOverlapChecker<'tcx> { } for item1 in impl_items1.in_definition_order() { - let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).any(|item2| { - // Symbols and namespace match, compare hygienically. - item1.kind.namespace() == item2.kind.namespace() - && item1.ident.normalize_to_macros_2_0() - == item2.ident.normalize_to_macros_2_0() - }); + let collision = impl_items2 + .filter_by_name_unhygienic(item1.ident.name) + .any(|item2| self.compare_hygienically(item1, item2)); if collision { return true; @@ -48,6 +48,12 @@ impl InherentOverlapChecker<'tcx> { false } + fn compare_hygienically(&self, item1: &ty::AssocItem, item2: &ty::AssocItem) -> bool { + // Symbols and namespace match, compare hygienically. + item1.kind.namespace() == item2.kind.namespace() + && item1.ident.normalize_to_macros_2_0() == item2.ident.normalize_to_macros_2_0() + } + fn check_for_common_items_in_impls( &self, impl1: DefId, @@ -58,12 +64,9 @@ impl InherentOverlapChecker<'tcx> { let impl_items2 = self.tcx.associated_items(impl2); for item1 in impl_items1.in_definition_order() { - let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).find(|item2| { - // Symbols and namespace match, compare hygienically. - item1.kind.namespace() == item2.kind.namespace() - && item1.ident.normalize_to_macros_2_0() - == item2.ident.normalize_to_macros_2_0() - }); + let collision = impl_items2 + .filter_by_name_unhygienic(item1.ident.name) + .find(|item2| self.compare_hygienically(item1, item2)); if let Some(item2) = collision { let name = item1.ident.normalize_to_macros_2_0(); @@ -134,10 +137,150 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { .map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id))) .collect::>(); - for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() { - for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] { - if self.impls_have_common_items(impl_items1, impl_items2) { - self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id); + // Perform a O(n^2) algorithm for small n, + // otherwise switch to an allocating algorithm with + // faster asymptotic runtime. + const ALLOCATING_ALGO_THRESHOLD: usize = 500; + if impls.len() < ALLOCATING_ALGO_THRESHOLD { + for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() { + for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] { + if self.impls_have_common_items(impl_items1, impl_items2) { + self.check_for_overlapping_inherent_impls( + impl1_def_id, + impl2_def_id, + ); + } + } + } + } else { + // Build a set of connected regions of impl blocks. + // Two impl blocks are regarded as connected if they share + // an item with the same unhygienic identifier. + // After we have assembled the connected regions, + // run the O(n^2) algorithm on each connected region. + // This is advantageous to running the algorithm over the + // entire graph when there are many connected regions. + + struct ConnectedRegion { + idents: SmallVec<[Symbol; 8]>, + impl_blocks: FxHashSet, + } + // Highest connected region id + let mut highest_region_id = 0; + let mut connected_region_ids = FxHashMap::default(); + let mut connected_regions = FxHashMap::default(); + + for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() { + if impl_items.len() == 0 { + continue; + } + // First obtain a list of existing connected region ids + let mut idents_to_add = SmallVec::<[Symbol; 8]>::new(); + let ids = impl_items + .in_definition_order() + .filter_map(|item| { + let entry = connected_region_ids.entry(item.ident.name); + if let Entry::Occupied(e) = &entry { + Some(*e.get()) + } else { + idents_to_add.push(item.ident.name); + None + } + }) + .collect::>(); + match ids.len() { + 0 | 1 => { + let id_to_set = if ids.len() == 0 { + // Create a new connected region + let region = ConnectedRegion { + idents: idents_to_add, + impl_blocks: std::iter::once(i).collect(), + }; + connected_regions.insert(highest_region_id, region); + (highest_region_id, highest_region_id += 1).0 + } else { + // Take the only id inside the list + let id_to_set = *ids.iter().next().unwrap(); + let region = connected_regions.get_mut(&id_to_set).unwrap(); + region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); + id_to_set + }; + let (_id, region) = connected_regions.iter().next().unwrap(); + // Update the connected region ids + for ident in region.idents.iter() { + connected_region_ids.insert(*ident, id_to_set); + } + } + _ => { + // We have multiple connected regions to merge. + // In the worst case this might add impl blocks + // one by one and can thus be O(n^2) in the size + // of the resulting final connected region, but + // this is no issue as the final step to check + // for overlaps runs in O(n^2) as well. + + // Take the smallest id from the list + let id_to_set = *ids.iter().min().unwrap(); + + // Sort the id list so that the algorithm is deterministic + let mut ids = ids.into_iter().collect::>(); + ids.sort(); + + let mut region = connected_regions.remove(&id_to_set).unwrap(); + region.idents.extend_from_slice(&idents_to_add); + region.impl_blocks.insert(i); + + for &id in ids.iter() { + if id == id_to_set { + continue; + } + let r = connected_regions.remove(&id).unwrap(); + // Update the connected region ids + for ident in r.idents.iter() { + connected_region_ids.insert(*ident, id_to_set); + } + region.idents.extend_from_slice(&r.idents); + region.impl_blocks.extend(r.impl_blocks); + } + connected_regions.insert(id_to_set, region); + } + } + } + + debug!( + "churning through {} components (sum={}, avg={}, var={}, max={})", + connected_regions.len(), + impls.len(), + impls.len() / connected_regions.len(), + { + let avg = impls.len() / connected_regions.len(); + let s = connected_regions + .iter() + .map(|r| r.1.impl_blocks.len() as isize - avg as isize) + .map(|v| v.abs() as usize) + .sum::(); + s / connected_regions.len() + }, + connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap() + ); + // List of connected regions is built. Now, run the overlap check + // for each pair of impl blocks in the same connected region. + for (_id, region) in connected_regions.into_iter() { + let mut impl_blocks = + region.impl_blocks.into_iter().collect::>(); + impl_blocks.sort(); + for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() { + let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx]; + for &impl2_items_idx in impl_blocks[(i + 1)..].iter() { + let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx]; + if self.impls_have_common_items(impl_items1, impl_items2) { + self.check_for_overlapping_inherent_impls( + impl1_def_id, + impl2_def_id, + ); + } + } } } } @@ -149,4 +292,6 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'v>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'v>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'v>) {} } diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index b2009962ab..253dcf06e0 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -244,4 +244,6 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs index b281092ea6..2d9128e7dc 100644 --- a/compiler/rustc_typeck/src/coherence/unsafety.rs +++ b/compiler/rustc_typeck/src/coherence/unsafety.rs @@ -94,4 +94,6 @@ impl ItemLikeVisitor<'v> for UnsafetyChecker<'tcx> { fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b431de9036..bc6b2037c1 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -359,8 +359,8 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx().sess, span, E0212, - "cannot extract an associated type from a higher-ranked trait bound \ - in this context" + "cannot use the associated type of a trait \ + with uninferred generic parameters" ); match self.node() { @@ -386,7 +386,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { "{}::{}", // Replace the existing lifetimes with a new named lifetime. self.tcx - .replace_late_bound_regions(&poly_trait_ref, |_| { + .replace_late_bound_regions(poly_trait_ref, |_| { self.tcx.mk_region(ty::ReEarlyBound( ty::EarlyBoundRegion { def_id: item_def_id, @@ -424,7 +424,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { format!( "{}::{}", // Erase named lt, we want `::C`, not `::C`. - self.tcx.anonymize_late_bound_regions(&poly_trait_ref).skip_binder(), + self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(), item_segment.ident ), Applicability::MaybeIncorrect, @@ -461,7 +461,7 @@ fn get_new_lifetime_name<'tcx>( .collect_referenced_late_bound_regions(&poly_trait_ref) .into_iter() .filter_map(|lt| { - if let ty::BoundRegion::BrNamed(_, name) = lt { + if let ty::BoundRegionKind::BrNamed(_, name) = lt { Some(name.as_str().to_string()) } else { None @@ -646,8 +646,9 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) { | hir::ItemKind::Use(..) | hir::ItemKind::Mod(_) | hir::ItemKind::GlobalAsm(_) => {} - hir::ItemKind::ForeignMod(ref foreign_mod) => { - for item in foreign_mod.items { + hir::ItemKind::ForeignMod { items, .. } => { + for item in items { + let item = tcx.hir().foreign_item(item.id); let def_id = tcx.hir().local_def_id(item.hir_id); tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); @@ -1368,7 +1369,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { generics.parent_count + generics.params.len() }); - let mut params: Vec<_> = opt_self.into_iter().collect(); + let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize); + + if let Some(opt_self) = opt_self { + params.push(opt_self); + } let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics); params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef { @@ -1918,10 +1923,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } else { let span = bound_pred.bounded_ty.span; let re_root_empty = tcx.lifetimes.re_root_empty; - let predicate = ty::OutlivesPredicate(ty, re_root_empty); + let predicate = ty::Binder::bind(ty::PredicateAtom::TypeOutlives( + ty::OutlivesPredicate(ty, re_root_empty), + )); predicates.insert(( - ty::PredicateAtom::TypeOutlives(predicate) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + predicate.potentially_quantified(tcx, ty::PredicateKind::ForAll), span, )); } @@ -1964,8 +1970,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); predicates.insert(( - ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + ty::Binder::bind(ty::PredicateAtom::TypeOutlives( + ty::OutlivesPredicate(ty, region), + )) + .potentially_quantified(tcx, ty::PredicateKind::ForAll), lifetime.span, )); } @@ -1982,9 +1990,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } _ => bug!(), }; - let pred = ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2)); + let pred = ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2)) + .to_predicate(icx.tcx); - (pred.potentially_quantified(icx.tcx, ty::PredicateKind::ForAll), span) + (pred, span) })) } @@ -2062,7 +2071,7 @@ fn const_evaluatable_predicates_of<'tcx>( } impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { - fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { self.preds.insert(( ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), @@ -2140,13 +2149,8 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // * It must be an associated type for this trait (*not* a // supertrait). if let ty::Projection(projection) = ty.kind() { - if projection.substs == trait_identity_substs + projection.substs == trait_identity_substs && tcx.associated_item(projection.item_def_id).container.id() == def_id - { - true - } else { - false - } } else { false } @@ -2238,7 +2242,7 @@ fn predicates_from_bound<'tcx>( hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) - .potentially_quantified(astconv.tcx(), ty::PredicateKind::ForAll); + .to_predicate(astconv.tcx()); vec![(pred, lifetime.span)] } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 61d1efc837..88ba5788b0 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -259,7 +259,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { ItemKind::Trait(..) | ItemKind::TraitAlias(..) | ItemKind::Mod(..) - | ItemKind::ForeignMod(..) + | ItemKind::ForeignMod { .. } | ItemKind::GlobalAsm(..) | ItemKind::ExternCrate(..) | ItemKind::Use(..) => { @@ -637,7 +637,7 @@ fn infer_placeholder_type( } // Typeck doesn't expect erased regions to be returned from `type_of`. - tcx.fold_regions(&ty, &mut false, |r, _| match r { + tcx.fold_regions(ty, &mut false, |r, _| match r { ty::ReErased => tcx.lifetimes.re_static, _ => r, }) diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index bae5bde700..e389fd4d9f 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -57,7 +57,7 @@ struct ParameterCollector { } impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective @@ -72,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if let ty::ReEarlyBound(data) = *r { self.parameters.push(Parameter::from(data)); } ControlFlow::CONTINUE } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { match c.val { ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { // Constant expressions are not injective diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 57bd89b9d3..ce9fd5575c 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::{self, adjustment, TyCtxt}; use rustc_target::abi::VariantIdx; use crate::mem_categorization as mc; -use rustc_span::Span; /////////////////////////////////////////////////////////////////////////// // The Delegate trait @@ -73,6 +72,7 @@ pub enum MutateMode { // This is the code that actually walks the tree. pub struct ExprUseVisitor<'a, 'tcx> { mc: mc::MemCategorizationContext<'a, 'tcx>, + body_owner: LocalDefId, delegate: &'a mut dyn Delegate<'tcx>, } @@ -110,6 +110,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ) -> Self { ExprUseVisitor { mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, typeck_results), + body_owner, delegate, } } @@ -241,7 +242,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::ExprKind::InlineAsm(ref asm) => { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr, .. } @@ -329,8 +330,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_expr(base); } - hir::ExprKind::Closure(_, _, _, fn_decl_span, _) => { - self.walk_captures(expr, fn_decl_span); + hir::ExprKind::Closure(..) => { + self.walk_captures(expr); } hir::ExprKind::Box(ref base) => { @@ -529,7 +530,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); let tcx = self.tcx(); - let ExprUseVisitor { ref mc, ref mut delegate } = *self; + let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.kind { debug!("walk_pat: binding place={:?} pat={:?}", place, pat,); @@ -569,50 +570,81 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { })); } - fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>, fn_decl_span: Span) { + /// Handle the case where the current body contains a closure. + /// + /// When the current body being handled is a closure, then we must make sure that + /// - The parent closure only captures Places from the nested closure that are not local to it. + /// + /// In the following example the closures `c` only captures `p.x`` even though `incr` + /// is a capture of the nested closure + /// + /// ```rust,ignore(cannot-test-this-because-pseduo-code) + /// let p = ..; + /// let c = || { + /// let incr = 10; + /// let nested = || p.x += incr; + /// } + /// ``` + /// + /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing + /// closure as the DefId. + fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) { debug!("walk_captures({:?})", closure_expr); - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id); - if let Some(upvars) = self.tcx().upvars_mentioned(closure_def_id) { - for &var_id in upvars.keys() { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_id }, - closure_expr_id: closure_def_id, - }; - let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id); - let captured_place = return_if_err!(self.cat_captured_var( - closure_expr.hir_id, - fn_decl_span, - var_id, - )); - match upvar_capture { - ty::UpvarCapture::ByValue(_) => { - let mode = copy_or_move(&self.mc, &captured_place); - self.delegate.consume(&captured_place, captured_place.hir_id, mode); - } - ty::UpvarCapture::ByRef(upvar_borrow) => { - self.delegate.borrow( - &captured_place, - captured_place.hir_id, - upvar_borrow.kind, - ); + let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); + let upvars = self.tcx().upvars_mentioned(self.body_owner); + + // For purposes of this function, generator and closures are equivalent. + let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() { + ty::Closure(..) | ty::Generator(..) => true, + _ => false, + }; + + if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) + { + for (var_hir_id, min_list) in min_captures.iter() { + if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) { + // The nested closure might be capturing the current (enclosing) closure's local variables. + // We check if the root variable is ever mentioned within the enclosing closure, if not + // then for the current body (if it's a closure) these aren't captures, we will ignore them. + continue; + } + for captured_place in min_list { + let place = &captured_place.place; + let capture_info = captured_place.info; + + let place_base = if body_owner_is_closure { + // Mark the place to be captured by the enclosing closure + PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner)) + } else { + // If the body owner isn't a closure then the variable must + // be a local variable + PlaceBase::Local(*var_hir_id) + }; + let place_with_id = PlaceWithHirId::new( + capture_info.expr_id.unwrap_or(closure_expr.hir_id), + place.base_ty, + place_base, + place.projections.clone(), + ); + + match capture_info.capture_kind { + ty::UpvarCapture::ByValue(_) => { + let mode = copy_or_move(&self.mc, &place_with_id); + self.delegate.consume(&place_with_id, place_with_id.hir_id, mode); + } + ty::UpvarCapture::ByRef(upvar_borrow) => { + self.delegate.borrow( + &place_with_id, + place_with_id.hir_id, + upvar_borrow.kind, + ); + } } } } } } - - fn cat_captured_var( - &mut self, - closure_hir_id: hir::HirId, - closure_span: Span, - var_id: hir::HirId, - ) -> mc::McResult> { - // Create the place for the variable being borrowed, from the - // perspective of the creator (parent) of the closure. - let var_ty = self.mc.node_ty(var_id)?; - self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id)) - } } fn copy_or_move<'a, 'tcx>( diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index 4901d6041d..14daa97c2c 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -93,6 +93,8 @@ impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> { fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {} } fn enforce_impl_params_are_constrained( diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 4cf3efcf51..5db9ff9524 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -165,7 +165,7 @@ fn get_impl_substs<'tcx>( // Conservatively use an empty `ParamEnv`. let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default()); - let impl2_substs = match infcx.fully_resolve(&impl2_substs) { + let impl2_substs = match infcx.fully_resolve(impl2_substs) { Ok(s) => s, Err(_) => { tcx.sess.struct_span_err(span, "could not resolve substs on overridden impl").emit(); diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 30904091c1..dde4a62ffb 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -61,6 +61,7 @@ This API is completely unstable and subject to change. #![feature(box_syntax)] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] +#![feature(is_sorted)] #![feature(nll)] #![feature(or_patterns)] #![feature(try_blocks)] @@ -225,19 +226,21 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { let expected_return_type = if tcx.lang_items().termination().is_some() { // we take the return type of the given main function, the real check is done // in `check_fn` - actual.output().skip_binder() + actual.output() } else { // standard () main return type - tcx.mk_unit() + ty::Binder::dummy(tcx.mk_unit()) }; - let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( - iter::empty(), - expected_return_type, - false, - hir::Unsafety::Normal, - Abi::Rust, - ))); + let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { + tcx.mk_fn_sig( + iter::empty(), + expected_return_type, + false, + hir::Unsafety::Normal, + Abi::Rust, + ) + })); require_same_types( tcx, diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index f6ac7aa915..9992094117 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) } - fn resolve_vars_if_possible(&self, value: &T) -> T + fn resolve_vars_if_possible(&self, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -142,7 +142,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> McResult> { match ty { Some(ty) => { - let ty = self.resolve_vars_if_possible(&ty); + let ty = self.resolve_vars_if_possible(ty); if ty.references_error() || ty.is_ty_var() { debug!("resolve_type_vars_or_error: error from {:?}", ty); Err(()) @@ -274,7 +274,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { F: FnOnce() -> McResult>, { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); - let target = self.resolve_vars_if_possible(&adjustment.target); + let target = self.resolve_vars_if_possible(adjustment.target); match adjustment.kind { adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index e7a9e078a7..3d0635e3fe 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -109,6 +109,8 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {} + + fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {} } fn insert_required_predicates_to_be_wf<'tcx>( diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 94926f480e..b1f79331d5 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -90,14 +90,14 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CratePredica match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty1, region2)) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate( region1, region2, )) - .potentially_quantified(tcx, ty::PredicateKind::ForAll), + .to_predicate(tcx), span, )), GenericArgKind::Const(_) => { diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_typeck/src/outlives/test.rs index abe9319d71..56d42f756c 100644 --- a/compiler/rustc_typeck/src/outlives/test.rs +++ b/compiler/rustc_typeck/src/outlives/test.rs @@ -26,4 +26,5 @@ impl ItemLikeVisitor<'tcx> for OutlivesTest<'tcx> { fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} + fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {} } diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index b2b062e409..a8fbdfb7c6 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -92,14 +92,6 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { self.visit_node_helper(item.hir_id); } - hir::ItemKind::ForeignMod(ref foreign_mod) => { - for foreign_item in foreign_mod.items { - if let hir::ForeignItemKind::Fn(..) = foreign_item.kind { - self.visit_node_helper(foreign_item.hir_id); - } - } - } - _ => {} } } @@ -115,6 +107,12 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { self.visit_node_helper(impl_item.hir_id); } } + + fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { + if let hir::ForeignItemKind::Fn(..) = foreign_item.kind { + self.visit_node_helper(foreign_item.hir_id); + } + } } impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs index 81c858c53c..3b2a1c24dd 100644 --- a/compiler/rustc_typeck/src/variance/terms.rs +++ b/compiler/rustc_typeck/src/variance/terms.rs @@ -153,14 +153,6 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { self.add_inferreds_for_item(item.hir_id); } - hir::ItemKind::ForeignMod(ref foreign_mod) => { - for foreign_item in foreign_mod.items { - if let hir::ForeignItemKind::Fn(..) = foreign_item.kind { - self.add_inferreds_for_item(foreign_item.hir_id); - } - } - } - _ => {} } } @@ -176,4 +168,10 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { self.add_inferreds_for_item(impl_item.hir_id); } } + + fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { + if let hir::ForeignItemKind::Fn(..) = foreign_item.kind { + self.add_inferreds_for_item(foreign_item.hir_id); + } + } } diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_typeck/src/variance/test.rs index 1aab89310c..d6e43b6d66 100644 --- a/compiler/rustc_typeck/src/variance/test.rs +++ b/compiler/rustc_typeck/src/variance/test.rs @@ -26,4 +26,5 @@ impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> { fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} + fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {} } diff --git a/config.toml.example b/config.toml.example index c9e1838875..b1fb8904ca 100644 --- a/config.toml.example +++ b/config.toml.example @@ -426,6 +426,14 @@ changelog-seen = 2 # FIXME(#61117): Some tests fail when this option is enabled. #debuginfo-level-tests = 0 +# Whether to run `dsymutil` on Apple platforms to gather debug info into .dSYM +# bundles. `dsymutil` adds time to builds for no clear benefit, and also makes +# it more difficult for debuggers to find debug info. The compiler currently +# defaults to running `dsymutil` to preserve its historical default, but when +# compiling the compiler itself, we skip it by default since we know it's safe +# to do so in that case. +#run-dsymutil = false + # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) #backtrace = true @@ -446,6 +454,11 @@ changelog-seen = 2 # nightly features #channel = "dev" +# A descriptive string to be appended to `rustc --version` output, which is +# also used in places like debuginfo `DW_AT_producer`. This may be useful for +# supplementary build information, like distro-specific package versions. +#description = "" + # The root location of the musl installation directory. #musl-root = "..." diff --git a/git-commit-hash b/git-commit-hash index 8a5d3d7d2f..cb573231ff 100644 --- a/git-commit-hash +++ b/git-commit-hash @@ -1 +1 @@ -e1884a8e3c3e813aada8254edfa120e85bf5ffca \ No newline at end of file +cb75ad5db02783e8b0222fee363c5f63f7e2cf5b \ No newline at end of file diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 381750a519..eff197d998 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -31,3 +31,5 @@ harness = false [features] compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] +compiler-builtins-asm = ["compiler_builtins/asm"] +compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 0a4f88dedb..4fbcc4590f 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -23,6 +23,8 @@ extern "Rust" { // (the code expanding that attribute macro generates those functions), or to call // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) // otherwise. + // The rustc fork of LLVM also special-cases these function names to be able to optimize them + // like `malloc`, `realloc`, and `free`, respectively. #[rustc_allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; @@ -36,7 +38,7 @@ extern "Rust" { /// The global memory allocator. /// -/// This type implements the [`AllocRef`] trait by forwarding calls +/// This type implements the [`Allocator`] trait by forwarding calls /// to the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. /// @@ -57,7 +59,7 @@ pub use std::alloc::Global; /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `alloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -91,7 +93,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `dealloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -109,7 +111,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `realloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -127,7 +129,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `alloc_zeroed` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -168,7 +170,7 @@ impl Global { } } - // SAFETY: Same as `AllocRef::grow` + // SAFETY: Same as `Allocator::grow` #[inline] unsafe fn grow_impl( &self, @@ -209,7 +211,7 @@ impl Global { old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(new_ptr) }, } @@ -218,19 +220,19 @@ impl Global { #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(test))] -unsafe impl AllocRef for Global { +unsafe impl Allocator for Global { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -275,7 +277,7 @@ unsafe impl AllocRef for Global { match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, @@ -295,9 +297,9 @@ unsafe impl AllocRef for Global { // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(new_ptr) }, } @@ -311,7 +313,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - match Global.alloc(layout) { + match Global.allocate(layout) { Ok(ptr) => ptr.as_mut_ptr(), Err(_) => handle_alloc_error(layout), } @@ -320,16 +322,16 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { #[cfg_attr(not(test), lang = "box_free")] #[inline] // This signature has to be the same as `Box`, otherwise an ICE will happen. -// When an additional parameter to `Box` is added (like `A: AllocRef`), this has to be added here as +// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. -// For example if `Box` is changed to `struct Box(Unique, A)`, -// this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +// For example if `Box` is changed to `struct Box(Unique, A)`, +// this function has to be changed to `fn box_free(Unique, A)` as well. +pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); let layout = Layout::from_size_align_unchecked(size, align); - alloc.dealloc(ptr.cast().into(), layout) + alloc.deallocate(ptr.cast().into(), layout) } } @@ -356,8 +358,9 @@ extern "Rust" { /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] -#[cfg(not(any(test, bootstrap)))] +#[cfg(not(test))] #[rustc_allocator_nounwind] +#[cold] pub fn handle_alloc_error(layout: Layout) -> ! { unsafe { __rust_alloc_error_handler(layout.size(), layout.align()); @@ -368,22 +371,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! { #[cfg(test)] pub use std::alloc::handle_alloc_error; -// In stage0 (bootstrap) `__rust_alloc_error_handler`, -// might not be generated yet, because an old compiler is used, -// so use the old direct call. -#[cfg(all(bootstrap, not(test)))] -#[stable(feature = "global_alloc", since = "1.28.0")] -#[doc(hidden)] -#[rustc_allocator_nounwind] -pub fn handle_alloc_error(layout: Layout) -> ! { - extern "Rust" { - #[lang = "oom"] - fn oom_impl(layout: Layout) -> !; - } - unsafe { oom_impl(layout) } -} - -#[cfg(not(any(target_os = "hermit", test, bootstrap)))] +#[cfg(not(any(target_os = "hermit", test)))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] diff --git a/library/alloc/src/alloc/tests.rs b/library/alloc/src/alloc/tests.rs index f7463d0daa..94e05fa448 100644 --- a/library/alloc/src/alloc/tests.rs +++ b/library/alloc/src/alloc/tests.rs @@ -9,7 +9,7 @@ fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = - Global.alloc_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); + Global.allocate_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); let mut i = ptr.as_non_null_ptr().as_ptr(); let end = i.add(layout.size()); @@ -17,7 +17,7 @@ fn allocate_zeroed() { assert_eq!(*i, 0); i = i.offset(1); } - Global.dealloc(ptr.as_non_null_ptr(), layout); + Global.deallocate(ptr.as_non_null_ptr(), layout); } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1512235da6..a6360f25ec 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -62,6 +62,13 @@ //! T` obtained from [`Box::::into_raw`] may be deallocated using the //! [`Global`] allocator with [`Layout::for_value(&*value)`]. //! +//! For zero-sized values, the `Box` pointer still has to be [valid] for reads +//! and writes and sufficiently aligned. In particular, casting any aligned +//! non-zero integer literal to a raw pointer produces a valid pointer, but a +//! pointer pointing into previously allocated memory that since got freed is +//! not valid. The recommended way to build a Box to a ZST if `Box::new` cannot +//! be used is to use [`ptr::NonNull::dangling`]. +//! //! So long as `T: Sized`, a `Box` is guaranteed to be represented //! as a single pointer and is also ABI-compatible with C pointers //! (i.e. the C type `T*`). This means that if you have extern "C" @@ -125,6 +132,7 @@ //! [`Global`]: crate::alloc::Global //! [`Layout`]: crate::alloc::Layout //! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value +//! [valid]: ptr#safety #![stable(feature = "rust1", since = "1.0.0")] @@ -145,7 +153,7 @@ use core::pin::Pin; use core::ptr::{self, Unique}; use core::task::{Context, Poll}; -use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{handle_alloc_error, Allocator, Global, Layout}; use crate::borrow::Cow; use crate::raw_vec::RawVec; use crate::str::from_boxed_utf8_unchecked; @@ -159,7 +167,7 @@ use crate::vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] pub struct Box< T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, >(Unique, A); impl Box { @@ -235,7 +243,7 @@ impl Box { } } -impl Box { +impl Box { /// Allocates memory in the given allocator then places `x` into it. /// /// This doesn't actually allocate if `T` is zero-sized. @@ -283,7 +291,7 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - let ptr = alloc.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); + let ptr = alloc.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); unsafe { Box::from_raw_in(ptr.as_ptr(), alloc) } } @@ -311,7 +319,8 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - let ptr = alloc.alloc_zeroed(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); + let ptr = + alloc.allocate_zeroed(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); unsafe { Box::from_raw_in(ptr.as_ptr(), alloc) } } @@ -319,7 +328,10 @@ impl Box { /// `x` will be pinned in memory and unable to be moved. #[unstable(feature = "allocator_api", issue = "32838")] #[inline(always)] - pub fn pin_in(x: T, alloc: A) -> Pin { + pub fn pin_in(x: T, alloc: A) -> Pin + where + A: 'static, + { Self::new_in(x, alloc).into() } @@ -328,7 +340,7 @@ impl Box { /// This conversion does not allocate on the heap and happens in place. #[unstable(feature = "box_into_boxed_slice", issue = "71582")] pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> { - let (raw, alloc) = Box::into_raw_with_alloc(boxed); + let (raw, alloc) = Box::into_raw_with_allocator(boxed); unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } } } @@ -383,7 +395,7 @@ impl Box<[T]> { } } -impl Box<[T], A> { +impl Box<[T], A> { /// Constructs a new boxed slice with uninitialized contents in the provided allocator. /// /// # Examples @@ -439,7 +451,7 @@ impl Box<[T], A> { } } -impl Box, A> { +impl Box, A> { /// Converts to `Box`. /// /// # Safety @@ -471,12 +483,12 @@ impl Box, A> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box { - let (raw, alloc) = Box::into_raw_with_alloc(self); + let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut T, alloc) } } } -impl Box<[mem::MaybeUninit], A> { +impl Box<[mem::MaybeUninit], A> { /// Converts to `Box<[T], A>`. /// /// # Safety @@ -510,7 +522,7 @@ impl Box<[mem::MaybeUninit], A> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box<[T], A> { - let (raw, alloc) = Box::into_raw_with_alloc(self); + let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut [T], alloc) } } } @@ -530,7 +542,10 @@ impl Box { /// memory problems. For example, a double-free may occur if the /// function is called twice on the same raw pointer. /// + /// The safety conditions are described in the [memory layout] section. + /// /// # Examples + /// /// Recreate a `Box` which was previously converted to a raw pointer /// using [`Box::into_raw`]: /// ``` @@ -561,7 +576,7 @@ impl Box { } } -impl Box { +impl Box { /// Constructs a box from a raw pointer in the given allocator. /// /// After calling this function, the raw pointer is owned by the @@ -580,24 +595,24 @@ impl Box { /// # Examples /// /// Recreate a `Box` which was previously converted to a raw pointer - /// using [`Box::into_raw_with_alloc`]: + /// using [`Box::into_raw_with_allocator`]: /// ``` /// #![feature(allocator_api)] /// /// use std::alloc::System; /// /// let x = Box::new_in(5, System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; /// ``` /// Manually create a `Box` from scratch by using the system allocator: /// ``` /// #![feature(allocator_api, slice_ptr_get)] /// - /// use std::alloc::{AllocRef, Layout, System}; + /// use std::alloc::{Allocator, Layout, System}; /// /// unsafe { - /// let ptr = System.alloc(Layout::new::())?.as_mut_ptr(); + /// let ptr = System.allocate(Layout::new::())?.as_mut_ptr(); /// // In general .write is required to avoid attempting to destruct /// // the (uninitialized) previous contents of `ptr`, though for this /// // simple example `*ptr = 5` would have worked as well. @@ -657,7 +672,7 @@ impl Box { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Self) -> *mut T { - Self::into_raw_with_alloc(b).0 + Self::into_raw_with_allocator(b).0 } /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. @@ -673,7 +688,7 @@ impl Box { /// the cleanup. /// /// Note: this is an associated function, which means that you have - /// to call it as `Box::into_raw_with_alloc(b)` instead of `b.into_raw_with_alloc()`. This + /// to call it as `Box::into_raw_with_allocator(b)` instead of `b.into_raw_with_allocator()`. This /// is so that there is no conflict with a method on the inner type. /// /// # Examples @@ -685,7 +700,7 @@ impl Box { /// use std::alloc::System; /// /// let x = Box::new_in(String::from("Hello"), System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; /// ``` /// Manual cleanup by explicitly running the destructor and deallocating @@ -693,22 +708,22 @@ impl Box { /// ``` /// #![feature(allocator_api)] /// - /// use std::alloc::{AllocRef, Layout, System}; + /// use std::alloc::{Allocator, Layout, System}; /// use std::ptr::{self, NonNull}; /// /// let x = Box::new_in(String::from("Hello"), System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// unsafe { /// ptr::drop_in_place(ptr); /// let non_null = NonNull::new_unchecked(ptr); - /// alloc.dealloc(non_null.cast(), Layout::new::()); + /// alloc.deallocate(non_null.cast(), Layout::new::()); /// } /// ``` /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn into_raw_with_alloc(b: Self) -> (*mut T, A) { + pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let (leaked, alloc) = Box::into_unique(b); (leaked.as_ptr(), alloc) } @@ -733,11 +748,11 @@ impl Box { /// Returns a reference to the underlying allocator. /// /// Note: this is an associated function, which means that you have - /// to call it as `Box::alloc_ref(&b)` instead of `b.alloc_ref()`. This + /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(b: &Self) -> &A { + pub fn allocator(b: &Self) -> &A { &b.1 } @@ -791,7 +806,10 @@ impl Box { /// /// This is also available via [`From`]. #[unstable(feature = "box_into_pin", issue = "62370")] - pub fn into_pin(boxed: Self) -> Pin { + pub fn into_pin(boxed: Self) -> Pin + where + A: 'static, + { // It's not possible to move or replace the insides of a `Pin>` // when `T: !Unpin`, so it's safe to pin it directly without any // additional requirements. @@ -800,7 +818,7 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: AllocRef> Drop for Box { +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { fn drop(&mut self) { // FIXME: Do nothing, drop is currently performed by compiler. } @@ -829,7 +847,7 @@ impl Default for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Box { +impl Clone for Box { /// Returns a new box with a `clone()` of this box's contents. /// /// # Examples @@ -883,7 +901,7 @@ impl Clone for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Box { +impl PartialEq for Box { #[inline] fn eq(&self, other: &Self) -> bool { PartialEq::eq(&**self, &**other) @@ -894,7 +912,7 @@ impl PartialEq for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Box { +impl PartialOrd for Box { #[inline] fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(&**self, &**other) @@ -917,24 +935,24 @@ impl PartialOrd for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Box { +impl Ord for Box { #[inline] fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Box {} +impl Eq for Box {} #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Box { +impl Hash for Box { fn hash(&self, state: &mut H) { (**self).hash(state); } } #[stable(feature = "indirect_hasher_impl", since = "1.22.0")] -impl Hasher for Box { +impl Hasher for Box { fn finish(&self) -> u64 { (**self).finish() } @@ -999,7 +1017,10 @@ impl From for Box { } #[stable(feature = "pin", since = "1.33.0")] -impl From> for Pin> { +impl From> for Pin> +where + A: 'static, +{ /// Converts a `Box` into a `Pin>` /// /// This conversion does not allocate on the heap and happens in place. @@ -1074,7 +1095,7 @@ impl From> for Box { } #[stable(feature = "boxed_str_conv", since = "1.19.0")] -impl From> for Box<[u8], A> { +impl From> for Box<[u8], A> { /// Converts a `Box` into a `Box<[u8]>` /// /// This conversion does not allocate on the heap and happens in place. @@ -1093,7 +1114,7 @@ impl From> for Box<[u8], A> { /// ``` #[inline] fn from(s: Box) -> Self { - let (raw, alloc) = Box::into_raw_with_alloc(s); + let (raw, alloc) = Box::into_raw_with_allocator(s); unsafe { Box::from_raw_in(raw as *mut [u8], alloc) } } } @@ -1127,7 +1148,7 @@ impl TryFrom> for Box<[T; N]> { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -1150,7 +1171,7 @@ impl Box { pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { - let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_alloc(self); + let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); Ok(Box::from_raw_in(raw as *mut T, alloc)) } } else { @@ -1159,7 +1180,7 @@ impl Box { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -1182,7 +1203,7 @@ impl Box { pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { - let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_alloc(self); + let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); Ok(Box::from_raw_in(raw as *mut T, alloc)) } } else { @@ -1192,21 +1213,21 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Box { +impl fmt::Display for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Box { +impl fmt::Debug for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Pointer for Box { +impl fmt::Pointer for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // It's not possible to extract the inner Uniq directly from the Box, // instead we cast it to a *const which aliases the Unique @@ -1216,7 +1237,7 @@ impl fmt::Pointer for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Box { +impl Deref for Box { type Target = T; fn deref(&self) -> &T { @@ -1225,17 +1246,17 @@ impl Deref for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl DerefMut for Box { +impl DerefMut for Box { fn deref_mut(&mut self) -> &mut T { &mut **self } } #[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Box {} +impl Receiver for Box {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Box { +impl Iterator for Box { type Item = I::Item; fn next(&mut self) -> Option { (**self).next() @@ -1256,7 +1277,7 @@ trait BoxIter { fn last(self) -> Option; } -impl BoxIter for Box { +impl BoxIter for Box { type Item = I::Item; default fn last(self) -> Option { #[inline] @@ -1271,14 +1292,14 @@ impl BoxIter for Box { /// Specialization for sized `I`s that uses `I`s implementation of `last()` /// instead of the default. #[stable(feature = "rust1", since = "1.0.0")] -impl BoxIter for Box { +impl BoxIter for Box { fn last(self) -> Option { (*self).last() } } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Box { +impl DoubleEndedIterator for Box { fn next_back(&mut self) -> Option { (**self).next_back() } @@ -1287,7 +1308,7 @@ impl DoubleEndedIterator for Box ExactSizeIterator for Box { +impl ExactSizeIterator for Box { fn len(&self) -> usize { (**self).len() } @@ -1297,10 +1318,10 @@ impl ExactSizeIterator for Box } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Box {} +impl FusedIterator for Box {} #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> FnOnce for Box { +impl + ?Sized, A: Allocator> FnOnce for Box { type Output = >::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output { @@ -1309,21 +1330,21 @@ impl + ?Sized, A: AllocRef> FnOnce for Box { } #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> FnMut for Box { +impl + ?Sized, A: Allocator> FnMut for Box { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { >::call_mut(self, args) } } #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> Fn for Box { +impl + ?Sized, A: Allocator> Fn for Box { extern "rust-call" fn call(&self, args: Args) -> Self::Output { >::call(self, args) } } #[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized, A: AllocRef> CoerceUnsized> for Box {} +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Box {} @@ -1336,9 +1357,10 @@ impl FromIterator for Box<[I]> { } #[stable(feature = "box_slice_clone", since = "1.3.0")] -impl Clone for Box<[T]> { +impl Clone for Box<[T], A> { fn clone(&self) -> Self { - self.to_vec().into_boxed_slice() + let alloc = Box::allocator(self).clone(); + self.to_vec_in(alloc).into_boxed_slice() } fn clone_from(&mut self, other: &Self) { @@ -1351,28 +1373,28 @@ impl Clone for Box<[T]> { } #[stable(feature = "box_borrow", since = "1.1.0")] -impl borrow::Borrow for Box { +impl borrow::Borrow for Box { fn borrow(&self) -> &T { &**self } } #[stable(feature = "box_borrow", since = "1.1.0")] -impl borrow::BorrowMut for Box { +impl borrow::BorrowMut for Box { fn borrow_mut(&mut self) -> &mut T { &mut **self } } #[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsRef for Box { +impl AsRef for Box { fn as_ref(&self) -> &T { &**self } } #[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsMut for Box { +impl AsMut for Box { fn as_mut(&mut self) -> &mut T { &mut **self } @@ -1401,10 +1423,13 @@ impl AsMut for Box { * could have a method to project a Pin from it. */ #[stable(feature = "pin", since = "1.33.0")] -impl Unpin for Box {} +impl Unpin for Box where A: 'static {} #[unstable(feature = "generator_trait", issue = "43122")] -impl + Unpin, R, A: AllocRef> Generator for Box { +impl + Unpin, R, A: Allocator> Generator for Box +where + A: 'static, +{ type Yield = G::Yield; type Return = G::Return; @@ -1414,7 +1439,10 @@ impl + Unpin, R, A: AllocRef> Generator for Box, R, A: AllocRef> Generator for Pin> { +impl, R, A: Allocator> Generator for Pin> +where + A: 'static, +{ type Yield = G::Yield; type Return = G::Return; @@ -1424,7 +1452,10 @@ impl, R, A: AllocRef> Generator for Pin> { } #[stable(feature = "futures_api", since = "1.36.0")] -impl Future for Box { +impl Future for Box +where + A: 'static, +{ type Output = F::Output; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index e0362b2f37..bd99c4ed2f 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -34,7 +34,7 @@ impl Root { where I: Iterator, { - let mut cur_node = self.node_as_mut().last_leaf_edge().into_node(); + let mut cur_node = self.borrow_mut().last_leaf_edge().into_node(); // Iterate through all key-value pairs, pushing them into nodes at the right level. for (key, value) in iter { // Try to push key-value pair into the current leaf node. @@ -67,7 +67,7 @@ impl Root { // Push key-value pair and new right subtree. let tree_height = open_node.height() - 1; - let mut right_tree = Root::new_leaf(); + let mut right_tree = Root::new(); for _ in 0..tree_height { right_tree.push_internal_level(); } @@ -86,23 +86,18 @@ impl Root { fn fix_right_edge(&mut self) { // Handle underfull nodes, start from the top. - let mut cur_node = self.node_as_mut(); + let mut cur_node = self.borrow_mut(); while let Internal(internal) = cur_node.force() { // Check if right-most child is underfull. - let mut last_edge = internal.last_edge(); - let right_child_len = last_edge.reborrow().descend().len(); + let mut last_kv = internal.last_kv().consider_for_balancing(); + let right_child_len = last_kv.right_child_len(); if right_child_len < MIN_LEN { // We need to steal. - let mut last_kv = match last_edge.left_kv() { - Ok(left) => left, - Err(_) => unreachable!(), - }; last_kv.bulk_steal_left(MIN_LEN - right_child_len); - last_edge = last_kv.right_edge(); } // Go further down. - cur_node = last_edge.descend(); + cur_node = last_kv.into_right_child(); } } } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 49122f53d3..735213363f 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -9,7 +9,7 @@ use core::ops::{Index, RangeBounds}; use core::ptr; use super::borrow::DormantMutRef; -use super::node::{self, marker, ForceResult::*, Handle, NodeRef}; +use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root}; use super::search::{self, SearchResult::*}; use super::unwrap_unchecked; @@ -128,7 +128,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct BTreeMap { - root: Option>, + root: Option>, length: usize, } @@ -145,7 +145,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap { impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { fn clone_subtree<'a, K: Clone, V: Clone>( - node: node::NodeRef, K, V, marker::LeafOrInternal>, + node: NodeRef, K, V, marker::LeafOrInternal>, ) -> BTreeMap where K: 'a, @@ -153,11 +153,11 @@ impl Clone for BTreeMap { { match node.force() { Leaf(leaf) => { - let mut out_tree = BTreeMap { root: Some(node::Root::new_leaf()), length: 0 }; + let mut out_tree = BTreeMap { root: Some(Root::new()), length: 0 }; { let root = out_tree.root.as_mut().unwrap(); // unwrap succeeds because we just wrapped - let mut out_node = match root.node_as_mut().force() { + let mut out_node = match root.borrow_mut().force() { Leaf(leaf) => leaf, Internal(_) => unreachable!(), }; @@ -198,7 +198,7 @@ impl Clone for BTreeMap { (root, length) }; - out_node.push(k, v, subroot.unwrap_or_else(node::Root::new_leaf)); + out_node.push(k, v, subroot.unwrap_or_else(Root::new)); out_tree.length += 1 + sublength; } } @@ -213,7 +213,7 @@ impl Clone for BTreeMap { // Ord` constraint, which this method lacks. BTreeMap { root: None, length: 0 } } else { - clone_subtree(self.root.as_ref().unwrap().node_as_ref()) // unwrap succeeds because not empty + clone_subtree(self.root.as_ref().unwrap().reborrow()) // unwrap succeeds because not empty } } } @@ -226,7 +226,7 @@ where type Key = K; fn get(&self, key: &Q) -> Option<&K> { - let root_node = self.root.as_ref()?.node_as_ref(); + let root_node = self.root.as_ref()?.reborrow(); match search::search_tree(root_node, key) { Found(handle) => Some(handle.into_kv().0), GoDown(_) => None, @@ -235,7 +235,7 @@ where fn take(&mut self, key: &Q) -> Option { let (map, dormant_map) = DormantMutRef::new(self); - let root_node = map.root.as_mut()?.node_as_mut(); + let root_node = map.root.as_mut()?.borrow_mut(); match search::search_tree(root_node, key) { Found(handle) => { Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_kv().0) @@ -246,9 +246,9 @@ where fn replace(&mut self, key: K) -> Option { let (map, dormant_map) = DormantMutRef::new(self); - let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut(); match search::search_tree::, K, (), K>(root_node, &key) { - Found(handle) => Some(mem::replace(handle.into_key_mut(), key)), + Found(mut kv) => Some(mem::replace(kv.key_mut(), key)), GoDown(handle) => { VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(()); None @@ -458,7 +458,7 @@ impl fmt::Debug for RangeMut<'_, K, V> { } impl BTreeMap { - /// Makes a new empty BTreeMap. + /// Makes a new, empty `BTreeMap`. /// /// Does not allocate anything on its own. /// @@ -522,7 +522,7 @@ impl BTreeMap { K: Borrow, Q: Ord, { - let root_node = self.root.as_ref()?.node_as_ref(); + let root_node = self.root.as_ref()?.reborrow(); match search::search_tree(root_node, key) { Found(handle) => Some(handle.into_kv().1), GoDown(_) => None, @@ -550,7 +550,7 @@ impl BTreeMap { K: Borrow, Q: Ord, { - let root_node = self.root.as_ref()?.node_as_ref(); + let root_node = self.root.as_ref()?.reborrow(); match search::search_tree(root_node, k) { Found(handle) => Some(handle.into_kv()), GoDown(_) => None, @@ -576,7 +576,7 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn first_key_value(&self) -> Option<(&K, &V)> { - let root_node = self.root.as_ref()?.node_as_ref(); + let root_node = self.root.as_ref()?.reborrow(); root_node.first_leaf_edge().right_kv().ok().map(Handle::into_kv) } @@ -603,7 +603,7 @@ impl BTreeMap { #[unstable(feature = "map_first_last", issue = "62924")] pub fn first_entry(&mut self) -> Option> { let (map, dormant_map) = DormantMutRef::new(self); - let root_node = map.root.as_mut()?.node_as_mut(); + let root_node = map.root.as_mut()?.borrow_mut(); let kv = root_node.first_leaf_edge().right_kv().ok()?; Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } @@ -650,7 +650,7 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn last_key_value(&self) -> Option<(&K, &V)> { - let root_node = self.root.as_ref()?.node_as_ref(); + let root_node = self.root.as_ref()?.reborrow(); root_node.last_leaf_edge().left_kv().ok().map(Handle::into_kv) } @@ -677,7 +677,7 @@ impl BTreeMap { #[unstable(feature = "map_first_last", issue = "62924")] pub fn last_entry(&mut self) -> Option> { let (map, dormant_map) = DormantMutRef::new(self); - let root_node = map.root.as_mut()?.node_as_mut(); + let root_node = map.root.as_mut()?.borrow_mut(); let kv = root_node.last_leaf_edge().left_kv().ok()?; Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } @@ -758,7 +758,7 @@ impl BTreeMap { K: Borrow, Q: Ord, { - let root_node = self.root.as_mut()?.node_as_mut(); + let root_node = self.root.as_mut()?.borrow_mut(); match search::search_tree(root_node, key) { Found(handle) => Some(handle.into_val_mut()), GoDown(_) => None, @@ -854,7 +854,7 @@ impl BTreeMap { Q: Ord, { let (map, dormant_map) = DormantMutRef::new(self); - let root_node = map.root.as_mut()?.node_as_mut(); + let root_node = map.root.as_mut()?.borrow_mut(); match search::search_tree(root_node, key) { Found(handle) => { Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_entry()) @@ -863,6 +863,30 @@ impl BTreeMap { } } + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_retain)] + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap = (0..8).map(|x| (x, x*10)).collect(); + /// // Keep only the elements with even-numbered keys. + /// map.retain(|&k, _| k % 2 == 0); + /// assert!(map.into_iter().eq(vec![(0, 0), (2, 20), (4, 40), (6, 60)])); + /// ``` + #[inline] + #[unstable(feature = "btree_retain", issue = "79025")] + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + self.drain_filter(|k, v| !f(k, v)); + } + /// Moves all elements from `other` into `Self`, leaving `other` empty. /// /// # Examples @@ -947,7 +971,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &self.root { - let (f, b) = root.node_as_ref().range_search(range); + let (f, b) = root.reborrow().range_search(range); Range { front: Some(f), back: Some(b) } } else { @@ -993,7 +1017,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &mut self.root { - let (f, b) = root.node_as_valmut().range_search(range); + let (f, b) = root.borrow_valmut().range_search(range); RangeMut { front: Some(f), back: Some(b), _marker: PhantomData } } else { @@ -1013,7 +1037,7 @@ impl BTreeMap { /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); /// /// // count the number of occurrences of letters in the vec - /// for x in vec!["a","b","a","c","a","b"] { + /// for x in vec!["a", "b", "a", "c", "a", "b"] { /// *count.entry(x).or_insert(0) += 1; /// } /// @@ -1023,7 +1047,7 @@ impl BTreeMap { pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { // FIXME(@porglezomp) Avoid allocating if we don't insert let (map, dormant_map) = DormantMutRef::new(self); - let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + let root_node = Self::ensure_is_owned(&mut map.root).borrow_mut(); match search::search_tree(root_node, &key) { Found(handle) => Occupied(OccupiedEntry { handle, dormant_map, _marker: PhantomData }), GoDown(handle) => { @@ -1079,10 +1103,10 @@ impl BTreeMap { left_root.split_off(right_root, key); if left_root.height() < right_root.height() { - self.length = left_root.node_as_ref().calc_length(); + self.length = left_root.reborrow().calc_length(); right.length = total_num - self.len(); } else { - right.length = right_root.node_as_ref().calc_length(); + right.length = right_root.reborrow().calc_length(); self.length = total_num - right.len(); } @@ -1130,7 +1154,7 @@ impl BTreeMap { pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V> { if let Some(root) = self.root.as_mut() { let (root, dormant_root) = DormantMutRef::new(root); - let front = root.node_as_mut().first_leaf_edge(); + let front = root.borrow_mut().first_leaf_edge(); DrainFilterInner { length: &mut self.length, dormant_root: Some(dormant_root), @@ -1337,7 +1361,7 @@ impl IntoIterator for BTreeMap { fn into_iter(self) -> IntoIter { let mut me = ManuallyDrop::new(self); if let Some(root) = me.root.take() { - let (f, b) = root.into_ref().full_range(); + let (f, b) = root.full_range(); IntoIter { front: Some(f), back: Some(b), length: me.length } } else { @@ -1527,14 +1551,14 @@ where pred: F, inner: DrainFilterInner<'a, K, V>, } -/// Most of the implementation of DrainFilter, independent of the type +/// Most of the implementation of DrainFilter are generic over the type /// of the predicate, thus also serving for BTreeSet::DrainFilter. pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> { /// Reference to the length field in the borrowed map, updated live. length: &'a mut usize, - /// Burried reference to the root field in the borrowed map. + /// Buried reference to the root field in the borrowed map. /// Wrapped in `Option` to allow drop handler to `take` it. - dormant_root: Option>>, + dormant_root: Option>>, /// Contains a leaf edge preceding the next element to be returned, or the last leaf edge. /// Empty if the map has no root, if iteration went beyond the last leaf edge, /// or if a panic occurred in the predicate. @@ -1900,7 +1924,7 @@ impl Hash for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeMap { - /// Creates an empty `BTreeMap`. + /// Creates an empty `BTreeMap`. fn default() -> BTreeMap { BTreeMap::new() } @@ -1983,7 +2007,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { if let Some(root) = &self.root { - let (f, b) = root.node_as_ref().full_range(); + let (f, b) = root.reborrow().full_range(); Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length } } else { @@ -2015,7 +2039,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { if let Some(root) = &mut self.root { - let (f, b) = root.node_as_valmut().full_range(); + let (f, b) = root.borrow_valmut().full_range(); IterMut { range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }, @@ -2136,8 +2160,8 @@ impl BTreeMap { /// If the root node is the empty (non-allocated) root node, allocate our /// own node. Is an associated function to avoid borrowing the entire BTreeMap. - fn ensure_is_owned(root: &mut Option>) -> &mut node::Root { - root.get_or_insert_with(node::Root::new_leaf) + fn ensure_is_owned(root: &mut Option>) -> &mut Root { + root.get_or_insert_with(Root::new) } } diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 73a0ca21f6..6cc8813bc5 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -116,15 +116,16 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } } - #[unstable(feature = "or_insert_with_key", issue = "71024")] - /// Ensures a value is in the entry by inserting, if empty, the result of the default function, - /// which takes the key as its argument, and returns a mutable reference to the value in the - /// entry. + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. /// /// # Examples /// /// ``` - /// #![feature(or_insert_with_key)] /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); @@ -134,6 +135,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 9); /// ``` #[inline] + #[stable(feature = "or_insert_with_key", since = "1.50.0")] pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -286,7 +288,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { // Safety: We have consumed self.handle and the reference returned. let map = unsafe { self.dormant_map.awaken() }; let root = map.root.as_mut().unwrap(); - root.push_internal_level().push(ins.k, ins.v, ins.right); + root.push_internal_level().push(ins.kv.0, ins.kv.1, ins.right); map.length += 1; val_ptr } @@ -459,7 +461,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { self.remove_kv().1 } - // Body of `remove_entry`, separate to keep the above implementations short. + // Body of `remove_entry`, probably separate because the name reflects the returned pair. pub(super) fn remove_kv(self) -> (K, V) { let mut emptied_internal_root = false; let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index dd3ebcccf7..90bef37f71 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -6,13 +6,17 @@ use crate::fmt::Debug; use crate::rc::Rc; use crate::string::{String, ToString}; use crate::vec::Vec; +use std::cmp::Ordering; use std::convert::TryFrom; use std::iter::{self, FromIterator}; use std::mem; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::ops::RangeBounds; use std::panic::{catch_unwind, AssertUnwindSafe}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + +mod ord_chaos; +use ord_chaos::{Cyclic3, Governed, Governor}; // Capacity of a tree with a single level, // i.e., a tree who's root is a leaf node at height 0. @@ -28,7 +32,7 @@ const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1; // It's not the minimum size: removing an element from such a tree does not always reduce height. const MIN_INSERTS_HEIGHT_2: usize = 89; -// Gather all references from a mutable iterator and make sure Miri notices if +// Gathers all references from a mutable iterator and makes sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { // Gather all those references. @@ -43,28 +47,42 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator } impl BTreeMap { - /// Panics if the map (or the code navigating it) is corrupted. - fn check(&self) - where - K: Copy + Debug + Ord, - { + // Panics if the map (or the code navigating it) is corrupted. + fn check_invariants(&self) { if let Some(root) = &self.root { - let root_node = root.node_as_ref(); + let root_node = root.reborrow(); + // Check the back pointers top-down, before we attempt to rely on + // more serious navigation code. assert!(root_node.ascend().is_err()); root_node.assert_back_pointers(); + // Check consistency of `length` with what navigation code encounters. assert_eq!(self.length, root_node.calc_length()); + // Lastly, check the invariant causing the least harm. root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 }); } else { assert_eq!(self.length, 0); } - self.assert_ascending(); + // Check that `assert_strictly_ascending` will encounter all keys. + assert_eq!(self.length, self.keys().count()); } - /// Returns the height of the root, if any. + // Panics if the map is corrupted or if the keys are not in strictly + // ascending order, in the current opinion of the `Ord` implementation. + // If the `Ord` implementation violates transitivity, this method does not + // guarantee that all keys are unique, just that adjacent keys are unique. + fn check(&self) + where + K: Debug + Ord, + { + self.check_invariants(); + self.assert_strictly_ascending(); + } + + // Returns the height of the root, if any. fn height(&self) -> Option { self.root.as_ref().map(node::Root::height) } @@ -74,34 +92,30 @@ impl BTreeMap { K: Debug, { if let Some(root) = self.root.as_ref() { - root.node_as_ref().dump_keys() + root.reborrow().dump_keys() } else { String::from("not yet allocated") } } - /// Asserts that the keys are in strictly ascending order. - fn assert_ascending(&self) + // Panics if the keys are not in strictly ascending order. + fn assert_strictly_ascending(&self) where - K: Copy + Debug + Ord, + K: Debug + Ord, { - let mut num_seen = 0; let mut keys = self.keys(); if let Some(mut previous) = keys.next() { - num_seen = 1; for next in keys { assert!(previous < next, "{:?} >= {:?}", previous, next); previous = next; - num_seen += 1; } } - assert_eq!(num_seen, self.len()); } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { fn assert_min_len(self, min_len: usize) { - assert!(self.len() >= min_len, "{} < {}", self.len(), min_len); + assert!(self.len() >= min_len, "node len {} < {}", self.len(), min_len); if let node::ForceResult::Internal(node) = self.force() { for idx in 0..=node.len() { let edge = unsafe { Handle::new_edge(node, idx) }; @@ -111,7 +125,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> } } -// Test our value of MIN_INSERTS_HEIGHT_2. It may change according to the +// Tests our value of MIN_INSERTS_HEIGHT_2. It may change according to the // implementation of insertion, but it's best to be aware of when it does. #[test] fn test_levels() { @@ -149,6 +163,25 @@ fn test_levels() { assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2, "{}", map.dump_keys()); } +// Ensures the testing infrastructure usually notices order violations. +#[test] +#[should_panic] +fn test_check_ord_chaos() { + let gov = Governor::new(); + let map: BTreeMap<_, _> = (0..2).map(|i| (Governed(i, &gov), ())).collect(); + gov.flip(); + map.check(); +} + +// Ensures the testing infrastructure doesn't always mind order violations. +#[test] +fn test_check_invariants_ord_chaos() { + let gov = Governor::new(); + let map: BTreeMap<_, _> = (0..2).map(|i| (Governed(i, &gov), ())).collect(); + gov.flip(); + map.check_invariants(); +} + #[test] fn test_basic_large() { let mut map = BTreeMap::new(); @@ -334,7 +367,7 @@ fn test_iter_rev() { test(size, map.into_iter().rev()); } -/// Specifically tests iter_mut's ability to mutate the value of pairs in-line +// Specifically tests iter_mut's ability to mutate the value of pairs in-line. fn do_test_iter_mut_mutation(size: usize) where T: Copy + Debug + Ord + TryFrom, @@ -439,6 +472,8 @@ fn test_iter_entering_root_twice() { *back.1 = 42; assert_eq!(front, (&0, &mut 24)); assert_eq!(back, (&1, &mut 42)); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); map.check(); } @@ -591,11 +626,12 @@ fn test_range_small() { #[test] fn test_range_height_1() { - // Tests tree with a root and 2 leaves. Depending on details we don't want or need - // to rely upon, the single key at the root will be 6 or 7. + // Tests tree with a root and 2 leaves. The single key in the root node is + // close to the middle among the keys. - let map: BTreeMap<_, _> = (1..=MIN_INSERTS_HEIGHT_1 as i32).map(|i| (i, i)).collect(); - for &root in &[6, 7] { + let map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1 as i32).map(|i| (i, i)).collect(); + let middle = MIN_INSERTS_HEIGHT_1 as i32 / 2; + for root in middle - 2..=middle + 2 { assert_eq!(range_keys(&map, (Excluded(root), Excluded(root + 1))), vec![]); assert_eq!(range_keys(&map, (Excluded(root), Included(root + 1))), vec![root + 1]); assert_eq!(range_keys(&map, (Included(root), Excluded(root + 1))), vec![root]); @@ -727,6 +763,19 @@ fn test_range_backwards_4() { map.range((Excluded(3), Excluded(2))); } +#[test] +#[should_panic] +fn test_range_backwards_5() { + let mut map = BTreeMap::new(); + map.insert(Cyclic3::B, ()); + // Lacking static_assert, call `range` conditionally, to emphasise that + // we cause a different panic than `test_range_backwards_1` does. + // A more refined `should_panic` would be welcome. + if Cyclic3::C < Cyclic3::A { + map.range(Cyclic3::C..=Cyclic3::A); + } +} + #[test] fn test_range_1000() { // Miri is too slow @@ -808,6 +857,17 @@ fn test_range_mut() { map.check(); } +#[test] +fn test_retain() { + let mut map: BTreeMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); +} + mod test_drain_filter { use super::*; @@ -819,22 +879,26 @@ mod test_drain_filter { map.check(); } + // Explicitly consumes the iterator, where most test cases drop it instantly. #[test] - fn consuming_nothing() { + fn consumed_keeping_all() { let pairs = (0..3).map(|i| (i, i)); let mut map: BTreeMap<_, _> = pairs.collect(); assert!(map.drain_filter(|_, _| false).eq(iter::empty())); map.check(); } + // Explicitly consumes the iterator, where most test cases drop it instantly. #[test] - fn consuming_all() { + fn consumed_removing_all() { let pairs = (0..3).map(|i| (i, i)); let mut map: BTreeMap<_, _> = pairs.clone().collect(); assert!(map.drain_filter(|_, _| true).eq(pairs)); + assert!(map.is_empty()); map.check(); } + // Explicitly consumes the iterator and modifies values through it. #[test] fn mutating_and_keeping() { let pairs = (0..3).map(|i| (i, i)); @@ -851,6 +915,7 @@ mod test_drain_filter { map.check(); } + // Explicitly consumes the iterator and modifies values through it. #[test] fn mutating_and_removing() { let pairs = (0..3).map(|i| (i, i)); @@ -1024,7 +1089,7 @@ mod test_drain_filter { struct D; impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + if DROPS.fetch_add(1, SeqCst) == 1 { panic!("panic in `drop`"); } } @@ -1035,14 +1100,14 @@ mod test_drain_filter { catch_unwind(move || { drop(map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, Ordering::SeqCst); + PREDS.fetch_add(1usize << i, SeqCst); true })) }) .unwrap_err(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 3); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 3); } #[test] @@ -1053,7 +1118,7 @@ mod test_drain_filter { struct D; impl Drop for D { fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); + DROPS.fetch_add(1, SeqCst); } } @@ -1062,7 +1127,7 @@ mod test_drain_filter { catch_unwind(AssertUnwindSafe(|| { drop(map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, Ordering::SeqCst); + PREDS.fetch_add(1usize << i, SeqCst); match i { 0 => true, _ => panic!(), @@ -1071,8 +1136,8 @@ mod test_drain_filter { })) .unwrap_err(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 1); assert_eq!(map.len(), 2); assert_eq!(map.first_entry().unwrap().key(), &4); assert_eq!(map.last_entry().unwrap().key(), &8); @@ -1088,7 +1153,7 @@ mod test_drain_filter { struct D; impl Drop for D { fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); + DROPS.fetch_add(1, SeqCst); } } @@ -1097,7 +1162,7 @@ mod test_drain_filter { { let mut it = map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, Ordering::SeqCst); + PREDS.fetch_add(1usize << i, SeqCst); match i { 0 => true, _ => panic!(), @@ -1110,8 +1175,8 @@ mod test_drain_filter { assert!(matches!(result, Ok(None))); } - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 1); assert_eq!(map.len(), 2); assert_eq!(map.first_entry().unwrap().key(), &4); assert_eq!(map.last_entry().unwrap().key(), &8); @@ -1245,8 +1310,6 @@ fn test_zst() { // undefined. #[test] fn test_bad_zst() { - use std::cmp::Ordering; - #[derive(Clone, Copy, Debug)] struct Bad; @@ -1693,7 +1756,7 @@ fn test_append_drop_leak() { impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 0 { + if DROPS.fetch_add(1, SeqCst) == 0 { panic!("panic in `drop`"); } } @@ -1709,7 +1772,28 @@ fn test_append_drop_leak() { catch_unwind(move || left.append(&mut right)).unwrap_err(); - assert_eq!(DROPS.load(Ordering::SeqCst), 4); // Rust issue #47949 ate one little piggy + assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy +} + +#[test] +fn test_append_ord_chaos() { + let mut map1 = BTreeMap::new(); + map1.insert(Cyclic3::A, ()); + map1.insert(Cyclic3::B, ()); + let mut map2 = BTreeMap::new(); + map2.insert(Cyclic3::A, ()); + map2.insert(Cyclic3::B, ()); + map2.insert(Cyclic3::C, ()); // lands first, before A + map2.insert(Cyclic3::B, ()); // lands first, before C + map1.check(); + map2.check(); // keys are not unique but still strictly ascending + assert_eq!(map1.len(), 2); + assert_eq!(map2.len(), 4); + map1.append(&mut map2); + assert_eq!(map1.len(), 5); + assert_eq!(map2.len(), 0); + map1.check(); + map2.check(); } fn rand_data(len: usize) -> Vec<(u32, u32)> { @@ -1803,7 +1887,7 @@ fn test_into_iter_drop_leak_height_0() { impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 3 { + if DROPS.fetch_add(1, SeqCst) == 3 { panic!("panic in `drop`"); } } @@ -1818,7 +1902,7 @@ fn test_into_iter_drop_leak_height_0() { catch_unwind(move || drop(map.into_iter())).unwrap_err(); - assert_eq!(DROPS.load(Ordering::SeqCst), 5); + assert_eq!(DROPS.load(SeqCst), 5); } #[test] @@ -1830,18 +1914,18 @@ fn test_into_iter_drop_leak_height_1() { struct D; impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == PANIC_POINT.load(Ordering::SeqCst) { + if DROPS.fetch_add(1, SeqCst) == PANIC_POINT.load(SeqCst) { panic!("panic in `drop`"); } } } for panic_point in vec![0, 1, size - 2, size - 1] { - DROPS.store(0, Ordering::SeqCst); - PANIC_POINT.store(panic_point, Ordering::SeqCst); + DROPS.store(0, SeqCst); + PANIC_POINT.store(panic_point, SeqCst); let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect(); catch_unwind(move || drop(map.into_iter())).unwrap_err(); - assert_eq!(DROPS.load(Ordering::SeqCst), size); + assert_eq!(DROPS.load(SeqCst), size); } } @@ -1874,11 +1958,27 @@ fn test_insert_remove_intertwined() { let loops = if cfg!(miri) { 100 } else { 1_000_000 }; let mut map = BTreeMap::new(); let mut i = 1; + let offset = 165; // somewhat arbitrarily chosen to cover some code paths for _ in 0..loops { - i = (i + 421) & 0xFF; + i = (i + offset) & 0xFF; map.insert(i, i); map.remove(&(0xFF - i)); } - map.check(); } + +#[test] +fn test_insert_remove_intertwined_ord_chaos() { + let loops = if cfg!(miri) { 100 } else { 1_000_000 }; + let gov = Governor::new(); + let mut map = BTreeMap::new(); + let mut i = 1; + let offset = 165; // more arbitrarily copied from above + for _ in 0..loops { + i = (i + offset) & 0xFF; + map.insert(Governed(i, &gov), ()); + map.remove(&Governed(0xFF - i, &gov)); + gov.flip(); + } + map.check_invariants(); +} diff --git a/library/alloc/src/collections/btree/map/tests/ord_chaos.rs b/library/alloc/src/collections/btree/map/tests/ord_chaos.rs new file mode 100644 index 0000000000..96ce7c1579 --- /dev/null +++ b/library/alloc/src/collections/btree/map/tests/ord_chaos.rs @@ -0,0 +1,81 @@ +use std::cell::Cell; +use std::cmp::Ordering::{self, *}; +use std::ptr; + +// Minimal type with an `Ord` implementation violating transitivity. +#[derive(Debug)] +pub enum Cyclic3 { + A, + B, + C, +} +use Cyclic3::*; + +impl PartialOrd for Cyclic3 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Cyclic3 { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (A, A) | (B, B) | (C, C) => Equal, + (A, B) | (B, C) | (C, A) => Less, + (A, C) | (B, A) | (C, B) => Greater, + } + } +} + +impl PartialEq for Cyclic3 { + fn eq(&self, other: &Self) -> bool { + self.cmp(&other) == Equal + } +} + +impl Eq for Cyclic3 {} + +// Controls the ordering of values wrapped by `Governed`. +#[derive(Debug)] +pub struct Governor { + flipped: Cell, +} + +impl Governor { + pub fn new() -> Self { + Governor { flipped: Cell::new(false) } + } + + pub fn flip(&self) { + self.flipped.set(!self.flipped.get()); + } +} + +// Type with an `Ord` implementation that forms a total order at any moment +// (assuming that `T` respects total order), but can suddenly be made to invert +// that total order. +#[derive(Debug)] +pub struct Governed<'a, T>(pub T, pub &'a Governor); + +impl PartialOrd for Governed<'_, T> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Governed<'_, T> { + fn cmp(&self, other: &Self) -> Ordering { + assert!(ptr::eq(self.1, other.1)); + let ord = self.0.cmp(&other.0); + if self.1.flipped.get() { ord.reverse() } else { ord } + } +} + +impl PartialEq for Governed<'_, T> { + fn eq(&self, other: &Self) -> bool { + assert!(ptr::eq(self.1, other.1)); + self.0.eq(&other.0) + } +} + +impl Eq for Governed<'_, T> {} diff --git a/library/alloc/src/collections/btree/mem.rs b/library/alloc/src/collections/btree/mem.rs index 5e7d9fa3f9..e1363d1ae1 100644 --- a/library/alloc/src/collections/btree/mem.rs +++ b/library/alloc/src/collections/btree/mem.rs @@ -6,6 +6,7 @@ use core::ptr; /// relevant function. /// /// If a panic occurs in the `change` closure, the entire process will be aborted. +#[allow(dead_code)] // keep as illustration and for future use #[inline] pub fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { replace(v, |value| (change(value), ())) diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index de78148fc8..cce8b21a2b 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -9,6 +9,9 @@ use super::search::{self, SearchResult}; use super::unwrap_unchecked; /// Finds the leaf edges delimiting a specified range in or underneath a node. +/// +/// The result is meaningful only if the tree is ordered by key, like the tree +/// in a `BTreeMap` is. fn range_search( root1: NodeRef, root2: NodeRef, @@ -122,6 +125,9 @@ fn full_range( impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Creates a pair of leaf edges delimiting a specified range in or underneath a node. + /// + /// The result is meaningful only if the tree is ordered by key, like the tree + /// in a `BTreeMap` is. pub fn range_search( self, range: R, @@ -152,6 +158,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> /// Splits a unique reference into a pair of leaf edges delimiting a specified range. /// The result are non-unique references allowing (some) mutation, which must be used /// carefully. + /// + /// The result is meaningful only if the tree is ordered by key, like the tree + /// in a `BTreeMap` is. pub fn range_search( self, range: R, @@ -362,20 +371,6 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::E } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { - /// Moves the leaf edge handle to the next leaf edge. - /// - /// # Safety - /// There must be another KV in the direction travelled. - pub unsafe fn move_next_unchecked(&mut self) { - super::mem::take_mut(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unsafe { unwrap_unchecked(kv.ok()) }; - kv.next_leaf_edge() - }) - } -} - impl Handle, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns the key and value /// in between, deallocating any node left behind while leaving the corresponding diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index dbf9031620..769383515b 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -27,13 +27,17 @@ // given node has exactly the same length. // - A node of length `n` has `n` keys, `n` values, and `n + 1` edges. // This implies that even an empty node has at least one edge. +// For a leaf node, "having an edge" only means we can identify a position in the node, +// since leaf edges are empty and need no data representation. In an internal node, +// an edge both identifies a position and contains a pointer to a child node. use core::cmp::Ordering; use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; -use core::ptr::{self, NonNull, Unique}; +use core::ptr::{self, NonNull}; +use core::slice::SliceIndex; -use crate::alloc::{AllocRef, Global, Layout}; +use crate::alloc::{Allocator, Global, Layout}; use crate::boxed::Box; const B: usize = 6; @@ -112,102 +116,65 @@ impl InternalNode { /// /// However, `BoxedNode` contains no information as to which of the two types /// of nodes it actually contains, and, partially due to this lack of information, -/// has no destructor. -struct BoxedNode { - ptr: Unique>, -} - -impl BoxedNode { - fn from_leaf(node: Box>) -> Self { - BoxedNode { ptr: Unique::from(Box::leak(node)) } - } - - fn from_internal(node: Box>) -> Self { - BoxedNode { ptr: Unique::from(Box::leak(node)).cast() } - } - - fn as_ptr(&self) -> NonNull> { - NonNull::from(self.ptr) - } -} +/// is not a separate type and has no destructor. +type BoxedNode = NonNull>; /// An owned tree. /// /// Note that this does not have a destructor, and must be cleaned up manually. -pub struct Root { - node: BoxedNode, - /// The number of levels below the root node. - height: usize, -} - -unsafe impl Sync for Root {} -unsafe impl Send for Root {} +pub type Root = NodeRef; impl Root { - /// Returns the number of levels below the root. - pub fn height(&self) -> usize { - self.height - } - /// Returns a new owned tree, with its own root node that is initially empty. - pub fn new_leaf() -> Self { - Root { node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), height: 0 } - } - - /// Borrows and returns an immutable reference to the node owned by the root. - pub fn node_as_ref(&self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } - } - - /// Borrows and returns a mutable reference to the node owned by the root. - pub fn node_as_mut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + pub fn new() -> Self { + NodeRef::new_leaf().forget_type() } +} - /// Borrows and returns a mutable reference to the leaf node owned by the root. - /// # Safety - /// The root node is a leaf. - unsafe fn leaf_node_as_mut(&mut self) -> NodeRef, K, V, marker::Leaf> { - debug_assert!(self.height == 0); - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } +impl NodeRef { + fn new_leaf() -> Self { + Self::from_new_leaf(Box::new(unsafe { LeafNode::new() })) } - /// Borrows and returns a mutable reference to the internal node owned by the root. - /// # Safety - /// The root node is not a leaf. - unsafe fn internal_node_as_mut(&mut self) -> NodeRef, K, V, marker::Internal> { - debug_assert!(self.height > 0); - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + fn from_new_leaf(leaf: Box>) -> Self { + NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData } } +} - pub fn node_as_valmut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } +impl NodeRef { + fn from_new_internal(internal: Box>, height: usize) -> Self { + NodeRef { height, node: NonNull::from(Box::leak(internal)).cast(), _marker: PhantomData } } +} - pub fn into_ref(self) -> NodeRef { - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } +impl NodeRef { + /// Mutably borrows the owned node. Unlike `reborrow_mut`, this is safe, + /// because the return value cannot be used to destroy the node itself, + /// and there cannot be other references to the tree (except during the + /// process of `into_iter` or `drop`, but that is horrific already). + pub fn borrow_mut(&mut self) -> NodeRef, K, V, Type> { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - /// Packs the reference, aware of type and height, into a type-agnostic pointer. - fn into_boxed_node(self) -> BoxedNode { - self.node + /// Slightly mutably borrows the owned node. + pub fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } +} +impl NodeRef { /// Adds a new internal node with a single edge pointing to the previous root node, /// make that new node the root node, and return it. This increases the height by 1 /// and is the opposite of `pop_internal_level`. pub fn push_internal_level(&mut self) -> NodeRef, K, V, marker::Internal> { let mut new_node = Box::new(unsafe { InternalNode::new() }); - new_node.edges[0].write(unsafe { ptr::read(&mut self.node) }); - - self.node = BoxedNode::from_internal(new_node); - self.height += 1; + new_node.edges[0].write(self.node); + let mut new_root = NodeRef::from_new_internal(new_node, self.height + 1); + new_root.borrow_mut().first_edge().correct_parent_link(); + *self = new_root.forget_type(); - unsafe { - let mut ret = self.internal_node_as_mut(); - ret.reborrow_mut().first_edge().correct_parent_link(); - ret - } + // `self.borrow_mut()`, except that we just forgot we're internal now: + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Removes the internal root node, using its first child as the new root node. @@ -216,22 +183,20 @@ impl Root { /// This decreases the height by 1 and is the opposite of `push_internal_level`. /// /// Requires exclusive access to the `Root` object but not to the root node; - /// it will not invalidate existing handles or references to the root node. + /// it will not invalidate other handles or references to the root node. /// /// Panics if there is no internal level, i.e., if the root node is a leaf. pub fn pop_internal_level(&mut self) { assert!(self.height > 0); - let top = BoxedNode::as_ptr(&self.node); + let top = self.node; - let mut internal_node = unsafe { self.internal_node_as_mut() }; - let internal_node = NodeRef::as_internal_mut(&mut internal_node); - self.node = unsafe { internal_node.edges[0].assume_init_read() }; - self.height -= 1; - self.node_as_mut().clear_parent_link(); + let internal_node = NodeRef { height: self.height, node: top, _marker: PhantomData }; + *self = internal_node.first_edge().descend(); + self.clear_parent_link(); unsafe { - Global.dealloc(top.cast(), Layout::new::>()); + Global.deallocate(top.cast(), Layout::new::>()); } } } @@ -254,6 +219,8 @@ impl Root { /// although insert methods allow a mutable pointer to a value to coexist. /// - When this is `Owned`, the `NodeRef` acts roughly like `Box`, /// but does not have a destructor, and must be cleaned up manually. +/// Since any `NodeRef` allows navigating through the tree, `BorrowType` +/// effectively applies to the entire tree, not just the node itself. /// - `K` and `V`: These are the types of keys and values stored in the nodes. /// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is /// `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the @@ -266,29 +233,29 @@ impl Root { /// such restrictions: /// - For each type parameter, we can only define a method either generically /// or for one particular type. For example, we cannot define a method like -/// `key_at` generically for all `BorrowType`, because we want to return +/// `key_at` generically for all `BorrowType`, because we want it to return /// `&'a K` for most choices of `BorrowType`, but plain `K` for `Owned`. -/// We cannot define `key_at` once for all types that have a lifetime. +/// We cannot define `key_at` once for all types that carry a lifetime. /// Therefore, we define it only for the least powerful type `Immut<'a>`. /// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`. /// Therefore, we have to explicitly call `reborrow` on a more powerfull /// `NodeRef` in order to reach a method like `key_at`. -/// - All methods on `NodeRef` that return some kind of reference, except -/// `reborrow` and `reborrow_mut`, take `self` by value and not by reference. -/// This avoids silently returning a second reference somewhere in the tree. -/// That is irrelevant when `BorrowType` is `Immut<'a>`, but the rule does -/// no harm because we make those `NodeRef` implicitly `Copy`. -/// The rule also avoids implicitly returning the lifetime of `&self`, -/// instead of the lifetime contained in `BorrowType`. -/// An exception to this rule are the insert functions. -/// - Given the above, we need a `reborrow_mut` to explicitly copy a `Mut<'a>` -/// `NodeRef` whenever we want to invoke a method returning an extra reference -/// somewhere in the tree. +/// +/// All methods on `NodeRef` that return some kind of reference, either: +/// - Take `self` by value, and return the lifetime carried by `BorrowType`. +/// Sometimes, to invoke such a method, we need to call `reborrow_mut`. +/// - Take `self` by reference, and (implicitly) return that reference's +/// lifetime, instead of the lifetime carried by `BorrowType`. That way, +/// the borrow checker guarantees that the `NodeRef` remains borrowed as long +/// as the returned reference is used. +/// The methods supporting insert bend this rule by returning a raw pointer, +/// i.e., a reference without any lifetime. pub struct NodeRef { - /// The number of levels below the node, a property of the node that cannot be - /// entirely described by `Type` and that the node does not store itself either. - /// Unconstrained if `Type` is `LeafOrInternal`, must be zero if `Type` is `Leaf`, - /// and must be non-zero if `Type` is `Internal`. + /// The number of levels that the node and the level of leaves are apart, a + /// constant of the node that cannot be entirely described by `Type`, and that + /// the node itself does not store. We only need to store the height of the root + /// node, and derive every other node's height from it. + /// Must be zero if `Type` is `Leaf` and non-zero if `Type` is `Internal`. height: usize, /// The pointer to the leaf or internal node. The definition of `InternalNode` /// ensures that the pointer is valid either way. @@ -310,13 +277,6 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef Send for NodeRef, K, V, Type> {} unsafe impl Send for NodeRef {} -impl NodeRef { - /// Unpack a node reference that was packed by `Root::into_boxed_node`. - fn from_boxed_node(boxed_node: BoxedNode, height: usize) -> Self { - NodeRef { height, node: boxed_node.as_ptr(), _marker: PhantomData } - } -} - impl NodeRef { /// Unpack a node reference that was packed as `NodeRef::parent`. fn from_internal(node: NonNull>, height: usize) -> Self { @@ -345,9 +305,9 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { } impl<'a, K, V> NodeRef, K, V, marker::Internal> { - /// Offers exclusive access to the data of an internal node. - fn as_internal_mut(this: &mut Self) -> &'a mut InternalNode { - let ptr = Self::as_internal_ptr(this); + /// Borrows exclusive access to the data of an internal node. + fn as_internal_mut(&mut self) -> &mut InternalNode { + let ptr = Self::as_internal_ptr(self); unsafe { &mut *ptr } } } @@ -363,8 +323,11 @@ impl NodeRef { unsafe { usize::from((*Self::as_leaf_ptr(self)).len) } } - /// Returns the height of this node with respect to the leaf level. Zero height means the - /// node is a leaf itself. + /// Returns the number of levels that the node and leaves are apart. Zero + /// height means the node is a leaf itself. If you picture trees with the + /// root on top, the number says at which elevation the node appears. + /// If you picture trees with leaves on top, the number says how high + /// the tree extends above the node. pub fn height(&self) -> usize { self.height } @@ -392,7 +355,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// The node has more than `idx` initialized elements. pub unsafe fn key_at(self, idx: usize) -> &'a K { debug_assert!(idx < self.len()); - unsafe { Self::as_leaf(&self).keys.get_unchecked(idx).assume_init_ref() } + unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() } } /// Exposes one of the values stored in the node. @@ -401,7 +364,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// The node has more than `idx` initialized elements. unsafe fn val_at(self, idx: usize) -> &'a V { debug_assert!(idx < self.len()); - unsafe { Self::as_leaf(&self).vals.get_unchecked(idx).assume_init_ref() } + unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() } } } @@ -422,6 +385,8 @@ impl NodeRef { /// that points to the current node. Returns `Err(self)` if the current node has /// no parent, giving back the original `NodeRef`. /// + /// The method name assumes you picture trees with the root node on top. + /// /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. pub fn ascend( @@ -466,8 +431,8 @@ impl NodeRef { impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// Exposes the leaf portion of any leaf or internal node in an immutable tree. - fn as_leaf(this: &Self) -> &'a LeafNode { - let ptr = Self::as_leaf_ptr(this); + fn into_leaf(self) -> &'a LeafNode { + let ptr = Self::as_leaf_ptr(&self); // SAFETY: there can be no mutable references into this tree borrowed as `Immut`. unsafe { &*ptr } } @@ -484,7 +449,7 @@ impl NodeRef { let node = self.node; let ret = self.ascend().ok(); unsafe { - Global.dealloc( + Global.deallocate( node.cast(), if height > 0 { Layout::new::>() @@ -498,6 +463,12 @@ impl NodeRef { } impl<'a, K, V, Type> NodeRef, K, V, Type> { + /// Unsafely asserts to the compiler the static information that this node is a `Leaf`. + unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { + debug_assert!(self.height == 0); + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } + /// Unsafely asserts to the compiler the static information that this node is an `Internal`. unsafe fn cast_to_internal_unchecked(self) -> NodeRef, K, V, marker::Internal> { debug_assert!(self.height > 0); @@ -518,42 +489,64 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } + /// Borrows exclusive access to the leaf portion of any leaf or internal node. + fn as_leaf_mut(&mut self) -> &mut LeafNode { + let ptr = Self::as_leaf_ptr(self); + // SAFETY: we have exclusive access to the entire node. + unsafe { &mut *ptr } + } + /// Offers exclusive access to the leaf portion of any leaf or internal node. - fn as_leaf_mut(this: &mut Self) -> &'a mut LeafNode { - let ptr = Self::as_leaf_ptr(this); + fn into_leaf_mut(mut self) -> &'a mut LeafNode { + let ptr = Self::as_leaf_ptr(&mut self); // SAFETY: we have exclusive access to the entire node. unsafe { &mut *ptr } } } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Offers exclusive access to a part of the key storage area. + /// Borrows exclusive access to an element of the key storage area. /// /// # Safety - /// The node has more than `idx` initialized elements. - unsafe fn into_key_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit { - debug_assert!(idx < self.len()); - unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(idx) } + /// `index` is in bounds of 0..CAPACITY + unsafe fn key_area_mut_at(&mut self, index: I) -> &mut Output + where + I: SliceIndex<[MaybeUninit], Output = Output>, + { + // SAFETY: the caller will not be able to call further methods on self + // until the key slice reference is dropped, as we have unique access + // for the lifetime of the borrow. + unsafe { self.as_leaf_mut().keys.as_mut_slice().get_unchecked_mut(index) } } - /// Offers exclusive access to a part of the value storage area. + /// Borrows exclusive access to an element or slice of the node's value storage area. /// /// # Safety - /// The node has more than `idx` initialized elements. - unsafe fn into_val_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit { - debug_assert!(idx < self.len()); - unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(idx) } + /// `index` is in bounds of 0..CAPACITY + unsafe fn val_area_mut_at(&mut self, index: I) -> &mut Output + where + I: SliceIndex<[MaybeUninit], Output = Output>, + { + // SAFETY: the caller will not be able to call further methods on self + // until the value slice reference is dropped, as we have unique access + // for the lifetime of the borrow. + unsafe { self.as_leaf_mut().vals.as_mut_slice().get_unchecked_mut(index) } } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { - /// Offers exclusive access to a part of the storage area for edge contents. + /// Borrows exclusive access to an element or slice of the node's storage area for edge contents. /// /// # Safety - /// The node has at least `idx` initialized elements. - unsafe fn into_edge_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit> { - debug_assert!(idx <= self.len()); - unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(idx) } + /// `index` is in bounds of 0..CAPACITY + 1 + unsafe fn edge_area_mut_at(&mut self, index: I) -> &mut Output + where + I: SliceIndex<[MaybeUninit>], Output = Output>, + { + // SAFETY: the caller will not be able to call further methods on self + // until the edge slice reference is dropped, as we have unique access + // for the lifetime of the borrow. + unsafe { self.as_internal_mut().edges.as_mut_slice().get_unchecked_mut(index) } } } @@ -562,14 +555,14 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { /// regardless of the node's current length, /// having exclusive access to the entire node. unsafe fn key_area(self) -> &'a [MaybeUninit] { - Self::as_leaf(&self).keys.as_slice() + self.into_leaf().keys.as_slice() } /// Exposes the entire value storage area in the node, /// regardless of the node's current length, /// having exclusive access to the entire node. unsafe fn val_area(self) -> &'a [MaybeUninit] { - Self::as_leaf(&self).vals.as_slice() + self.into_leaf().vals.as_slice() } } @@ -582,41 +575,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { } } -impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Offers exclusive access to a sized slice of key storage area in the node. - unsafe fn into_key_area_slice(mut self) -> &'a mut [MaybeUninit] { - let len = self.len(); - // SAFETY: the caller will not be able to call further methods on self - // until the key slice reference is dropped, as we have unique access - // for the lifetime of the borrow. - unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(..len) } - } - - /// Offers exclusive access to a sized slice of value storage area in the node. - unsafe fn into_val_area_slice(mut self) -> &'a mut [MaybeUninit] { - let len = self.len(); - // SAFETY: the caller will not be able to call further methods on self - // until the value slice reference is dropped, as we have unique access - // for the lifetime of the borrow. - unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(..len) } - } -} - -impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { - /// Offers exclusive access to a sized slice of storage area for edge contents in the node. - unsafe fn into_edge_area_slice(mut self) -> &'a mut [MaybeUninit>] { - let len = self.len(); - // SAFETY: the caller will not be able to call further methods on self - // until the edge slice reference is dropped, as we have unique access - // for the lifetime of the borrow. - unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(..len + 1) } - } -} - impl<'a, K, V, Type> NodeRef, K, V, Type> { /// # Safety /// - The node has more than `idx` initialized elements. - /// - The keys and values of the node must be initialized up to its current length. unsafe fn into_key_val_mut_at(mut self, idx: usize) -> (&'a K, &'a mut V) { // We only create a reference to the one element we are interested in, // to avoid aliasing with outstanding references to other elements, @@ -634,50 +595,52 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Exposes exclusive access to the length of the node. - pub fn into_len_mut(mut self) -> &'a mut u16 { - &mut (*Self::as_leaf_mut(&mut self)).len + /// Borrows exclusive access to the length of the node. + pub fn len_mut(&mut self) -> &mut u16 { + &mut self.as_leaf_mut().len } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { - /// Set or clear the node's link to its parent edge, + /// Sets the node's link to its parent edge, /// without invalidating other references to the node. fn set_parent_link(&mut self, parent: NonNull>, parent_idx: usize) { let leaf = Self::as_leaf_ptr(self); unsafe { (*leaf).parent = Some(parent) }; unsafe { (*leaf).parent_idx.write(parent_idx as u16) }; } +} - /// Clear the node's link to its parent edge, freeing it from its tree. - /// This only makes sense when there are no other references to the node. +impl NodeRef { + /// Clears the root's link to its parent edge. fn clear_parent_link(&mut self) { - let leaf = Self::as_leaf_mut(self); + let mut root_node = self.borrow_mut(); + let leaf = root_node.as_leaf_mut(); leaf.parent = None; } } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { - /// Adds a key/value pair to the end of the node. + /// Adds a key-value pair to the end of the node. pub fn push(&mut self, key: K, val: V) { - let len = unsafe { self.reborrow_mut().into_len_mut() }; + let len = self.len_mut(); let idx = usize::from(*len); assert!(idx < CAPACITY); *len += 1; unsafe { - self.reborrow_mut().into_key_area_mut_at(idx).write(key); - self.reborrow_mut().into_val_area_mut_at(idx).write(val); + self.key_area_mut_at(idx).write(key); + self.val_area_mut_at(idx).write(val); } } - /// Adds a key/value pair to the beginning of the node. + /// Adds a key-value pair to the beginning of the node. fn push_front(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); - + let new_len = self.len() + 1; + assert!(new_len <= CAPACITY); unsafe { - *self.reborrow_mut().into_len_mut() += 1; - slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key); - slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val); + slice_insert(self.key_area_mut_at(..new_len), 0, key); + slice_insert(self.val_area_mut_at(..new_len), 0, val); + *self.len_mut() = new_len as u16; } } } @@ -699,34 +662,35 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { - /// Adds a key/value pair, and an edge to go to the right of that pair, + /// Adds a key-value pair, and an edge to go to the right of that pair, /// to the end of the node. pub fn push(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); - let len = unsafe { self.reborrow_mut().into_len_mut() }; + let len = self.len_mut(); let idx = usize::from(*len); assert!(idx < CAPACITY); *len += 1; unsafe { - self.reborrow_mut().into_key_area_mut_at(idx).write(key); - self.reborrow_mut().into_val_area_mut_at(idx).write(val); - self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.into_boxed_node()); + self.key_area_mut_at(idx).write(key); + self.val_area_mut_at(idx).write(val); + self.edge_area_mut_at(idx + 1).write(edge.node); Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } - /// Adds a key/value pair, and an edge to go to the left of that pair, + /// Adds a key-value pair, and an edge to go to the left of that pair, /// to the beginning of the node. fn push_front(&mut self, key: K, val: V, edge: Root) { + let new_len = self.len() + 1; assert!(edge.height == self.height - 1); - assert!(self.len() < CAPACITY); + assert!(new_len <= CAPACITY); unsafe { - *self.reborrow_mut().into_len_mut() += 1; - slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key); - slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val); - slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.into_boxed_node()); + slice_insert(self.key_area_mut_at(..new_len), 0, key); + slice_insert(self.val_area_mut_at(..new_len), 0, val); + slice_insert(self.edge_area_mut_at(..new_len + 1), 0, edge.node); + *self.len_mut() = new_len as u16; } self.correct_all_childrens_parent_links(); @@ -734,7 +698,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { } impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { - /// Removes a key/value pair from the end of the node and returns the pair. + /// Removes a key-value pair from the end of the node and returns the pair. /// Also removes the edge that was to the right of that pair and, if the node /// is internal, returns the orphaned subtree that this edge owned. fn pop(&mut self) -> (K, V, Option>) { @@ -748,21 +712,21 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(internal) => { - let boxed_node = ptr::read(internal.reborrow().edge_at(idx + 1)); - let mut edge = Root { node: boxed_node, height: internal.height - 1 }; - // In practice, clearing the parent is a waste of time, because we will + let node = ptr::read(internal.reborrow().edge_at(idx + 1)); + let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; + // Currently, clearing the parent link is superfluous, because we will // insert the node elsewhere and set its parent link again. - edge.node_as_mut().clear_parent_link(); + edge.clear_parent_link(); Some(edge) } }; - *self.reborrow_mut().into_len_mut() -= 1; + *self.len_mut() -= 1; (key, val, edge) } } - /// Removes a key/value pair from the beginning of the node and returns the pair. + /// Removes a key-value pair from the beginning of the node and returns the pair. /// Also removes the edge that was to the left of that pair and, if the node is /// internal, returns the orphaned subtree that this edge owned. fn pop_front(&mut self) -> (K, V, Option>) { @@ -771,17 +735,16 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let old_len = self.len(); unsafe { - let key = slice_remove(self.reborrow_mut().into_key_area_slice(), 0); - let val = slice_remove(self.reborrow_mut().into_val_area_slice(), 0); + let key = slice_remove(self.key_area_mut_at(..old_len), 0); + let val = slice_remove(self.val_area_mut_at(..old_len), 0); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let boxed_node = - slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0); - let mut edge = Root { node: boxed_node, height: internal.height - 1 }; - // In practice, clearing the parent is a waste of time, because we will + let node = slice_remove(internal.edge_area_mut_at(..old_len + 1), 0); + let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; + // Currently, clearing the parent link is superfluous, because we will // insert the node elsewhere and set its parent link again. - edge.node_as_mut().clear_parent_link(); + edge.clear_parent_link(); internal.correct_childrens_parent_links(0..old_len); @@ -789,14 +752,14 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { } }; - *self.reborrow_mut().into_len_mut() -= 1; + *self.len_mut() -= 1; (key, val, edge) } } fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) { - let leaf = Self::as_leaf_mut(&mut self); + let leaf = self.as_leaf_mut(); let keys = MaybeUninit::slice_as_mut_ptr(&mut leaf.keys); let vals = MaybeUninit::slice_as_mut_ptr(&mut leaf.vals); (keys, vals) @@ -827,12 +790,12 @@ impl NodeRef { } } -/// A reference to a specific key/value pair or edge within a node. The `Node` parameter -/// must be a `NodeRef`, while the `Type` can either be `KV` (signifying a handle on a key/value +/// A reference to a specific key-value pair or edge within a node. The `Node` parameter +/// must be a `NodeRef`, while the `Type` can either be `KV` (signifying a handle on a key-value /// pair) or `Edge` (signifying a handle on an edge). /// /// Note that even `Leaf` nodes can have `Edge` handles. Instead of representing a pointer to -/// a child node, these represent the spaces where child pointers would go between the key/value +/// a child node, these represent the spaces where child pointers would go between the key-value /// pairs. For example, in a node with length 2, there would be 3 possible edge locations - one /// to the left of the node, one between the two pairs, and one at the right of the node. pub struct Handle { @@ -851,7 +814,7 @@ impl Clone for Handle { } impl Handle { - /// Retrieves the node that contains the edge or key/value pair this handle points to. + /// Retrieves the node that contains the edge or key-value pair this handle points to. pub fn into_node(self) -> Node { self.node } @@ -863,7 +826,7 @@ impl Handle { } impl Handle, marker::KV> { - /// Creates a new handle to a key/value pair in `node`. + /// Creates a new handle to a key-value pair in `node`. /// Unsafe because the caller must ensure that `idx < node.len()`. pub unsafe fn new_kv(node: NodeRef, idx: usize) -> Self { debug_assert!(idx < node.len()); @@ -883,7 +846,7 @@ impl Handle, mar impl NodeRef { /// Could be a public implementation of PartialEq, but only used in this module. fn eq(&self, other: &Self) -> bool { - let Self { node, height, _marker: _ } = self; + let Self { node, height, _marker } = self; if node.eq(&other.node) { debug_assert_eq!(*height, other.height); true @@ -897,7 +860,7 @@ impl PartialEq for Handle, HandleType> { fn eq(&self, other: &Self) -> bool { - let Self { node, idx, _marker: _ } = self; + let Self { node, idx, _marker } = self; node.eq(&other.node) && *idx == other.idx } } @@ -906,7 +869,7 @@ impl PartialOrd for Handle, HandleType> { fn partial_cmp(&self, other: &Self) -> Option { - let Self { node, idx, _marker: _ } = self; + let Self { node, idx, _marker } = self; if node.eq(&other.node) { Some(idx.cmp(&other.idx)) } else { None } } } @@ -922,6 +885,14 @@ impl } impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeType>, HandleType> { + /// Unsafely asserts to the compiler the static information that the handle's node is a `Leaf`. + pub unsafe fn cast_to_leaf_unchecked( + self, + ) -> Handle, K, V, marker::Leaf>, HandleType> { + let node = unsafe { self.node.cast_to_leaf_unchecked() }; + Handle { node, idx: self.idx, _marker: PhantomData } + } + /// Temporarily takes out another, mutable handle on the same location. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. @@ -961,9 +932,9 @@ impl Handle, mar } } -enum InsertionPlace { - Left(usize), - Right(usize), +pub enum LeftOrRight { + Left(T), + Right(T), } /// Given an edge index where we want to insert into a node filled to capacity, @@ -971,38 +942,39 @@ enum InsertionPlace { /// The goal of the split point is for its key and value to end up in a parent node; /// the keys, values and edges to the left of the split point become the left child; /// the keys, values and edges to the right of the split point become the right child. -fn splitpoint(edge_idx: usize) -> (usize, InsertionPlace) { +fn splitpoint(edge_idx: usize) -> (usize, LeftOrRight) { debug_assert!(edge_idx <= CAPACITY); // Rust issue #74834 tries to explain these symmetric rules. match edge_idx { - 0..EDGE_IDX_LEFT_OF_CENTER => (KV_IDX_CENTER - 1, InsertionPlace::Left(edge_idx)), - EDGE_IDX_LEFT_OF_CENTER => (KV_IDX_CENTER, InsertionPlace::Left(edge_idx)), - EDGE_IDX_RIGHT_OF_CENTER => (KV_IDX_CENTER, InsertionPlace::Right(0)), - _ => (KV_IDX_CENTER + 1, InsertionPlace::Right(edge_idx - (KV_IDX_CENTER + 1 + 1))), + 0..EDGE_IDX_LEFT_OF_CENTER => (KV_IDX_CENTER - 1, LeftOrRight::Left(edge_idx)), + EDGE_IDX_LEFT_OF_CENTER => (KV_IDX_CENTER, LeftOrRight::Left(edge_idx)), + EDGE_IDX_RIGHT_OF_CENTER => (KV_IDX_CENTER, LeftOrRight::Right(0)), + _ => (KV_IDX_CENTER + 1, LeftOrRight::Right(edge_idx - (KV_IDX_CENTER + 1 + 1))), } } impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { - /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// Inserts a new key-value pair between the key-value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. /// /// The returned pointer points to the inserted value. fn insert_fit(&mut self, key: K, val: V) -> *mut V { debug_assert!(self.node.len() < CAPACITY); + let new_len = self.node.len() + 1; unsafe { - *self.node.reborrow_mut().into_len_mut() += 1; - slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key); - slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val); + slice_insert(self.node.key_area_mut_at(..new_len), self.idx, key); + slice_insert(self.node.val_area_mut_at(..new_len), self.idx, val); + *self.node.len_mut() = new_len as u16; - self.node.reborrow_mut().into_val_area_mut_at(self.idx).assume_init_mut() + self.node.val_area_mut_at(self.idx).assume_init_mut() } } } impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { - /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// Inserts a new key-value pair between the key-value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room. /// /// The returned pointer points to the inserted value. @@ -1014,24 +986,24 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark } else { let (middle_kv_idx, insertion) = splitpoint(self.idx); let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) }; - let (mut left, k, v, mut right) = middle.split(); + let mut result = middle.split(); let mut insertion_edge = match insertion { - InsertionPlace::Left(insert_idx) => unsafe { - Handle::new_edge(left.reborrow_mut(), insert_idx) + LeftOrRight::Left(insert_idx) => unsafe { + Handle::new_edge(result.left.reborrow_mut(), insert_idx) }, - InsertionPlace::Right(insert_idx) => unsafe { - Handle::new_edge(right.leaf_node_as_mut(), insert_idx) + LeftOrRight::Right(insert_idx) => unsafe { + Handle::new_edge(result.right.borrow_mut(), insert_idx) }, }; let val_ptr = insertion_edge.insert_fit(key, val); - (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), val_ptr) + (InsertResult::Split(result), val_ptr) } } } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::Edge> { - /// Fixes the parent pointer and index in the child node below this edge. This is useful - /// when the ordering of edges has been changed, such as in the various `insert` methods. + /// Fixes the parent pointer and index in the child node that this edge + /// links to. This is useful when the ordering of edges has been changed, fn correct_parent_link(self) { // Create backpointer without invalidating other references to the node. let ptr = unsafe { NonNull::new_unchecked(NodeRef::as_internal_ptr(&self.node)) }; @@ -1042,26 +1014,26 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::Edge> { - /// Inserts a new key/value pair and an edge that will go to the right of that new pair - /// between this edge and the key/value pair to the right of this edge. This method assumes + /// Inserts a new key-value pair and an edge that will go to the right of that new pair + /// between this edge and the key-value pair to the right of this edge. This method assumes /// that there is enough space in the node for the new pair to fit. fn insert_fit(&mut self, key: K, val: V, edge: Root) { debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); + let new_len = self.node.len() + 1; - let boxed_node = edge.into_boxed_node(); unsafe { - *self.node.reborrow_mut().into_len_mut() += 1; - slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key); - slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val); - slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, boxed_node); + slice_insert(self.node.key_area_mut_at(..new_len), self.idx, key); + slice_insert(self.node.val_area_mut_at(..new_len), self.idx, val); + slice_insert(self.node.edge_area_mut_at(..new_len + 1), self.idx + 1, edge.node); + *self.node.len_mut() = new_len as u16; - self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); + self.node.correct_childrens_parent_links(self.idx + 1..new_len + 1); } } - /// Inserts a new key/value pair and an edge that will go to the right of that new pair - /// between this edge and the key/value pair to the right of this edge. This method splits + /// Inserts a new key-value pair and an edge that will go to the right of that new pair + /// between this edge and the key-value pair to the right of this edge. This method splits /// the node if there isn't enough room. fn insert( mut self, @@ -1078,23 +1050,23 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, } else { let (middle_kv_idx, insertion) = splitpoint(self.idx); let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) }; - let (mut left, k, v, mut right) = middle.split(); + let mut result = middle.split(); let mut insertion_edge = match insertion { - InsertionPlace::Left(insert_idx) => unsafe { - Handle::new_edge(left.reborrow_mut(), insert_idx) + LeftOrRight::Left(insert_idx) => unsafe { + Handle::new_edge(result.left.reborrow_mut(), insert_idx) }, - InsertionPlace::Right(insert_idx) => unsafe { - Handle::new_edge(right.internal_node_as_mut(), insert_idx) + LeftOrRight::Right(insert_idx) => unsafe { + Handle::new_edge(result.right.borrow_mut(), insert_idx) }, }; insertion_edge.insert_fit(key, val, edge); - InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }) + InsertResult::Split(result) } } } impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { - /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// Inserts a new key-value pair between the key-value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room, and tries to /// insert the split off portion into the parent node recursively, until the root is reached. /// @@ -1110,16 +1082,16 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark (InsertResult::Fit(handle), ptr) => { return (InsertResult::Fit(handle.forget_node_type()), ptr); } - (InsertResult::Split(split), val_ptr) => (split, val_ptr), + (InsertResult::Split(split), val_ptr) => (split.forget_node_type(), val_ptr), }; loop { split = match split.left.ascend() { - Ok(parent) => match parent.insert(split.k, split.v, split.right) { + Ok(parent) => match parent.insert(split.kv.0, split.kv.1, split.right) { InsertResult::Fit(handle) => { return (InsertResult::Fit(handle.forget_node_type()), val_ptr); } - InsertResult::Split(split) => split, + InsertResult::Split(split) => split.forget_node_type(), }, Err(root) => { return (InsertResult::Split(SplitResult { left: root, ..split }), val_ptr); @@ -1132,6 +1104,8 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark impl Handle, marker::Edge> { /// Finds the node pointed to by this edge. /// + /// The method name assumes you picture trees with the root node on top. + /// /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. pub fn descend(self) -> NodeRef { @@ -1143,8 +1117,8 @@ impl Handle, marke // reference (Rust issue #73987) and invalidate any other references // to or inside the array, should any be around. let parent_ptr = NodeRef::as_internal_ptr(&self.node); - let boxed_node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() }; - NodeRef::from_boxed_node(boxed_node, self.node.height - 1) + let node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() }; + NodeRef { node, height: self.node.height - 1, _marker: PhantomData } } } @@ -1155,12 +1129,13 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeTyp } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn into_key_mut(self) -> &'a mut K { - unsafe { self.node.into_key_area_mut_at(self.idx).assume_init_mut() } + pub fn key_mut(&mut self) -> &mut K { + unsafe { self.node.key_area_mut_at(self.idx).assume_init_mut() } } pub fn into_val_mut(self) -> &'a mut V { - unsafe { self.node.into_val_area_mut_at(self.idx).assume_init_mut() } + let leaf = self.node.into_leaf_mut(); + unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() } } } @@ -1175,26 +1150,26 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> // We cannot call separate key and value methods, because calling the second one // invalidates the reference returned by the first. unsafe { - let leaf = NodeRef::as_leaf_mut(&mut self.node.reborrow_mut()); + let leaf = self.node.as_leaf_mut(); let key = leaf.keys.get_unchecked_mut(self.idx).assume_init_mut(); let val = leaf.vals.get_unchecked_mut(self.idx).assume_init_mut(); (key, val) } } -} -impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { - /// Helps implementations of `split` for a particular `NodeType`, - /// by calculating the length of the new node. - fn split_new_node_len(&self) -> usize { - debug_assert!(self.idx < self.node.len()); - self.node.len() - self.idx - 1 + /// Replace the key and value that the KV handle refers to. + pub fn replace_kv(&mut self, k: K, v: V) -> (K, V) { + let (key, val) = self.kv_mut(); + (mem::replace(key, k), mem::replace(val, v)) } +} +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { /// Helps implementations of `split` for a particular `NodeType`, /// by taking care of leaf data. fn split_leaf_data(&mut self, new_node: &mut LeafNode) -> (K, V) { - let new_len = self.split_new_node_len(); + debug_assert!(self.idx < self.node.len()); + let new_len = self.node.len() - self.idx - 1; new_node.len = new_len as u16; unsafe { let k = ptr::read(self.node.reborrow().key_at(self.idx)); @@ -1211,7 +1186,7 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> new_len, ); - *self.node.reborrow_mut().into_len_mut() = self.idx as u16; + *self.node.len_mut() = self.idx as u16; (k, v) } } @@ -1220,222 +1195,320 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType> impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::KV> { /// Splits the underlying node into three parts: /// - /// - The node is truncated to only contain the key/value pairs to the left of + /// - The node is truncated to only contain the key-value pairs to the left of /// this handle. /// - The key and value pointed to by this handle are extracted. - /// - All the key/value pairs to the right of this handle are put into a newly + /// - All the key-value pairs to the right of this handle are put into a newly /// allocated node. - pub fn split(mut self) -> (NodeRef, K, V, marker::Leaf>, K, V, Root) { + pub fn split(mut self) -> SplitResult<'a, K, V, marker::Leaf> { unsafe { let mut new_node = Box::new(LeafNode::new()); - let (k, v) = self.split_leaf_data(&mut new_node); + let kv = self.split_leaf_data(&mut new_node); - let right = Root { node: BoxedNode::from_leaf(new_node), height: 0 }; - (self.node, k, v, right) + let right = NodeRef::from_new_leaf(new_node); + SplitResult { left: self.node, kv, right } } } - /// Removes the key/value pair pointed to by this handle and returns it, along with the edge - /// that the key/value pair collapsed into. + /// Removes the key-value pair pointed to by this handle and returns it, along with the edge + /// that the key-value pair collapsed into. pub fn remove( mut self, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { + let old_len = self.node.len(); unsafe { - let k = slice_remove(self.node.reborrow_mut().into_key_area_slice(), self.idx); - let v = slice_remove(self.node.reborrow_mut().into_val_area_slice(), self.idx); - *self.node.reborrow_mut().into_len_mut() -= 1; + let k = slice_remove(self.node.key_area_mut_at(..old_len), self.idx); + let v = slice_remove(self.node.val_area_mut_at(..old_len), self.idx); + *self.node.len_mut() = (old_len - 1) as u16; ((k, v), self.left_edge()) } } } -impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { - /// Returns `true` if it is valid to call `.merge()`, i.e., whether there is enough room in - /// a node to hold the combination of the nodes to the left and right of this handle along - /// with the key/value pair at this handle. - pub fn can_merge(&self) -> bool { - (self.reborrow().left_edge().descend().len() - + self.reborrow().right_edge().descend().len() - + 1) - <= CAPACITY - } -} - impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::KV> { /// Splits the underlying node into three parts: /// - /// - The node is truncated to only contain the edges and key/value pairs to the + /// - The node is truncated to only contain the edges and key-value pairs to the /// left of this handle. /// - The key and value pointed to by this handle are extracted. - /// - All the edges and key/value pairs to the right of this handle are put into + /// - All the edges and key-value pairs to the right of this handle are put into /// a newly allocated node. - pub fn split(mut self) -> (NodeRef, K, V, marker::Internal>, K, V, Root) { + pub fn split(mut self) -> SplitResult<'a, K, V, marker::Internal> { unsafe { let mut new_node = Box::new(InternalNode::new()); - let new_len = self.split_new_node_len(); - // Move edges out before reducing length: + let kv = self.split_leaf_data(&mut new_node.data); + let new_len = usize::from(new_node.data.len); ptr::copy_nonoverlapping( self.node.reborrow().edge_area().as_ptr().add(self.idx + 1), new_node.edges.as_mut_ptr(), new_len + 1, ); - let (k, v) = self.split_leaf_data(&mut new_node.data); let height = self.node.height; - let mut right = Root { node: BoxedNode::from_internal(new_node), height }; + let mut right = NodeRef::from_new_internal(new_node, height); - right.internal_node_as_mut().correct_childrens_parent_links(0..=new_len); + right.borrow_mut().correct_childrens_parent_links(0..=new_len); - (self.node, k, v, right) + SplitResult { left: self.node, kv, right } } } +} - /// Combines the node immediately to the left of this handle, the key/value pair pointed - /// to by this handle, and the node immediately to the right of this handle into one new - /// child of the underlying node, returning an edge referencing that new child. - /// - /// Panics unless this edge `.can_merge()`. - pub fn merge( - mut self, - ) -> Handle, K, V, marker::Internal>, marker::Edge> { +/// Represents a session for evaluating and performing a balancing operation +/// around an internal key-value pair. +pub struct BalancingContext<'a, K, V> { + parent: Handle, K, V, marker::Internal>, marker::KV>, + left_child: NodeRef, K, V, marker::LeafOrInternal>, + right_child: NodeRef, K, V, marker::LeafOrInternal>, +} + +impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { + pub fn consider_for_balancing(self) -> BalancingContext<'a, K, V> { let self1 = unsafe { ptr::read(&self) }; let self2 = unsafe { ptr::read(&self) }; - let mut left_node = self1.left_edge().descend(); - let left_len = left_node.len(); - let right_node = self2.right_edge().descend(); + BalancingContext { + parent: self, + left_child: self1.left_edge().descend(), + right_child: self2.right_edge().descend(), + } + } +} + +impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { + /// Chooses a balancing context involving the node as a child, thus between + /// the KV immediately to the left or to the right in the parent node. + /// Returns an `Err` if there is no parent. + /// Panics if the parent is empty. + /// + /// Prefers the left side, to be optimal if the given node is somehow + /// underfull, meaning here only that it has fewer elements than its left + /// sibling and than its right sibling, if they exist. In that case, + /// merging with the left sibling is faster, since we only need to move + /// the node's N elements, instead of shifting them to the right and moving + /// more than N elements in front. Stealing from the left sibling is also + /// typically faster, since we only need to shift the node's N elements to + /// the right, instead of shifting at least N of the sibling's elements to + /// the left. + pub fn choose_parent_kv(self) -> Result>, Self> { + match unsafe { ptr::read(&self) }.ascend() { + Ok(parent_edge) => match parent_edge.left_kv() { + Ok(left_parent_kv) => Ok(LeftOrRight::Left(BalancingContext { + parent: unsafe { ptr::read(&left_parent_kv) }, + left_child: left_parent_kv.left_edge().descend(), + right_child: self, + })), + Err(parent_edge) => match parent_edge.right_kv() { + Ok(right_parent_kv) => Ok(LeftOrRight::Right(BalancingContext { + parent: unsafe { ptr::read(&right_parent_kv) }, + left_child: self, + right_child: right_parent_kv.right_edge().descend(), + })), + Err(_) => unreachable!("empty internal node"), + }, + }, + Err(root) => Err(root), + } + } +} + +impl<'a, K, V> BalancingContext<'a, K, V> { + pub fn left_child_len(&self) -> usize { + self.left_child.len() + } + + pub fn right_child_len(&self) -> usize { + self.right_child.len() + } + + pub fn into_left_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { + self.left_child + } + + pub fn into_right_child(self) -> NodeRef, K, V, marker::LeafOrInternal> { + self.right_child + } + + /// Returns `true` if it is valid to call `.merge()` in the balancing context, + /// i.e., whether there is enough room in a node to hold the combination of + /// both adjacent child nodes, along with the key-value pair in the parent. + pub fn can_merge(&self) -> bool { + self.left_child.len() + 1 + self.right_child.len() <= CAPACITY + } +} + +impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { + /// Merges the parent's key-value pair and both adjacent child nodes into + /// the left node and returns an edge handle in that expanded left node. + /// If `track_edge_idx` is given some value, the returned edge corresponds + /// to where the edge in that child node ended up, + /// + /// Panics unless we `.can_merge()`. + pub fn merge( + self, + track_edge_idx: Option>, + ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { + let Handle { node: mut parent_node, idx: parent_idx, _marker } = self.parent; + let old_parent_len = parent_node.len(); + let mut left_node = self.left_child; + let old_left_len = left_node.len(); + let right_node = self.right_child; let right_len = right_node.len(); + let new_left_len = old_left_len + 1 + right_len; - assert!(left_len + right_len < CAPACITY); + assert!(new_left_len <= CAPACITY); + assert!(match track_edge_idx { + None => true, + Some(LeftOrRight::Left(idx)) => idx <= old_left_len, + Some(LeftOrRight::Right(idx)) => idx <= right_len, + }); unsafe { - *left_node.reborrow_mut().into_len_mut() += right_len as u16 + 1; + *left_node.len_mut() = new_left_len as u16; - let parent_key = slice_remove(self.node.reborrow_mut().into_key_area_slice(), self.idx); - left_node.reborrow_mut().into_key_area_mut_at(left_len).write(parent_key); + let parent_key = + slice_remove(parent_node.key_area_mut_at(..old_parent_len), parent_idx); + left_node.key_area_mut_at(old_left_len).write(parent_key); ptr::copy_nonoverlapping( right_node.reborrow().key_area().as_ptr(), - left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(left_len + 1), + left_node.key_area_mut_at(old_left_len + 1..).as_mut_ptr(), right_len, ); - let parent_val = slice_remove(self.node.reborrow_mut().into_val_area_slice(), self.idx); - left_node.reborrow_mut().into_val_area_mut_at(left_len).write(parent_val); + let parent_val = + slice_remove(parent_node.val_area_mut_at(..old_parent_len), parent_idx); + left_node.val_area_mut_at(old_left_len).write(parent_val); ptr::copy_nonoverlapping( right_node.reborrow().val_area().as_ptr(), - left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(left_len + 1), + left_node.val_area_mut_at(old_left_len + 1..).as_mut_ptr(), right_len, ); - slice_remove(&mut self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1); - let self_len = self.node.len(); - self.node.correct_childrens_parent_links(self.idx + 1..self_len); - *self.node.reborrow_mut().into_len_mut() -= 1; + slice_remove(&mut parent_node.edge_area_mut_at(..old_parent_len + 1), parent_idx + 1); + parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len); + *parent_node.len_mut() -= 1; - if self.node.height > 1 { + if parent_node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. - let mut left_node = left_node.cast_to_internal_unchecked(); + let mut left_node = left_node.reborrow_mut().cast_to_internal_unchecked(); let right_node = right_node.cast_to_internal_unchecked(); ptr::copy_nonoverlapping( right_node.reborrow().edge_area().as_ptr(), - left_node.reborrow_mut().into_edge_area_slice().as_mut_ptr().add(left_len + 1), + left_node.edge_area_mut_at(old_left_len + 1..).as_mut_ptr(), right_len + 1, ); - left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); + left_node.correct_childrens_parent_links(old_left_len + 1..new_left_len + 1); - Global.dealloc(right_node.node.cast(), Layout::new::>()); + Global.deallocate(right_node.node.cast(), Layout::new::>()); } else { - Global.dealloc(right_node.node.cast(), Layout::new::>()); + Global.deallocate(right_node.node.cast(), Layout::new::>()); } - Handle::new_edge(self.node, self.idx) + let new_idx = match track_edge_idx { + None => 0, + Some(LeftOrRight::Left(idx)) => idx, + Some(LeftOrRight::Right(idx)) => old_left_len + 1 + idx, + }; + Handle::new_edge(left_node, new_idx) } } - /// This removes a key/value pair from the left child and places it in the key/value storage - /// pointed to by this handle while pushing the old key/value pair of this handle into the right - /// child. - pub fn steal_left(&mut self) { + /// Removes a key-value pair from the left child and places it in the key-value storage + /// of the parent, while pushing the old parent key-value pair into the right child. + /// Returns a handle to the edge in the right child corresponding to where the original + /// edge specified by `track_right_edge_idx` ended up. + pub fn steal_left( + mut self, + track_right_edge_idx: usize, + ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { unsafe { - let (k, v, edge) = self.reborrow_mut().left_edge().descend().pop(); + let (k, v, edge) = self.left_child.pop(); - let k = mem::replace(self.kv_mut().0, k); - let v = mem::replace(self.kv_mut().1, v); + let (k, v) = self.parent.replace_kv(k, v); - match self.reborrow_mut().right_edge().descend().force() { + match self.right_child.reborrow_mut().force() { ForceResult::Leaf(mut leaf) => leaf.push_front(k, v), ForceResult::Internal(mut internal) => internal.push_front(k, v, edge.unwrap()), } + + Handle::new_edge(self.right_child, 1 + track_right_edge_idx) } } - /// This removes a key/value pair from the right child and places it in the key/value storage - /// pointed to by this handle while pushing the old key/value pair of this handle into the left - /// child. - pub fn steal_right(&mut self) { + /// Removes a key-value pair from the right child and places it in the key-value storage + /// of the parent, while pushing the old parent key-value pair onto the left child. + /// Returns a handle to the edge in the left child specified by `track_left_edge_idx`, + /// which didn't move. + pub fn steal_right( + mut self, + track_left_edge_idx: usize, + ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { unsafe { - let (k, v, edge) = self.reborrow_mut().right_edge().descend().pop_front(); + let (k, v, edge) = self.right_child.pop_front(); - let k = mem::replace(self.kv_mut().0, k); - let v = mem::replace(self.kv_mut().1, v); + let (k, v) = self.parent.replace_kv(k, v); - match self.reborrow_mut().left_edge().descend().force() { + match self.left_child.reborrow_mut().force() { ForceResult::Leaf(mut leaf) => leaf.push(k, v), ForceResult::Internal(mut internal) => internal.push(k, v, edge.unwrap()), } + + Handle::new_edge(self.left_child, track_left_edge_idx) } } /// This does stealing similar to `steal_left` but steals multiple elements at once. pub fn bulk_steal_left(&mut self, count: usize) { + assert!(count > 0); unsafe { - let mut left_node = ptr::read(self).left_edge().descend(); - let left_len = left_node.len(); - let mut right_node = ptr::read(self).right_edge().descend(); - let right_len = right_node.len(); + let left_node = &mut self.left_child; + let old_left_len = left_node.len(); + let right_node = &mut self.right_child; + let old_right_len = right_node.len(); // Make sure that we may steal safely. - assert!(right_len + count <= CAPACITY); - assert!(left_len >= count); + assert!(old_right_len + count <= CAPACITY); + assert!(old_left_len >= count); - let new_left_len = left_len - count; + let new_left_len = old_left_len - count; + let new_right_len = old_right_len + count; + *left_node.len_mut() = new_left_len as u16; + *right_node.len_mut() = new_right_len as u16; - // Move data. + // Move leaf data. { let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); let parent_kv = { - let kv = self.kv_mut(); + let kv = self.parent.kv_mut(); (kv.0 as *mut K, kv.1 as *mut V) }; // Make room for stolen elements in the right child. - ptr::copy(right_kv.0, right_kv.0.add(count), right_len); - ptr::copy(right_kv.1, right_kv.1.add(count), right_len); + ptr::copy(right_kv.0, right_kv.0.add(count), old_right_len); + ptr::copy(right_kv.1, right_kv.1.add(count), old_right_len); // Move elements from the left child to the right one. move_kv(left_kv, new_left_len + 1, right_kv, 0, count - 1); - // Move parent's key/value pair to the right child. + // Move parent's key-value pair to the right child. move_kv(parent_kv, 0, right_kv, count - 1, 1); // Move the left-most stolen pair to the parent. move_kv(left_kv, new_left_len, parent_kv, 0, 1); } - *left_node.reborrow_mut().into_len_mut() -= count as u16; - *right_node.reborrow_mut().into_len_mut() += count as u16; - - match (left_node.force(), right_node.force()) { + match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { // Make room for stolen edges. let left = left.reborrow(); - let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr(); - ptr::copy(right_edges, right_edges.add(count), right_len + 1); - right.correct_childrens_parent_links(count..count + right_len + 1); + let right_edges = right.edge_area_mut_at(..).as_mut_ptr(); + ptr::copy(right_edges, right_edges.add(count), old_right_len + 1); + right.correct_childrens_parent_links(count..new_right_len + 1); + // Steal edges. move_edges(left, new_left_len + 1, right, 0, count); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} @@ -1446,50 +1519,52 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// The symmetric clone of `bulk_steal_left`. pub fn bulk_steal_right(&mut self, count: usize) { + assert!(count > 0); unsafe { - let mut left_node = ptr::read(self).left_edge().descend(); - let left_len = left_node.len(); - let mut right_node = ptr::read(self).right_edge().descend(); - let right_len = right_node.len(); + let left_node = &mut self.left_child; + let old_left_len = left_node.len(); + let right_node = &mut self.right_child; + let old_right_len = right_node.len(); // Make sure that we may steal safely. - assert!(left_len + count <= CAPACITY); - assert!(right_len >= count); + assert!(old_left_len + count <= CAPACITY); + assert!(old_right_len >= count); - let new_right_len = right_len - count; + let new_left_len = old_left_len + count; + let new_right_len = old_right_len - count; + *left_node.len_mut() = new_left_len as u16; + *right_node.len_mut() = new_right_len as u16; - // Move data. + // Move leaf data. { let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); let parent_kv = { - let kv = self.kv_mut(); + let kv = self.parent.kv_mut(); (kv.0 as *mut K, kv.1 as *mut V) }; - // Move parent's key/value pair to the left child. - move_kv(parent_kv, 0, left_kv, left_len, 1); + // Move parent's key-value pair to the left child. + move_kv(parent_kv, 0, left_kv, old_left_len, 1); // Move elements from the right child to the left one. - move_kv(right_kv, 0, left_kv, left_len + 1, count - 1); + move_kv(right_kv, 0, left_kv, old_left_len + 1, count - 1); // Move the right-most stolen pair to the parent. move_kv(right_kv, count - 1, parent_kv, 0, 1); - // Fix right indexing + // Fill gap where stolen elements used to be. ptr::copy(right_kv.0.add(count), right_kv.0, new_right_len); ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len); } - *left_node.reborrow_mut().into_len_mut() += count as u16; - *right_node.reborrow_mut().into_len_mut() -= count as u16; - - match (left_node.force(), right_node.force()) { + match (left_node.reborrow_mut().force(), right_node.reborrow_mut().force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { - move_edges(right.reborrow(), 0, left, left_len + 1, count); + // Steal edges. + move_edges(right.reborrow(), 0, left, old_left_len + 1, count); - // Fix right indexing. - let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr(); + // Fill gap where stolen edges used to be. + let right_edges = right.edge_area_mut_at(..).as_mut_ptr(); ptr::copy(right_edges.add(count), right_edges, new_right_len + 1); right.correct_childrens_parent_links(0..=new_right_len); } @@ -1523,8 +1598,8 @@ unsafe fn move_edges<'a, K: 'a, V: 'a>( ) { unsafe { let source_ptr = source.edge_area().as_ptr(); - let dest_ptr = dest.reborrow_mut().into_edge_area_slice().as_mut_ptr(); - ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); + let dest_ptr = dest.edge_area_mut_at(dest_offset..).as_mut_ptr(); + ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr, count); dest.correct_childrens_parent_links(dest_offset..dest_offset + count); } } @@ -1604,28 +1679,28 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma right: &mut NodeRef, K, V, marker::LeafOrInternal>, ) { unsafe { - let left_new_len = self.idx; + let new_left_len = self.idx; let mut left_node = self.reborrow_mut().into_node(); - let right_new_len = left_node.len() - left_new_len; + let new_right_len = left_node.len() - new_left_len; let mut right_node = right.reborrow_mut(); assert!(right_node.len() == 0); assert!(left_node.height == right_node.height); - if right_new_len > 0 { + if new_right_len > 0 { let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); - move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); + move_kv(left_kv, new_left_len, right_kv, 0, new_right_len); - *left_node.reborrow_mut().into_len_mut() = left_new_len as u16; - *right_node.reborrow_mut().into_len_mut() = right_new_len as u16; + *left_node.len_mut() = new_left_len as u16; + *right_node.len_mut() = new_right_len as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(right)) => { let left = left.reborrow(); - move_edges(left, left_new_len + 1, right, 1, right_new_len); + move_edges(left, new_left_len + 1, right, 1, new_right_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} _ => unreachable!(), @@ -1641,20 +1716,30 @@ pub enum ForceResult { } /// Result of insertion, when a node needed to expand beyond its capacity. -/// Does not distinguish between `Leaf` and `Internal` because `Root` doesn't. -pub struct SplitResult<'a, K, V> { - // Altered node in existing tree with elements and edges that belong to the left of `k`. - pub left: NodeRef, K, V, marker::LeafOrInternal>, +pub struct SplitResult<'a, K, V, NodeType> { + // Altered node in existing tree with elements and edges that belong to the left of `kv`. + pub left: NodeRef, K, V, NodeType>, // Some key and value split off, to be inserted elsewhere. - pub k: K, - pub v: V, - // Owned, unattached, new node with elements and edges that belong to the right of `k`. - pub right: Root, + pub kv: (K, V), + // Owned, unattached, new node with elements and edges that belong to the right of `kv`. + pub right: NodeRef, +} + +impl<'a, K, V> SplitResult<'a, K, V, marker::Leaf> { + pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { + SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() } + } +} + +impl<'a, K, V> SplitResult<'a, K, V, marker::Internal> { + pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> { + SplitResult { left: self.left.forget_type(), kv: self.kv, right: self.right.forget_type() } + } } -pub enum InsertResult<'a, K, V, Type> { - Fit(Handle, K, V, Type>, marker::KV>), - Split(SplitResult<'a, K, V>), +pub enum InsertResult<'a, K, V, NodeType> { + Fit(Handle, K, V, NodeType>, marker::KV>), + Split(SplitResult<'a, K, V, NodeType>), } pub mod marker { diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index 38c75de34e..7fe8ff743c 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -5,7 +5,7 @@ use crate::string::String; use core::cmp::Ordering::*; impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { - /// Asserts that the back pointer in each reachable node points to its parent. + // Asserts that the back pointer in each reachable node points to its parent. pub fn assert_back_pointers(self) { if let ForceResult::Internal(node) = self.force() { for idx in 0..=node.len() { @@ -17,6 +17,9 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> } } + // Renders a multi-line display of the keys in order and in tree hierarchy, + // picturing the tree growing sideways from its root on the left to its + // leaves on the right. pub fn dump_keys(self) -> String where K: Debug, @@ -27,11 +30,15 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> let depth = self.height(); let indent = " ".repeat(depth); result += &format!("\n{}", indent); - for idx in 0..leaf.len() { - if idx > 0 { - result += ", "; + if leaf.len() == 0 { + result += "(empty node)"; + } else { + for idx in 0..leaf.len() { + if idx > 0 { + result += ", "; + } + result += &format!("{:?}", unsafe { leaf.key_at(idx) }); } - result += &format!("{:?}", unsafe { leaf.key_at(idx) }); } } navigate::Position::Internal(_) => {} @@ -54,11 +61,11 @@ fn test_splitpoint() { let mut left_len = middle_kv_idx; let mut right_len = CAPACITY - middle_kv_idx - 1; match insertion { - InsertionPlace::Left(edge_idx) => { + LeftOrRight::Left(edge_idx) => { assert!(edge_idx <= left_len); left_len += 1; } - InsertionPlace::Right(edge_idx) => { + LeftOrRight::Right(edge_idx) => { assert!(edge_idx <= right_len); right_len += 1; } @@ -71,16 +78,19 @@ fn test_splitpoint() { #[test] fn test_partial_cmp_eq() { - let mut root1: Root = Root::new_leaf(); - let mut leaf1 = unsafe { root1.leaf_node_as_mut() }; + let mut root1 = NodeRef::new_leaf(); + let mut leaf1 = root1.borrow_mut(); leaf1.push(1, ()); + let mut root1 = root1.forget_type(); root1.push_internal_level(); - let root2: Root = Root::new_leaf(); + let root2 = Root::new(); + root1.reborrow().assert_back_pointers(); + root2.reborrow().assert_back_pointers(); - let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type(); - let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type(); - let top_edge_1 = root1.node_as_ref().first_edge(); - let top_edge_2 = root2.node_as_ref().first_edge(); + let leaf_edge_1a = root1.reborrow().first_leaf_edge().forget_node_type(); + let leaf_edge_1b = root1.reborrow().last_leaf_edge().forget_node_type(); + let top_edge_1 = root1.reborrow().first_edge(); + let top_edge_2 = root2.reborrow().first_edge(); assert!(leaf_edge_1a == leaf_edge_1a); assert!(leaf_edge_1a != leaf_edge_1b); @@ -97,8 +107,8 @@ fn test_partial_cmp_eq() { assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None); root1.pop_internal_level(); - unsafe { root1.into_ref().deallocate_and_ascend() }; - unsafe { root2.into_ref().deallocate_and_ascend() }; + unsafe { root1.deallocate_and_ascend() }; + unsafe { root2.deallocate_and_ascend() }; } #[test] diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index 99655d3e2b..7aeb39cbc3 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -1,133 +1,151 @@ use super::map::MIN_LEN; -use super::node::{marker, ForceResult, Handle, NodeRef}; +use super::node::{marker, ForceResult::*, Handle, LeftOrRight::*, NodeRef}; use super::unwrap_unchecked; -use core::mem; -use core::ptr; impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { - /// Removes a key/value-pair from the map, and returns that pair, as well as - /// the leaf edge corresponding to that former pair. + /// Removes a key-value pair from the tree, and returns that pair, as well as + /// the leaf edge corresponding to that former pair. It's possible this empties + /// a root node that is internal, which the caller should pop from the map + /// holding the tree. The caller should also decrement the map's length. pub fn remove_kv_tracking( self, handle_emptied_internal_root: F, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { - let (old_kv, mut pos, was_internal) = match self.force() { - ForceResult::Leaf(leaf) => { - let (old_kv, pos) = leaf.remove(); - (old_kv, pos, false) - } - ForceResult::Internal(mut internal) => { - // Replace the location freed in the internal node with an - // adjacent KV, and remove that adjacent KV from its leaf. - // Always choose the adjacent KV on the left side because - // it is typically faster to pop an element from the end - // of the KV arrays without needing to shift other elements. - - let key_loc = internal.kv_mut().0 as *mut K; - let val_loc = internal.kv_mut().1 as *mut V; - - let to_remove = internal.left_edge().descend().last_leaf_edge().left_kv().ok(); - let to_remove = unsafe { unwrap_unchecked(to_remove) }; - - let (kv, pos) = to_remove.remove(); - - let old_key = unsafe { mem::replace(&mut *key_loc, kv.0) }; - let old_val = unsafe { mem::replace(&mut *val_loc, kv.1) }; - - ((old_key, old_val), pos, true) - } - }; - - // Handle underflow - let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() }; - let mut at_leaf = true; - while cur_node.len() < MIN_LEN { - match handle_underfull_node(cur_node) { - UnderflowResult::AtRoot => break, - UnderflowResult::Merged(edge, merged_with_left, offset) => { - // If we merged with our right sibling then our tracked - // position has not changed. However if we merged with our - // left sibling then our tracked position is now dangling. - if at_leaf && merged_with_left { - let idx = pos.idx() + offset; - let node = match unsafe { ptr::read(&edge).descend().force() } { - ForceResult::Leaf(leaf) => leaf, - ForceResult::Internal(_) => unreachable!(), - }; - pos = unsafe { Handle::new_edge(node, idx) }; - } + match self.force() { + Leaf(node) => node.remove_leaf_kv(handle_emptied_internal_root), + Internal(node) => node.remove_internal_kv(handle_emptied_internal_root), + } + } +} - let parent = edge.into_node(); - if parent.len() == 0 { - // The parent that was just emptied must be the root, - // because nodes on a lower level would not have been - // left with a single child. - handle_emptied_internal_root(); - break; +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::KV> { + fn remove_leaf_kv( + self, + handle_emptied_internal_root: F, + ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { + let (old_kv, mut pos) = self.remove(); + let len = pos.reborrow().into_node().len(); + if len < MIN_LEN { + let idx = pos.idx(); + // We have to temporarily forget the child type, because there is no + // distinct node type for the immediate parents of a leaf. + let new_pos = match pos.into_node().forget_type().choose_parent_kv() { + Ok(Left(left_parent_kv)) => { + debug_assert!(left_parent_kv.right_child_len() == MIN_LEN - 1); + if left_parent_kv.can_merge() { + left_parent_kv.merge(Some(Right(idx))) } else { - cur_node = parent.forget_type(); - at_leaf = false; + debug_assert!(left_parent_kv.left_child_len() > MIN_LEN); + left_parent_kv.steal_left(idx) } } - UnderflowResult::Stole(stole_from_left) => { - // Adjust the tracked position if we stole from a left sibling - if stole_from_left && at_leaf { - // SAFETY: This is safe since we just added an element to our node. - unsafe { - pos.move_next_unchecked(); - } + Ok(Right(right_parent_kv)) => { + debug_assert!(right_parent_kv.left_child_len() == MIN_LEN - 1); + if right_parent_kv.can_merge() { + right_parent_kv.merge(Some(Left(idx))) + } else { + debug_assert!(right_parent_kv.right_child_len() > MIN_LEN); + right_parent_kv.steal_right(idx) } - break; } - } - } + Err(pos) => unsafe { Handle::new_edge(pos, idx) }, + }; + // SAFETY: `new_pos` is the leaf we started from or a sibling. + pos = unsafe { new_pos.cast_to_leaf_unchecked() }; - // If we deleted from an internal node then we need to compensate for - // the earlier swap and adjust the tracked position to point to the - // next element. - if was_internal { - pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() }; + // Only if we merged, the parent (if any) has shrunk, but skipping + // the following step otherwise does not pay off in benchmarks. + // + // SAFETY: We won't destroy or rearrange the leaf where `pos` is at + // by handling its parent recursively; at worst we will destroy or + // rearrange the parent through the grandparent, thus change the + // link to the parent inside the leaf. + if let Ok(parent) = unsafe { pos.reborrow_mut() }.into_node().ascend() { + parent.into_node().handle_shrunk_node_recursively(handle_emptied_internal_root); + } } - (old_kv, pos) } } -enum UnderflowResult<'a, K, V> { - AtRoot, - Merged(Handle, K, V, marker::Internal>, marker::Edge>, bool, usize), - Stole(bool), -} +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::KV> { + fn remove_internal_kv( + self, + handle_emptied_internal_root: F, + ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { + // Remove an adjacent KV from its leaf and then put it back in place of + // the element we were asked to remove. Prefer the left adjacent KV, + // for the reasons listed in `choose_parent_kv`. + let left_leaf_kv = self.left_edge().descend().last_leaf_edge().left_kv(); + let left_leaf_kv = unsafe { unwrap_unchecked(left_leaf_kv.ok()) }; + let (left_kv, left_hole) = left_leaf_kv.remove_leaf_kv(handle_emptied_internal_root); -fn handle_underfull_node<'a, K: 'a, V: 'a>( - node: NodeRef, K, V, marker::LeafOrInternal>, -) -> UnderflowResult<'_, K, V> { - let parent = match node.ascend() { - Ok(parent) => parent, - Err(_) => return UnderflowResult::AtRoot, - }; + // The internal node may have been stolen from or merged. Go back right + // to find where the original KV ended up. + let mut internal = unsafe { unwrap_unchecked(left_hole.next_kv().ok()) }; + let old_kv = internal.replace_kv(left_kv.0, left_kv.1); + let pos = internal.next_leaf_edge(); + (old_kv, pos) + } +} - // Prefer the left KV if it exists. Merging with the left side is faster, - // since merging happens towards the left and `node` has fewer elements. - // Stealing from the left side is faster, since we can pop from the end of - // the KV arrays. - let (is_left, mut handle) = match parent.left_kv() { - Ok(left) => (true, left), - Err(parent) => { - let right = unsafe { unwrap_unchecked(parent.right_kv().ok()) }; - (false, right) +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { + /// Stocks up a possibly underfull internal node and its ancestors, + /// until it reaches an ancestor that has elements to spare or is the root. + fn handle_shrunk_node_recursively(mut self, handle_emptied_internal_root: F) { + loop { + self = match self.len() { + 0 => { + // An empty node must be the root, because length is only + // reduced by one, and non-root underfull nodes are stocked up, + // so non-root nodes never have fewer than MIN_LEN - 1 elements. + debug_assert!(self.ascend().is_err()); + handle_emptied_internal_root(); + return; + } + 1..MIN_LEN => { + if let Some(parent) = self.handle_underfull_node_locally() { + parent + } else { + return; + } + } + _ => return, + } } - }; + } - if handle.can_merge() { - let offset = if is_left { handle.reborrow().left_edge().descend().len() + 1 } else { 0 }; - UnderflowResult::Merged(handle.merge(), is_left, offset) - } else { - if is_left { - handle.steal_left(); - } else { - handle.steal_right(); + /// Stocks up an underfull internal node, possibly at the cost of shrinking + /// its parent instead, which is then returned. + fn handle_underfull_node_locally( + self, + ) -> Option, K, V, marker::Internal>> { + match self.forget_type().choose_parent_kv() { + Ok(Left(left_parent_kv)) => { + debug_assert_eq!(left_parent_kv.right_child_len(), MIN_LEN - 1); + if left_parent_kv.can_merge() { + let pos = left_parent_kv.merge(None); + let parent_edge = unsafe { unwrap_unchecked(pos.into_node().ascend().ok()) }; + Some(parent_edge.into_node()) + } else { + debug_assert!(left_parent_kv.left_child_len() > MIN_LEN); + left_parent_kv.steal_left(0); + None + } + } + Ok(Right(right_parent_kv)) => { + debug_assert_eq!(right_parent_kv.left_child_len(), MIN_LEN - 1); + if right_parent_kv.can_merge() { + let pos = right_parent_kv.merge(None); + let parent_edge = unsafe { unwrap_unchecked(pos.into_node().ascend().ok()) }; + Some(parent_edge.into_node()) + } else { + debug_assert!(right_parent_kv.right_child_len() > MIN_LEN); + right_parent_kv.steal_right(0); + None + } + } + Err(_) => None, } - UnderflowResult::Stole(is_left) } } diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 701d5ec73e..ed7f95fe63 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -14,6 +14,9 @@ pub enum SearchResult { /// Returns a `Found` with the handle of the matching KV, if any. Otherwise, /// returns a `GoDown` with the handle of the possible leaf edge where the key /// belongs. +/// +/// The result is meaningful only if the tree is ordered by key, like the tree +/// in a `BTreeMap` is. pub fn search_tree( mut node: NodeRef, key: &Q, @@ -38,8 +41,11 @@ where /// Looks up a given key in a given node, without recursion. /// Returns a `Found` with the handle of the matching KV, if any. Otherwise, -/// returns a `GoDown` with the handle of the edge where the key might be found. -/// If the node is a leaf, a `GoDown` edge is not an actual edge but a possible edge. +/// returns a `GoDown` with the handle of the edge where the key might be found +/// (if the node is internal) or where the key can be inserted. +/// +/// The result is meaningful only if the tree is ordered by key, like the tree +/// in a `BTreeMap` is. pub fn search_node( node: NodeRef, key: &Q, @@ -50,15 +56,15 @@ where { match search_linear(&node, key) { (idx, true) => Found(unsafe { Handle::new_kv(node, idx) }), - (idx, false) => SearchResult::GoDown(unsafe { Handle::new_edge(node, idx) }), + (idx, false) => GoDown(unsafe { Handle::new_edge(node, idx) }), } } -/// Returns the index in the node at which the key (or an equivalent) exists -/// or could exist, and whether it exists in the node itself. If it doesn't -/// exist in the node itself, it may exist in the subtree with that index -/// (if the node has subtrees). If the key doesn't exist in node or subtree, -/// the returned index is the position or subtree where the key belongs. +/// Returns either the KV index in the node at which the key (or an equivalent) +/// exists and `true`, or the edge index where the key belongs and `false`. +/// +/// The result is meaningful only if the tree is ordered by key, like the tree +/// in a `BTreeMap` is. fn search_linear( node: &NodeRef, key: &Q, diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 684019f8f5..f63c3dd580 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -214,13 +214,15 @@ impl fmt::Debug for Union<'_, T> { // This constant is used by functions that compare two sets. // It estimates the relative size at which searching performs better // than iterating, based on the benchmarks in -// https://github.com/ssomers/rust_bench_btreeset_intersection; +// https://github.com/ssomers/rust_bench_btreeset_intersection. // It's used to divide rather than multiply sizes, to rule out overflow, // and it's a power of two to make that division cheap. const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16; impl BTreeSet { - /// Makes a new `BTreeSet` with a reasonable choice of B. + /// Makes a new, empty `BTreeSet`. + /// + /// Does not allocate anything on its own. /// /// # Examples /// @@ -677,7 +679,7 @@ impl BTreeSet { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn pop_first(&mut self) -> Option { - self.map.first_entry().map(|entry| entry.remove_entry().0) + self.map.pop_first().map(|kv| kv.0) } /// Removes the last value from the set and returns it, if any. @@ -699,7 +701,7 @@ impl BTreeSet { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn pop_last(&mut self) -> Option { - self.map.last_entry().map(|entry| entry.remove_entry().0) + self.map.pop_last().map(|kv| kv.0) } /// Adds a value to the set. @@ -798,6 +800,30 @@ impl BTreeSet { Recover::take(&mut self.map, value) } + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_retain)] + /// use std::collections::BTreeSet; + /// + /// let xs = [1, 2, 3, 4, 5, 6]; + /// let mut set: BTreeSet = xs.iter().cloned().collect(); + /// // Keep only the even numbers. + /// set.retain(|&k| k % 2 == 0); + /// assert!(set.iter().eq([2, 4, 6].iter())); + /// ``` + #[unstable(feature = "btree_retain", issue = "79025")] + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.drain_filter(|v| !f(v)); + } + /// Moves all elements from `other` into `Self`, leaving `other` empty. /// /// # Examples @@ -1097,7 +1123,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { - /// Makes an empty `BTreeSet` with a reasonable choice of B. + /// Creates an empty `BTreeSet`. fn default() -> BTreeSet { BTreeSet::new() } diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 52cde8299e..4d05bc4ebf 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -1,9 +1,10 @@ use super::super::DeterministicRng; use super::*; use crate::vec::Vec; +use std::cmp::Ordering; use std::iter::FromIterator; use std::panic::{catch_unwind, AssertUnwindSafe}; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering::SeqCst}; #[test] fn test_clone_eq() { @@ -324,6 +325,17 @@ fn test_is_subset() { assert_eq!(is_subset(&[99, 100], &large), false); } +#[test] +fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: BTreeSet = xs.iter().cloned().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); +} + #[test] fn test_drain_filter() { let mut x: BTreeSet<_> = [1].iter().copied().collect(); @@ -344,7 +356,7 @@ fn test_drain_filter_drop_panic_leak() { struct D(i32); impl Drop for D { fn drop(&mut self) { - if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + if DROPS.fetch_add(1, SeqCst) == 1 { panic!("panic in `drop`"); } } @@ -357,14 +369,14 @@ fn test_drain_filter_drop_panic_leak() { catch_unwind(move || { drop(set.drain_filter(|d| { - PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst); + PREDS.fetch_add(1u32 << d.0, SeqCst); true })) }) .ok(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 3); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 3); } #[test] @@ -376,7 +388,7 @@ fn test_drain_filter_pred_panic_leak() { struct D(i32); impl Drop for D { fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); + DROPS.fetch_add(1, SeqCst); } } @@ -387,7 +399,7 @@ fn test_drain_filter_pred_panic_leak() { catch_unwind(AssertUnwindSafe(|| { drop(set.drain_filter(|d| { - PREDS.fetch_add(1u32 << d.0, Ordering::SeqCst); + PREDS.fetch_add(1u32 << d.0, SeqCst); match d.0 { 0 => true, _ => panic!(), @@ -396,8 +408,8 @@ fn test_drain_filter_pred_panic_leak() { })) .ok(); - assert_eq!(PREDS.load(Ordering::SeqCst), 0x011); - assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(PREDS.load(SeqCst), 0x011); + assert_eq!(DROPS.load(SeqCst), 1); assert_eq!(set.len(), 2); assert_eq!(set.first().unwrap().0, 4); assert_eq!(set.last().unwrap().0, 8); @@ -487,8 +499,6 @@ fn test_extend_ref() { #[test] fn test_recovery() { - use std::cmp::Ordering; - #[derive(Debug)] struct Foo(&'static str, i32); diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index 5f00a5a25a..6108c139bb 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -9,7 +9,7 @@ impl Root { K: Borrow, { debug_assert!(right_root.height() == 0); - debug_assert!(right_root.node_as_ref().len() == 0); + debug_assert!(right_root.len() == 0); let left_root = self; for _ in 0..left_root.height() { @@ -17,14 +17,14 @@ impl Root { } { - let mut left_node = left_root.node_as_mut(); - let mut right_node = right_root.node_as_mut(); + let mut left_node = left_root.borrow_mut(); + let mut right_node = right_root.borrow_mut(); loop { let mut split_edge = match search_node(left_node, key) { // key is going to the right tree - Found(handle) => handle.left_edge(), - GoDown(handle) => handle, + Found(kv) => kv.left_edge(), + GoDown(edge) => edge, }; split_edge.move_suffix(&mut right_node); @@ -48,7 +48,7 @@ impl Root { /// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty. fn fix_top(&mut self) { - while self.height() > 0 && self.node_as_ref().len() == 0 { + while self.height() > 0 && self.len() == 0 { self.pop_internal_level(); } } @@ -57,20 +57,20 @@ impl Root { self.fix_top(); { - let mut cur_node = self.node_as_mut(); + let mut cur_node = self.borrow_mut(); while let Internal(node) = cur_node.force() { - let mut last_kv = node.last_kv(); + let mut last_kv = node.last_kv().consider_for_balancing(); if last_kv.can_merge() { - cur_node = last_kv.merge().descend(); + cur_node = last_kv.merge(None).into_node(); } else { - let right_len = last_kv.reborrow().right_edge().descend().len(); + let right_len = last_kv.right_child_len(); // `MIN_LEN + 1` to avoid readjust if merge happens on the next level. if right_len < MIN_LEN + 1 { last_kv.bulk_steal_left(MIN_LEN + 1 - right_len); } - cur_node = last_kv.right_edge().descend(); + cur_node = last_kv.into_right_child(); } } } @@ -83,20 +83,20 @@ impl Root { self.fix_top(); { - let mut cur_node = self.node_as_mut(); + let mut cur_node = self.borrow_mut(); while let Internal(node) = cur_node.force() { - let mut first_kv = node.first_kv(); + let mut first_kv = node.first_kv().consider_for_balancing(); if first_kv.can_merge() { - cur_node = first_kv.merge().descend(); + cur_node = first_kv.merge(None).into_node(); } else { - let left_len = first_kv.reborrow().left_edge().descend().len(); + let left_len = first_kv.left_child_len(); // `MIN_LEN + 1` to avoid readjust if merge happens on the next level. if left_len < MIN_LEN + 1 { first_kv.bulk_steal_right(MIN_LEN + 1 - left_len); } - cur_node = first_kv.left_edge().descend(); + cur_node = first_kv.into_left_child(); } } } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 412c65681e..4707f12940 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1099,68 +1099,6 @@ impl ExactSizeIterator for IterMut<'_, T> {} #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IterMut<'_, T> {} -impl IterMut<'_, T> { - /// Inserts the given element just after the element most recently returned by `.next()`. - /// The inserted element does not appear in the iteration. - /// - /// This method will be removed soon. - #[inline] - #[unstable( - feature = "linked_list_extras", - reason = "this is probably better handled by a cursor type -- we'll see", - issue = "27794" - )] - #[rustc_deprecated( - reason = "Deprecated in favor of CursorMut methods. This method will be removed soon.", - since = "1.47.0" - )] - pub fn insert_next(&mut self, element: T) { - match self.head { - // `push_back` is okay with aliasing `element` references - None => self.list.push_back(element), - Some(head) => unsafe { - let prev = match head.as_ref().prev { - // `push_front` is okay with aliasing nodes - None => return self.list.push_front(element), - Some(prev) => prev, - }; - - let node = Some( - Box::leak(box Node { next: Some(head), prev: Some(prev), element }).into(), - ); - - // Not creating references to entire nodes to not invalidate the - // reference to `element` we handed to the user. - (*prev.as_ptr()).next = node; - (*head.as_ptr()).prev = node; - - self.list.len += 1; - }, - } - } - - /// Provides a reference to the next element, without changing the iterator. - /// - /// This method will be removed soon. - #[inline] - #[unstable( - feature = "linked_list_extras", - reason = "this is probably better handled by a cursor type -- we'll see", - issue = "27794" - )] - #[rustc_deprecated( - reason = "Deprecated in favor of CursorMut methods. This method will be removed soon.", - since = "1.47.0" - )] - pub fn peek_next(&mut self) -> Option<&mut T> { - if self.len == 0 { - None - } else { - unsafe { self.head.as_mut().map(|node| &mut node.as_mut().element) } - } - } -} - /// A cursor over a `LinkedList`. /// /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 6b21e54f66..8213e904fb 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -41,7 +41,7 @@ pub use linked_list::LinkedList; #[doc(no_inline)] pub use vec_deque::VecDeque; -use crate::alloc::{Layout, LayoutErr}; +use crate::alloc::{Layout, LayoutError}; use core::fmt::Display; /// The error type for `try_reserve` methods. @@ -71,9 +71,9 @@ pub enum TryReserveError { } #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] -impl From for TryReserveError { +impl From for TryReserveError { #[inline] - fn from(_: LayoutErr) -> Self { + fn from(_: LayoutError) -> Self { TryReserveError::CapacityOverflow } } diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs new file mode 100644 index 0000000000..465b058cd9 --- /dev/null +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -0,0 +1,57 @@ +use core::fmt; +use core::iter::FusedIterator; + +use super::VecDeque; + +/// An owning iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`into_iter`] method on [`VecDeque`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: VecDeque::into_iter +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter { + pub(crate) inner: VecDeque, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IntoIter").field(&self.inner).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.inner.pop_front() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.inner.len(); + (len, Some(len)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.inner.pop_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs new file mode 100644 index 0000000000..ad31b991cb --- /dev/null +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -0,0 +1,159 @@ +use core::fmt; +use core::iter::FusedIterator; +use core::ops::Try; + +use super::{count, wrap_index, RingSlices}; + +/// An iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter`] method on [`super::VecDeque`]. See its +/// documentation for more. +/// +/// [`iter`]: super::VecDeque::iter +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + pub(crate) ring: &'a [T], + pub(crate) tail: usize, + pub(crate) head: usize, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + f.debug_tuple("Iter").field(&front).field(&back).finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { ring: self.ring, tail: self.tail, head: self.head } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + if self.tail == self.head { + return None; + } + let tail = self.tail; + self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); + unsafe { Some(self.ring.get_unchecked(tail)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = count(self.tail, self.head, self.ring.len()); + (len, Some(len)) + } + + fn fold(self, mut accum: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = front.iter().fold(accum, &mut f); + back.iter().fold(accum, &mut f) + } + + fn try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let (mut iter, final_res); + if self.tail <= self.head { + // single slice self.ring[self.tail..self.head] + iter = self.ring[self.tail..self.head].iter(); + final_res = iter.try_fold(init, &mut f); + } else { + // two slices: self.ring[self.tail..], self.ring[..self.head] + let (front, back) = self.ring.split_at(self.tail); + let mut back_iter = back.iter(); + let res = back_iter.try_fold(init, &mut f); + let len = self.ring.len(); + self.tail = (self.ring.len() - back_iter.len()) & (len - 1); + iter = front[..self.head].iter(); + final_res = iter.try_fold(res?, &mut f); + } + self.tail = self.head - iter.len(); + final_res + } + + fn nth(&mut self, n: usize) -> Option { + if n >= count(self.tail, self.head, self.ring.len()) { + self.tail = self.head; + None + } else { + self.tail = wrap_index(self.tail.wrapping_add(n), self.ring.len()); + self.next() + } + } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a T> { + if self.tail == self.head { + return None; + } + self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); + unsafe { Some(self.ring.get_unchecked(self.head)) } + } + + fn rfold(self, mut accum: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = back.iter().rfold(accum, &mut f); + front.iter().rfold(accum, &mut f) + } + + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let (mut iter, final_res); + if self.tail <= self.head { + // single slice self.ring[self.tail..self.head] + iter = self.ring[self.tail..self.head].iter(); + final_res = iter.try_rfold(init, &mut f); + } else { + // two slices: self.ring[self.tail..], self.ring[..self.head] + let (front, back) = self.ring.split_at(self.tail); + let mut front_iter = front[..self.head].iter(); + let res = front_iter.try_rfold(init, &mut f); + self.head = front_iter.len(); + iter = back.iter(); + final_res = iter.try_rfold(res?, &mut f); + } + self.head = self.tail + iter.len(); + final_res + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Iter<'_, T> { + fn is_empty(&self) -> bool { + self.head == self.tail + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Iter<'_, T> {} diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs new file mode 100644 index 0000000000..3d0c3094e2 --- /dev/null +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -0,0 +1,128 @@ +use core::fmt; +use core::iter::FusedIterator; +use core::marker::PhantomData; + +use super::{count, wrap_index, RingSlices}; + +/// A mutable iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`super::VecDeque`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: super::VecDeque::iter_mut +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + // Internal safety invariant: the entire slice is dereferencable. + pub(crate) ring: *mut [T], + pub(crate) tail: usize, + pub(crate) head: usize, + pub(crate) phantom: PhantomData<&'a mut [T]>, +} + +// SAFETY: we do nothing thread-local and there is no interior mutability, +// so the usual structural `Send`/`Sync` apply. +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for IterMut<'_, T> {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for IterMut<'_, T> {} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + // SAFETY: these are the elements we have not handed out yet, so aliasing is fine. + // The `IterMut` invariant also ensures everything is dereferencable. + let (front, back) = unsafe { (&*front, &*back) }; + f.debug_tuple("IterMut").field(&front).field(&back).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + #[inline] + fn next(&mut self) -> Option<&'a mut T> { + if self.tail == self.head { + return None; + } + let tail = self.tail; + self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); + + unsafe { + let elem = self.ring.get_unchecked_mut(tail); + Some(&mut *elem) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = count(self.tail, self.head, self.ring.len()); + (len, Some(len)) + } + + fn fold(self, mut accum: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + // SAFETY: these are the elements we have not handed out yet, so aliasing is fine. + // The `IterMut` invariant also ensures everything is dereferencable. + let (front, back) = unsafe { (&mut *front, &mut *back) }; + accum = front.iter_mut().fold(accum, &mut f); + back.iter_mut().fold(accum, &mut f) + } + + fn nth(&mut self, n: usize) -> Option { + if n >= count(self.tail, self.head, self.ring.len()) { + self.tail = self.head; + None + } else { + self.tail = wrap_index(self.tail.wrapping_add(n), self.ring.len()); + self.next() + } + } + + #[inline] + fn last(mut self) -> Option<&'a mut T> { + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut T> { + if self.tail == self.head { + return None; + } + self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); + + unsafe { + let elem = self.ring.get_unchecked_mut(self.head); + Some(&mut *elem) + } + } + + fn rfold(self, mut accum: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + // SAFETY: these are the elements we have not handed out yet, so aliasing is fine. + // The `IterMut` invariant also ensures everything is dereferencable. + let (front, back) = unsafe { (&mut *front, &mut *back) }; + accum = back.iter_mut().rfold(accum, &mut f); + front.iter_mut().rfold(accum, &mut f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IterMut<'_, T> { + fn is_empty(&self) -> bool { + self.head == self.tail + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IterMut<'_, T> {} diff --git a/library/alloc/src/collections/vec_deque/macros.rs b/library/alloc/src/collections/vec_deque/macros.rs new file mode 100644 index 0000000000..0d59d312cf --- /dev/null +++ b/library/alloc/src/collections/vec_deque/macros.rs @@ -0,0 +1,19 @@ +macro_rules! __impl_slice_eq1 { + ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => { + #[stable(feature = "vec_deque_partial_eq_slice", since = "1.17.0")] + impl PartialEq<$rhs> for $lhs + where + A: PartialEq, + $($constraints)* + { + fn eq(&self, other: &$rhs) -> bool { + if self.len() != other.len() { + return false; + } + let (sa, sb) = self.as_slices(); + let (oa, ob) = other[..].split_at(sa.len()); + sa == oa && sb == ob + } + } + } +} diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque/mod.rs similarity index 86% rename from library/alloc/src/collections/vec_deque.rs rename to library/alloc/src/collections/vec_deque/mod.rs index c0a3ca6a58..9e54c15ea6 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -7,16 +7,13 @@ #![stable(feature = "rust1", since = "1.0.0")] -// ignore-tidy-filelength - -use core::array; use core::cmp::{self, Ordering}; use core::fmt; use core::hash::{Hash, Hasher}; -use core::iter::{repeat_with, FromIterator, FusedIterator}; +use core::iter::{repeat_with, FromIterator}; use core::marker::PhantomData; -use core::mem::{self, replace, ManuallyDrop}; -use core::ops::{Index, IndexMut, Range, RangeBounds, Try}; +use core::mem::{self, ManuallyDrop}; +use core::ops::{Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice; @@ -24,11 +21,37 @@ use crate::collections::TryReserveError; use crate::raw_vec::RawVec; use crate::vec::Vec; +#[macro_use] +mod macros; + #[stable(feature = "drain", since = "1.6.0")] pub use self::drain::Drain; mod drain; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::iter_mut::IterMut; + +mod iter_mut; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::into_iter::IntoIter; + +mod into_iter; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::iter::Iter; + +mod iter; + +use self::pair_slices::PairSlices; + +mod pair_slices; + +use self::ring_slices::RingSlices; + +mod ring_slices; + #[cfg(test)] mod tests; @@ -68,67 +91,6 @@ pub struct VecDeque { buf: RawVec, } -/// PairSlices pairs up equal length slice parts of two deques -/// -/// For example, given deques "A" and "B" with the following division into slices: -/// -/// A: [0 1 2] [3 4 5] -/// B: [a b] [c d e] -/// -/// It produces the following sequence of matching slices: -/// -/// ([0 1], [a b]) -/// (\[2\], \[c\]) -/// ([3 4], [d e]) -/// -/// and the uneven remainder of either A or B is skipped. -struct PairSlices<'a, 'b, T> { - a0: &'a mut [T], - a1: &'a mut [T], - b0: &'b [T], - b1: &'b [T], -} - -impl<'a, 'b, T> PairSlices<'a, 'b, T> { - fn from(to: &'a mut VecDeque, from: &'b VecDeque) -> Self { - let (a0, a1) = to.as_mut_slices(); - let (b0, b1) = from.as_slices(); - PairSlices { a0, a1, b0, b1 } - } - - fn has_remainder(&self) -> bool { - !self.b0.is_empty() - } - - fn remainder(self) -> impl Iterator { - array::IntoIter::new([self.b0, self.b1]) - } -} - -impl<'a, 'b, T> Iterator for PairSlices<'a, 'b, T> { - type Item = (&'a mut [T], &'b [T]); - fn next(&mut self) -> Option { - // Get next part length - let part = cmp::min(self.a0.len(), self.b0.len()); - if part == 0 { - return None; - } - let (p0, p1) = replace(&mut self.a0, &mut []).split_at_mut(part); - let (q0, q1) = self.b0.split_at(part); - - // Move a1 into a0, if it's empty (and b1, b0 the same way). - self.a0 = p1; - self.b0 = q1; - if self.a0.is_empty() { - self.a0 = replace(&mut self.a1, &mut []); - } - if self.b0.is_empty() { - self.b0 = replace(&mut self.b1, &[]); - } - Some((p0, q0)) - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Clone for VecDeque { fn clone(&self) -> VecDeque { @@ -2002,7 +1964,7 @@ impl VecDeque { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); + /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); /// let buf2 = buf.split_off(1); /// assert_eq!(buf, [1]); /// assert_eq!(buf2, [2, 3]); @@ -2560,10 +2522,10 @@ impl VecDeque { /// (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), /// (1, 21), (2, 34), (4, 55)].into(); /// - /// assert_eq!(deque.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); - /// assert_eq!(deque.binary_search_by_key(&4, |&(a,b)| b), Err(7)); - /// assert_eq!(deque.binary_search_by_key(&100, |&(a,b)| b), Err(13)); - /// let r = deque.binary_search_by_key(&1, |&(a,b)| b); + /// assert_eq!(deque.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(deque.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(deque.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = deque.binary_search_by_key(&1, |&(a, b)| b); /// assert!(matches!(r, Ok(1..=4))); /// ``` #[unstable(feature = "vecdeque_binary_search", issue = "78021")] @@ -2613,61 +2575,6 @@ fn wrap_index(index: usize, size: usize) -> usize { index & (size - 1) } -/// Returns the two slices that cover the `VecDeque`'s valid range -trait RingSlices: Sized { - fn slice(self, from: usize, to: usize) -> Self; - fn split_at(self, i: usize) -> (Self, Self); - - fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) { - let contiguous = tail <= head; - if contiguous { - let (empty, buf) = buf.split_at(0); - (buf.slice(tail, head), empty) - } else { - let (mid, right) = buf.split_at(tail); - let (left, _) = mid.split_at(head); - (right, left) - } - } -} - -impl RingSlices for &[T] { - fn slice(self, from: usize, to: usize) -> Self { - &self[from..to] - } - fn split_at(self, i: usize) -> (Self, Self) { - (*self).split_at(i) - } -} - -impl RingSlices for &mut [T] { - fn slice(self, from: usize, to: usize) -> Self { - &mut self[from..to] - } - fn split_at(self, i: usize) -> (Self, Self) { - (*self).split_at_mut(i) - } -} - -impl RingSlices for *mut [T] { - fn slice(self, from: usize, to: usize) -> Self { - assert!(from <= to && to < self.len()); - // Not using `get_unchecked_mut` to keep this a safe operation. - let len = to - from; - ptr::slice_from_raw_parts_mut(self.as_mut_ptr().wrapping_add(from), len) - } - - fn split_at(self, mid: usize) -> (Self, Self) { - let len = self.len(); - let ptr = self.as_mut_ptr(); - assert!(mid <= len); - ( - ptr::slice_from_raw_parts_mut(ptr, mid), - ptr::slice_from_raw_parts_mut(ptr.wrapping_add(mid), len - mid), - ) - } -} - /// Calculate the number of elements left to be read in the buffer #[inline] fn count(tail: usize, head: usize, size: usize) -> usize { @@ -2675,336 +2582,6 @@ fn count(tail: usize, head: usize, size: usize) -> usize { (head.wrapping_sub(tail)) & (size - 1) } -/// An iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its -/// documentation for more. -/// -/// [`iter`]: VecDeque::iter -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - ring: &'a [T], - tail: usize, - head: usize, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Iter<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - f.debug_tuple("Iter").field(&front).field(&back).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Iter<'_, T> { - fn clone(&self) -> Self { - Iter { ring: self.ring, tail: self.tail, head: self.head } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - if self.tail == self.head { - return None; - } - let tail = self.tail; - self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); - unsafe { Some(self.ring.get_unchecked(tail)) } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = count(self.tail, self.head, self.ring.len()); - (len, Some(len)) - } - - fn fold(self, mut accum: Acc, mut f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = front.iter().fold(accum, &mut f); - back.iter().fold(accum, &mut f) - } - - fn try_fold(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - let (mut iter, final_res); - if self.tail <= self.head { - // single slice self.ring[self.tail..self.head] - iter = self.ring[self.tail..self.head].iter(); - final_res = iter.try_fold(init, &mut f); - } else { - // two slices: self.ring[self.tail..], self.ring[..self.head] - let (front, back) = self.ring.split_at(self.tail); - let mut back_iter = back.iter(); - let res = back_iter.try_fold(init, &mut f); - let len = self.ring.len(); - self.tail = (self.ring.len() - back_iter.len()) & (len - 1); - iter = front[..self.head].iter(); - final_res = iter.try_fold(res?, &mut f); - } - self.tail = self.head - iter.len(); - final_res - } - - fn nth(&mut self, n: usize) -> Option { - if n >= count(self.tail, self.head, self.ring.len()) { - self.tail = self.head; - None - } else { - self.tail = wrap_index(self.tail.wrapping_add(n), self.ring.len()); - self.next() - } - } - - #[inline] - fn last(mut self) -> Option<&'a T> { - self.next_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Iter<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a T> { - if self.tail == self.head { - return None; - } - self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); - unsafe { Some(self.ring.get_unchecked(self.head)) } - } - - fn rfold(self, mut accum: Acc, mut f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = back.iter().rfold(accum, &mut f); - front.iter().rfold(accum, &mut f) - } - - fn try_rfold(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - let (mut iter, final_res); - if self.tail <= self.head { - // single slice self.ring[self.tail..self.head] - iter = self.ring[self.tail..self.head].iter(); - final_res = iter.try_rfold(init, &mut f); - } else { - // two slices: self.ring[self.tail..], self.ring[..self.head] - let (front, back) = self.ring.split_at(self.tail); - let mut front_iter = front[..self.head].iter(); - let res = front_iter.try_rfold(init, &mut f); - self.head = front_iter.len(); - iter = back.iter(); - final_res = iter.try_rfold(res?, &mut f); - } - self.head = self.tail + iter.len(); - final_res - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Iter<'_, T> { - fn is_empty(&self) -> bool { - self.head == self.tail - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Iter<'_, T> {} - -/// A mutable iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its -/// documentation for more. -/// -/// [`iter_mut`]: VecDeque::iter_mut -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IterMut<'a, T: 'a> { - // Internal safety invariant: the entire slice is dereferencable. - ring: *mut [T], - tail: usize, - head: usize, - phantom: PhantomData<&'a mut [T]>, -} - -// SAFETY: we do nothing thread-local and there is no interior mutability, -// so the usual structural `Send`/`Sync` apply. -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IterMut<'_, T> {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IterMut<'_, T> {} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IterMut<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - // SAFETY: these are the elements we have not handed out yet, so aliasing is fine. - // The `IterMut` invariant also ensures everything is dereferencable. - let (front, back) = unsafe { (&*front, &*back) }; - f.debug_tuple("IterMut").field(&front).field(&back).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for IterMut<'a, T> { - type Item = &'a mut T; - - #[inline] - fn next(&mut self) -> Option<&'a mut T> { - if self.tail == self.head { - return None; - } - let tail = self.tail; - self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); - - unsafe { - let elem = self.ring.get_unchecked_mut(tail); - Some(&mut *elem) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = count(self.tail, self.head, self.ring.len()); - (len, Some(len)) - } - - fn fold(self, mut accum: Acc, mut f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - // SAFETY: these are the elements we have not handed out yet, so aliasing is fine. - // The `IterMut` invariant also ensures everything is dereferencable. - let (front, back) = unsafe { (&mut *front, &mut *back) }; - accum = front.iter_mut().fold(accum, &mut f); - back.iter_mut().fold(accum, &mut f) - } - - fn nth(&mut self, n: usize) -> Option { - if n >= count(self.tail, self.head, self.ring.len()) { - self.tail = self.head; - None - } else { - self.tail = wrap_index(self.tail.wrapping_add(n), self.ring.len()); - self.next() - } - } - - #[inline] - fn last(mut self) -> Option<&'a mut T> { - self.next_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut T> { - if self.tail == self.head { - return None; - } - self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); - - unsafe { - let elem = self.ring.get_unchecked_mut(self.head); - Some(&mut *elem) - } - } - - fn rfold(self, mut accum: Acc, mut f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - // SAFETY: these are the elements we have not handed out yet, so aliasing is fine. - // The `IterMut` invariant also ensures everything is dereferencable. - let (front, back) = unsafe { (&mut *front, &mut *back) }; - accum = back.iter_mut().rfold(accum, &mut f); - front.iter_mut().rfold(accum, &mut f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IterMut<'_, T> { - fn is_empty(&self) -> bool { - self.head == self.tail - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IterMut<'_, T> {} - -/// An owning iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`into_iter`] method on [`VecDeque`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`into_iter`]: VecDeque::into_iter -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - inner: VecDeque, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IntoIter").field(&self.inner).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.inner.pop_front() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.inner.len(); - (len, Some(len)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.pop_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - fn is_empty(&self) -> bool { - self.inner.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for VecDeque { fn eq(&self, other: &VecDeque) -> bool { @@ -3047,26 +2624,6 @@ impl PartialEq for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for VecDeque {} -macro_rules! __impl_slice_eq1 { - ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => { - #[stable(feature = "vec_deque_partial_eq_slice", since = "1.17.0")] - impl PartialEq<$rhs> for $lhs - where - A: PartialEq, - $($constraints)* - { - fn eq(&self, other: &$rhs) -> bool { - if self.len() != other.len() { - return false; - } - let (sa, sb) = self.as_slices(); - let (oa, ob) = other[..].split_at(sa.len()); - sa == oa && sb == ob - } - } - } -} - __impl_slice_eq1! { [] VecDeque, Vec, } __impl_slice_eq1! { [] VecDeque, &[B], } __impl_slice_eq1! { [] VecDeque, &mut [B], } @@ -3236,8 +2793,12 @@ impl From> for VecDeque { let len = other.len(); // We need to extend the buf if it's not a power of two, too small - // or doesn't have at least one free space - if !buf.capacity().is_power_of_two() + // or doesn't have at least one free space. + // We check if `T` is a ZST in the first condition, + // because `usize::MAX` (the capacity returned by `capacity()` for ZST) + // is not a power of two and thus it'll always try + // to reserve more memory which will panic for ZST (rust-lang/rust#78532) + if (!buf.capacity().is_power_of_two() && mem::size_of::() != 0) || (buf.capacity() < (MINIMUM_CAPACITY + 1)) || (buf.capacity() == len) { diff --git a/library/alloc/src/collections/vec_deque/pair_slices.rs b/library/alloc/src/collections/vec_deque/pair_slices.rs new file mode 100644 index 0000000000..812765d0b0 --- /dev/null +++ b/library/alloc/src/collections/vec_deque/pair_slices.rs @@ -0,0 +1,66 @@ +use core::array; +use core::cmp::{self}; +use core::mem::replace; + +use super::VecDeque; + +/// PairSlices pairs up equal length slice parts of two deques +/// +/// For example, given deques "A" and "B" with the following division into slices: +/// +/// A: [0 1 2] [3 4 5] +/// B: [a b] [c d e] +/// +/// It produces the following sequence of matching slices: +/// +/// ([0 1], [a b]) +/// (\[2\], \[c\]) +/// ([3 4], [d e]) +/// +/// and the uneven remainder of either A or B is skipped. +pub struct PairSlices<'a, 'b, T> { + pub(crate) a0: &'a mut [T], + pub(crate) a1: &'a mut [T], + pub(crate) b0: &'b [T], + pub(crate) b1: &'b [T], +} + +impl<'a, 'b, T> PairSlices<'a, 'b, T> { + pub fn from(to: &'a mut VecDeque, from: &'b VecDeque) -> Self { + let (a0, a1) = to.as_mut_slices(); + let (b0, b1) = from.as_slices(); + PairSlices { a0, a1, b0, b1 } + } + + pub fn has_remainder(&self) -> bool { + !self.b0.is_empty() + } + + pub fn remainder(self) -> impl Iterator { + array::IntoIter::new([self.b0, self.b1]) + } +} + +impl<'a, 'b, T> Iterator for PairSlices<'a, 'b, T> { + type Item = (&'a mut [T], &'b [T]); + fn next(&mut self) -> Option { + // Get next part length + let part = cmp::min(self.a0.len(), self.b0.len()); + if part == 0 { + return None; + } + let (p0, p1) = replace(&mut self.a0, &mut []).split_at_mut(part); + let (q0, q1) = self.b0.split_at(part); + + // Move a1 into a0, if it's empty (and b1, b0 the same way). + self.a0 = p1; + self.b0 = q1; + if self.a0.is_empty() { + self.a0 = replace(&mut self.a1, &mut []); + } + if self.b0.is_empty() { + self.b0 = replace(&mut self.b1, &[]); + } + Some((p0, q0)) + } +} diff --git a/library/alloc/src/collections/vec_deque/ring_slices.rs b/library/alloc/src/collections/vec_deque/ring_slices.rs new file mode 100644 index 0000000000..dd0fa7d607 --- /dev/null +++ b/library/alloc/src/collections/vec_deque/ring_slices.rs @@ -0,0 +1,56 @@ +use core::ptr::{self}; + +/// Returns the two slices that cover the `VecDeque`'s valid range +pub trait RingSlices: Sized { + fn slice(self, from: usize, to: usize) -> Self; + fn split_at(self, i: usize) -> (Self, Self); + + fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) { + let contiguous = tail <= head; + if contiguous { + let (empty, buf) = buf.split_at(0); + (buf.slice(tail, head), empty) + } else { + let (mid, right) = buf.split_at(tail); + let (left, _) = mid.split_at(head); + (right, left) + } + } +} + +impl RingSlices for &[T] { + fn slice(self, from: usize, to: usize) -> Self { + &self[from..to] + } + fn split_at(self, i: usize) -> (Self, Self) { + (*self).split_at(i) + } +} + +impl RingSlices for &mut [T] { + fn slice(self, from: usize, to: usize) -> Self { + &mut self[from..to] + } + fn split_at(self, i: usize) -> (Self, Self) { + (*self).split_at_mut(i) + } +} + +impl RingSlices for *mut [T] { + fn slice(self, from: usize, to: usize) -> Self { + assert!(from <= to && to < self.len()); + // Not using `get_unchecked_mut` to keep this a safe operation. + let len = to - from; + ptr::slice_from_raw_parts_mut(self.as_mut_ptr().wrapping_add(from), len) + } + + fn split_at(self, mid: usize) -> (Self, Self) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + assert!(mid <= len); + ( + ptr::slice_from_raw_parts_mut(ptr, mid), + ptr::slice_from_raw_parts_mut(ptr.wrapping_add(mid), len - mid), + ) + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f21fc8854d..3ac34c9ae2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -72,7 +72,7 @@ #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] #![deny(unsafe_op_in_unsafe_fn)] -#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] +#![feature(rustc_allow_const_fn_unstable)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] #![cfg_attr(test, feature(new_uninit))] @@ -112,7 +112,8 @@ #![feature(never_type)] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] -#![feature(optin_builtin_traits)] +#![cfg_attr(bootstrap, feature(optin_builtin_traits))] +#![cfg_attr(not(bootstrap), feature(auto_traits))] #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] @@ -130,8 +131,7 @@ #![feature(unicode_internals)] #![feature(unsafe_block_in_unsafe_fn)] #![feature(unsize)] -#![cfg_attr(not(bootstrap), feature(unsized_fn_params))] -#![cfg_attr(bootstrap, feature(unsized_locals))] +#![feature(unsized_fn_params)] #![feature(allocator_internals)] #![feature(slice_partition_dedup)] #![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index a992d768d6..7d4eff6185 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -29,6 +29,10 @@ /// to the same boxed integer value, not five references pointing to independently /// boxed integers. /// +/// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector. +/// This will still evaluate `expr`, however, and immediately drop the resulting value, so +/// be mindful of side effects. +/// /// [`Vec`]: crate::vec::Vec #[cfg(not(test))] #[macro_export] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index a4240308bb..36b7efc33a 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -1,7 +1,7 @@ #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")] #![doc(hidden)] -use core::alloc::LayoutErr; +use core::alloc::LayoutError; use core::cmp; use core::intrinsics; use core::mem::{self, ManuallyDrop, MaybeUninit}; @@ -9,7 +9,7 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{handle_alloc_error, Allocator, Global, Layout}; use crate::boxed::Box; use crate::collections::TryReserveError::{self, *}; @@ -46,7 +46,7 @@ enum AllocInit { /// `usize::MAX`. This means that you need to be careful when round-tripping this type with a /// `Box<[T]>`, since `capacity()` won't yield the length. #[allow(missing_debug_implementations)] -pub struct RawVec { +pub struct RawVec { ptr: Unique, cap: usize, alloc: A, @@ -113,11 +113,10 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] + #[rustc_allow_const_fn_unstable(const_fn)] pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr: Unique::dangling(), cap: 0, alloc } @@ -140,7 +139,7 @@ impl RawVec { /// Converts a `Box<[T]>` into a `RawVec`. pub fn from_box(slice: Box<[T], A>) -> Self { unsafe { - let (slice, alloc) = Box::into_raw_with_alloc(slice); + let (slice, alloc) = Box::into_raw_with_allocator(slice); RawVec::from_raw_parts_in(slice.as_mut_ptr(), slice.len(), alloc) } } @@ -186,8 +185,8 @@ impl RawVec { Err(_) => capacity_overflow(), } let result = match init { - AllocInit::Uninitialized => alloc.alloc(layout), - AllocInit::Zeroed => alloc.alloc_zeroed(layout), + AllocInit::Uninitialized => alloc.allocate(layout), + AllocInit::Zeroed => alloc.allocate_zeroed(layout), }; let ptr = match result { Ok(ptr) => ptr, @@ -233,15 +232,10 @@ impl RawVec { } /// Returns a shared reference to the allocator backing this `RawVec`. - pub fn alloc(&self) -> &A { + pub fn allocator(&self) -> &A { &self.alloc } - /// Returns a mutable reference to the allocator backing this `RawVec`. - pub fn alloc_mut(&mut self) -> &mut A { - &mut self.alloc - } - fn current_memory(&self) -> Option<(NonNull, Layout)> { if mem::size_of::() == 0 || self.cap == 0 { None @@ -365,7 +359,7 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Returns if the buffer needs to grow to fulfill the needed extra capacity. /// Mainly used to make inlining reserve-calls possible without inlining `grow`. fn needs_to_grow(&self, len: usize, additional: usize) -> bool { @@ -471,13 +465,14 @@ impl RawVec { // above `RawVec::grow_amortized` for details. (The `A` parameter isn't // significant, because the number of different `A` types seen in practice is // much smaller than the number of `T` types.) +#[inline(never)] fn finish_grow( - new_layout: Result, + new_layout: Result, current_memory: Option<(NonNull, Layout)>, alloc: &mut A, ) -> Result, TryReserveError> where - A: AllocRef, + A: Allocator, { // Check for the error here to minimize the size of `RawVec::grow_*`. let new_layout = new_layout.map_err(|_| CapacityOverflow)?; @@ -492,17 +487,17 @@ where alloc.grow(ptr, old_layout, new_layout) } } else { - alloc.alloc(new_layout) + alloc.allocate(new_layout) }; memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) } -unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) { if let Some((ptr, layout)) = self.current_memory() { - unsafe { self.alloc.dealloc(ptr, layout) } + unsafe { self.alloc.deallocate(ptr, layout) } } } } diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index cb4fe1b46c..8c15a24409 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -20,13 +20,13 @@ fn allocator_param() { struct BoundedAlloc { fuel: Cell, } - unsafe impl AllocRef for BoundedAlloc { - fn alloc(&self, layout: Layout) -> Result, AllocError> { + unsafe impl Allocator for BoundedAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { let size = layout.size(); if size > self.fuel.get() { return Err(AllocError); } - match Global.alloc(layout) { + match Global.allocate(layout) { ok @ Ok(_) => { self.fuel.set(self.fuel.get() - size); ok @@ -34,8 +34,8 @@ fn allocator_param() { err @ Err(_) => err, } } - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { - unsafe { Global.dealloc(ptr, layout) } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { Global.deallocate(ptr, layout) } } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 7217d81d9d..73d12f0a5f 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -262,7 +262,7 @@ use core::pin::Pin; use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -416,7 +416,7 @@ impl Rc { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| mem as *mut RcBox>, )) } @@ -447,7 +447,7 @@ impl Rc { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| mem as *mut RcBox>, )) } @@ -555,7 +555,7 @@ impl Rc<[T]> { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[mem::MaybeUninit]> @@ -1040,7 +1040,7 @@ impl Rc { unsafe { Self::allocate_for_layout( Layout::for_value(&*ptr), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox, ) } @@ -1075,7 +1075,7 @@ impl Rc<[T]> { unsafe { Self::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>, ) } @@ -1125,7 +1125,7 @@ impl Rc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout); + Global.deallocate(self.mem, self.layout); } } } @@ -1225,7 +1225,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.inner().dec_weak(); if self.inner().weak() == 0 { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -2042,7 +2042,7 @@ impl Drop for Weak { // the strong pointers have disappeared. if inner.weak() == 0 { unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 3db6696494..064700fc72 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -87,6 +87,7 @@ use core::cmp::Ordering::{self, Less}; use core::mem::{self, size_of}; use core::ptr; +use crate::alloc::{Allocator, Global}; use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; @@ -137,28 +138,82 @@ pub use hack::to_vec; // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test mod hack { + use core::alloc::Allocator; + use crate::boxed::Box; use crate::vec::Vec; // We shouldn't add inline attribute to this since this is used in // `vec!` macro mostly and causes perf regression. See #71204 for // discussion and perf results. - pub fn into_vec(b: Box<[T]>) -> Vec { + pub fn into_vec(b: Box<[T], A>) -> Vec { unsafe { let len = b.len(); - let b = Box::into_raw(b); - Vec::from_raw_parts(b as *mut T, len, len) + let (b, alloc) = Box::into_raw_with_allocator(b); + Vec::from_raw_parts_in(b as *mut T, len, len, alloc) } } #[inline] - pub fn to_vec(s: &[T]) -> Vec - where - T: Clone, - { - let mut vec = Vec::with_capacity(s.len()); - vec.extend_from_slice(s); - vec + pub fn to_vec(s: &[T], alloc: A) -> Vec { + T::to_vec(s, alloc) + } + + pub trait ConvertVec { + fn to_vec(s: &[Self], alloc: A) -> Vec + where + Self: Sized; + } + + impl ConvertVec for T { + #[inline] + default fn to_vec(s: &[Self], alloc: A) -> Vec { + struct DropGuard<'a, T, A: Allocator> { + vec: &'a mut Vec, + num_init: usize, + } + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + #[inline] + fn drop(&mut self) { + // SAFETY: + // items were marked initialized in the loop below + unsafe { + self.vec.set_len(self.num_init); + } + } + } + let mut vec = Vec::with_capacity_in(s.len(), alloc); + let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; + let slots = guard.vec.spare_capacity_mut(); + // .take(slots.len()) is necessary for LLVM to remove bounds checks + // and has better codegen than zip. + for (i, b) in s.iter().enumerate().take(slots.len()) { + guard.num_init = i; + slots[i].write(b.clone()); + } + core::mem::forget(guard); + // SAFETY: + // the vec was allocated and initialized above to at least this length. + unsafe { + vec.set_len(s.len()); + } + vec + } + } + + impl ConvertVec for T { + #[inline] + fn to_vec(s: &[Self], alloc: A) -> Vec { + let mut v = Vec::with_capacity_in(s.len(), alloc); + // SAFETY: + // allocated above with the capacity of `s`, and initialize to `s.len()` in + // ptr::copy_to_non_overlapping below. + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); + v.set_len(s.len()); + } + v + } } } @@ -388,11 +443,33 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_vec(&self) -> Vec + where + T: Clone, + { + self.to_vec_in(Global) + } + + /// Copies `self` into a new `Vec` with an allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let s = [10, 40, 30]; + /// let x = s.to_vec_in(System); + /// // Here, `s` and `x` can be modified independently. + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn to_vec_in(&self, alloc: A) -> Vec where T: Clone, { // N.B., see the `hack` module in this file for more details. - hack::to_vec(self) + hack::to_vec(self, alloc) } /// Converts `self` into a vector without clones or allocation. @@ -411,7 +488,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn into_vec(self: Box) -> Vec { + pub fn into_vec(self: Box) -> Vec { // N.B., see the `hack` module in this file for more details. hack::into_vec(self) } @@ -730,7 +807,7 @@ impl ToOwned for [T] { #[cfg(test)] fn to_owned(&self) -> Vec { - hack::to_vec(self) + hack::to_vec(self, Global) } fn clone_into(&self, target: &mut Vec) { diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 339592728a..578eca7d89 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -388,7 +388,7 @@ impl str { } fn case_ignoreable_then_cased>(iter: I) -> bool { - use core::unicode::derived_property::{Case_Ignorable, Cased}; + use core::unicode::{Case_Ignorable, Cased}; match iter.skip_while(|&c| Case_Ignorable(c)).next() { Some(c) => Cased(c), None => false, diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ce216e5336..27b32b6950 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1413,7 +1413,7 @@ impl String { self.len() == 0 } - /// Splits the string into two at the given index. + /// Splits the string into two at the given byte index. /// /// Returns a newly allocated `String`. `self` contains bytes `[0, at)`, and /// the returned `String` contains bytes `[at, len)`. `at` must be on the diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5db9132f94..53ba9c283a 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -22,7 +22,7 @@ use core::slice::from_raw_parts_mut; use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -434,7 +434,7 @@ impl Arc { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| mem as *mut ArcInner>, )) } @@ -465,7 +465,7 @@ impl Arc { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| mem as *mut ArcInner>, )) } @@ -572,7 +572,7 @@ impl Arc<[T]> { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[mem::MaybeUninit]> @@ -1015,7 +1015,7 @@ impl Arc { unsafe { Self::allocate_for_layout( Layout::for_value(&*ptr), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner, ) } @@ -1050,7 +1050,7 @@ impl Arc<[T]> { unsafe { Self::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, ) } @@ -1102,7 +1102,7 @@ impl Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout); + Global.deallocate(self.mem, self.layout); } } } @@ -1927,7 +1927,7 @@ impl Drop for Weak { if inner.weak.fetch_sub(1, Release) == 1 { acquire!(inner.weak); - unsafe { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } + unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } } } diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 2c8bc3d53e..2b08f1f362 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -68,6 +68,7 @@ use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; +use crate::alloc::{Allocator, Global}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; @@ -297,8 +298,8 @@ use crate::raw_vec::RawVec; /// [`&`]: ../../std/primitive.reference.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] -pub struct Vec { - buf: RawVec, +pub struct Vec { + buf: RawVec, len: usize, } @@ -320,7 +321,7 @@ impl Vec { #[inline] #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")] #[stable(feature = "rust1", since = "1.0.0")] - pub const fn new() -> Vec { + pub const fn new() -> Self { Vec { buf: RawVec::NEW, len: 0 } } @@ -359,49 +360,145 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize) -> Vec { - Vec { buf: RawVec::with_capacity(capacity), len: 0 } + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) } - /// Decomposes a `Vec` into its raw components. + /// Creates a `Vec` directly from the raw components of another vector. /// - /// Returns the raw pointer to the underlying data, the length of - /// the vector (in elements), and the allocated capacity of the - /// data (in elements). These are the same arguments in the same - /// order as the arguments to [`from_raw_parts`]. + /// # Safety /// - /// After calling this function, the caller is responsible for the - /// memory previously managed by the `Vec`. The only way to do - /// this is to convert the raw pointer, length, and capacity back - /// into a `Vec` with the [`from_raw_parts`] function, allowing - /// the destructor to perform the cleanup. + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: /// - /// [`from_raw_parts`]: Vec::from_raw_parts + /// * `ptr` needs to have been previously allocated via [`String`]/`Vec` + /// (at least, it's highly likely to be incorrect if it wasn't). + /// * `T` needs to have the same size and alignment as what `ptr` was allocated with. + /// (`T` having a less strict alignment is not sufficient, the alignment really + /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be + /// allocated and deallocated with the same layout.) + /// * `length` needs to be less than or equal to `capacity`. + /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. For example it is **not** safe + /// to build a `Vec` from a pointer to a C `char` array with length `size_t`. + /// It's also not safe to build one from a `Vec` and its length, because + /// the allocator cares about the alignment, and these two types have different + /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after + /// turning it into a `Vec` it'll be deallocated with alignment 1. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// [`String`]: crate::string::String + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc /// /// # Examples /// /// ``` - /// #![feature(vec_into_raw_parts)] - /// let v: Vec = vec![-1, 0, 1]; + /// use std::ptr; + /// use std::mem; /// - /// let (ptr, len, cap) = v.into_raw_parts(); + /// let v = vec![1, 2, 3]; /// - /// let rebuilt = unsafe { - /// // We can now make changes to the components, such as - /// // transmuting the raw pointer to a compatible type. - /// let ptr = ptr as *mut u32; + // FIXME Update this when vec_into_raw_parts is stabilized + /// // Prevent running `v`'s destructor so we are in complete control + /// // of the allocation. + /// let mut v = mem::ManuallyDrop::new(v); /// - /// Vec::from_raw_parts(ptr, len, cap) - /// }; - /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// // Pull out the various important pieces of information about `v` + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); + /// + /// unsafe { + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len as isize { + /// ptr::write(p.offset(i), 4 + i); + /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_raw_parts(p, len, cap); + /// assert_eq!(rebuilt, [4, 5, 6]); + /// } /// ``` - #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_raw_parts(self) -> (*mut T, usize, usize) { - let mut me = ManuallyDrop::new(self); - (me.as_mut_ptr(), me.len(), me.capacity()) + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { + unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) } } +} - /// Creates a `Vec` directly from the raw components of another vector. +impl Vec { + /// Constructs a new, empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// # #[allow(unused_mut)] + /// let mut vec: Vec = Vec::new_in(System); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub const fn new_in(alloc: A) -> Self { + Vec { buf: RawVec::new_in(alloc), len: 0 } + } + + /// Constructs a new, empty `Vec` with the specified capacity with the provided + /// allocator. + /// + /// The vector will be able to hold exactly `capacity` elements without + /// reallocating. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// *capacity* specified, the vector will have a zero *length*. For an + /// explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let mut vec = Vec::with_capacity_in(10, System); + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.push(i); + /// } + /// assert_eq!(vec.len(), 10); + /// assert_eq!(vec.capacity(), 10); + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity() >= 11); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } + } + + /// Creates a `Vec` directly from the raw components of another vector. /// /// # Safety /// @@ -437,10 +534,17 @@ impl Vec { /// # Examples /// /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// /// use std::ptr; /// use std::mem; /// - /// let v = vec![1, 2, 3]; + /// let mut v = Vec::with_capacity_in(3, System); + /// v.push(1); + /// v.push(2); + /// v.push(3); /// // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control @@ -451,6 +555,7 @@ impl Vec { /// let p = v.as_mut_ptr(); /// let len = v.len(); /// let cap = v.capacity(); + /// let alloc = v.allocator(); /// /// unsafe { /// // Overwrite memory with 4, 5, 6 @@ -459,13 +564,100 @@ impl Vec { /// } /// /// // Put everything back together into a Vec - /// let rebuilt = Vec::from_raw_parts(p, len, cap); + /// let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone()); /// assert_eq!(rebuilt, [4, 5, 6]); /// } /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec { - unsafe { Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } } + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { + unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } + } + + /// Decomposes a `Vec` into its raw components. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_raw_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `Vec` with the [`from_raw_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts`]: Vec::from_raw_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts)] + /// let v: Vec = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_raw_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// Vec::from_raw_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + let mut me = ManuallyDrop::new(self); + (me.as_mut_ptr(), me.len(), me.capacity()) + } + + /// Decomposes a `Vec` into its raw components. + /// + /// Returns the raw pointer to the underlying data, the length of the vector (in elements), + /// the allocated capacity of the data (in elements), and the allocator. These are the same + /// arguments in the same order as the arguments to [`from_raw_parts_in`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `Vec` with the [`from_raw_parts_in`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts_in`]: Vec::from_raw_parts_in + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, vec_into_raw_parts)] + /// + /// use std::alloc::System; + /// + /// let mut v: Vec = Vec::new_in(System); + /// v.push(-1); + /// v.push(0); + /// v.push(1); + /// + /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// Vec::from_raw_parts_in(ptr, len, cap, alloc) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) { + let mut me = ManuallyDrop::new(self); + let len = me.len(); + let capacity = me.capacity(); + let ptr = me.as_mut_ptr(); + let alloc = unsafe { ptr::read(me.allocator()) }; + (ptr, len, capacity, alloc) } /// Returns the number of elements the vector can hold without @@ -684,7 +876,7 @@ impl Vec { /// assert_eq!(slice.into_vec().capacity(), 3); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_boxed_slice(mut self) -> Box<[T]> { + pub fn into_boxed_slice(mut self) -> Box<[T], A> { unsafe { self.shrink_to_fit(); let me = ManuallyDrop::new(self); @@ -849,7 +1041,7 @@ impl Vec { /// } /// x.set_len(size); /// } - /// assert_eq!(&*x, &[0,1,2,3]); + /// assert_eq!(&*x, &[0, 1, 2, 3]); /// ``` #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[inline] @@ -863,6 +1055,13 @@ impl Vec { ptr } + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + self.buf.allocator() + } + /// Forces the length of the vector to `new_len`. /// /// This is a low-level operation that maintains none of the normal @@ -1299,7 +1498,7 @@ impl Vec { /// assert_eq!(v, &[]); /// ``` #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self, range: R) -> Drain<'_, T> + pub fn drain(&mut self, range: R) -> Drain<'_, T, A> where R: RangeBounds, { @@ -1395,7 +1594,7 @@ impl Vec { /// # Examples /// /// ``` - /// let mut vec = vec![1,2,3]; + /// let mut vec = vec![1, 2, 3]; /// let vec2 = vec.split_off(1); /// assert_eq!(vec, [1]); /// assert_eq!(vec2, [2, 3]); @@ -1403,7 +1602,10 @@ impl Vec { #[inline] #[must_use = "use `.truncate()` if you don't need the other half"] #[stable(feature = "split_off", since = "1.4.0")] - pub fn split_off(&mut self, at: usize) -> Self { + pub fn split_off(&mut self, at: usize) -> Self + where + A: Clone, + { #[cold] #[inline(never)] fn assert_failed(at: usize, len: usize) -> ! { @@ -1416,11 +1618,14 @@ impl Vec { if at == 0 { // the new vector can take over the original buffer and avoid the copy - return mem::replace(self, Vec::with_capacity(self.capacity())); + return mem::replace( + self, + Vec::with_capacity_in(self.capacity(), self.allocator().clone()), + ); } let other_len = self.len - at; - let mut other = Vec::with_capacity(other_len); + let mut other = Vec::with_capacity_in(other_len, self.allocator().clone()); // Unsafely `set_len` and copy items to `other`. unsafe { @@ -1497,7 +1702,7 @@ impl Vec { #[inline] pub fn leak<'a>(self) -> &'a mut [T] where - T: 'a, // Technically not needed, but kept to be explicit. + A: 'a, { Box::leak(self.into_boxed_slice()) } @@ -1544,7 +1749,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. /// /// If `new_len` is greater than `len`, the `Vec` is extended by the @@ -1639,7 +1844,7 @@ impl T> ExtendWith for ExtendFunc { } } -impl Vec { +impl Vec { /// Extend the vector by `n` values, using the given generator. fn extend_with>(&mut self, n: usize, mut value: E) { self.reserve(n); @@ -1699,7 +1904,7 @@ impl Drop for SetLenOnDrop<'_> { } } -impl Vec { +impl Vec { /// Removes consecutive repeated elements in the vector according to the /// [`PartialEq`] trait implementation. /// @@ -1721,7 +1926,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Removes the first instance of `item` from the vector if the item exists. /// /// This method will be removed soon. @@ -1749,17 +1954,23 @@ impl Vec { #[doc(hidden)] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_elem(elem: T, n: usize) -> Vec { - ::from_elem(elem, n) + ::from_elem(elem, n, Global) +} + +#[doc(hidden)] +#[unstable(feature = "allocator_api", issue = "32838")] +pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { + ::from_elem(elem, n, alloc) } // Specialization trait used for Vec::from_elem trait SpecFromElem: Sized { - fn from_elem(elem: Self, n: usize) -> Vec; + fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; } impl SpecFromElem for T { - default fn from_elem(elem: Self, n: usize) -> Vec { - let mut v = Vec::with_capacity(n); + default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { + let mut v = Vec::with_capacity_in(n, alloc); v.extend_with(n, ExtendElement(elem)); v } @@ -1767,12 +1978,12 @@ impl SpecFromElem for T { impl SpecFromElem for i8 { #[inline] - fn from_elem(elem: i8, n: usize) -> Vec { + fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { if elem == 0 { - return Vec { buf: RawVec::with_capacity_zeroed(n), len: n }; + return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } unsafe { - let mut v = Vec::with_capacity(n); + let mut v = Vec::with_capacity_in(n, alloc); ptr::write_bytes(v.as_mut_ptr(), elem as u8, n); v.set_len(n); v @@ -1782,12 +1993,12 @@ impl SpecFromElem for i8 { impl SpecFromElem for u8 { #[inline] - fn from_elem(elem: u8, n: usize) -> Vec { + fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { if elem == 0 { - return Vec { buf: RawVec::with_capacity_zeroed(n), len: n }; + return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } unsafe { - let mut v = Vec::with_capacity(n); + let mut v = Vec::with_capacity_in(n, alloc); ptr::write_bytes(v.as_mut_ptr(), elem, n); v.set_len(n); v @@ -1797,11 +2008,11 @@ impl SpecFromElem for u8 { impl SpecFromElem for T { #[inline] - fn from_elem(elem: T, n: usize) -> Vec { + fn from_elem(elem: T, n: usize, alloc: A) -> Vec { if elem.is_zero() { - return Vec { buf: RawVec::with_capacity_zeroed(n), len: n }; + return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } - let mut v = Vec::with_capacity(n); + let mut v = Vec::with_capacity_in(n, alloc); v.extend_with(n, ExtendElement(elem)); v } @@ -1882,7 +2093,7 @@ unsafe impl IsZero for Option> { //////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for Vec { +impl ops::Deref for Vec { type Target = [T]; fn deref(&self) -> &[T] { @@ -1891,17 +2102,18 @@ impl ops::Deref for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::DerefMut for Vec { +impl ops::DerefMut for Vec { fn deref_mut(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Vec { +impl Clone for Vec { #[cfg(not(test))] - fn clone(&self) -> Vec { - <[T]>::to_vec(&**self) + fn clone(&self) -> Self { + let alloc = self.allocator().clone(); + <[T]>::to_vec_in(&**self, alloc) } // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is @@ -1909,17 +2121,27 @@ impl Clone for Vec { // `slice::to_vec` function which is only available with cfg(test) // NB see the slice::hack module in slice.rs for more information #[cfg(test)] - fn clone(&self) -> Vec { - crate::slice::to_vec(&**self) + fn clone(&self) -> Self { + let alloc = self.allocator().clone(); + crate::slice::to_vec(&**self, alloc) } - fn clone_from(&mut self, other: &Vec) { - other.as_slice().clone_into(self); + fn clone_from(&mut self, other: &Self) { + // drop anything that will not be overwritten + self.truncate(other.len()); + + // self.len <= other.len due to the truncate above, so the + // slices here are always in-bounds. + let (init, tail) = other.split_at(self.len()); + + // reuse the contained values' allocations/resources. + self.clone_from_slice(init); + self.extend_from_slice(tail); } } #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Vec { +impl Hash for Vec { #[inline] fn hash(&self, state: &mut H) { Hash::hash(&**self, state) @@ -1931,7 +2153,7 @@ impl Hash for Vec { message = "vector indices are of type `usize` or ranges of `usize`", label = "vector indices are of type `usize` or ranges of `usize`" )] -impl> Index for Vec { +impl, A: Allocator> Index for Vec { type Output = I::Output; #[inline] @@ -1945,7 +2167,7 @@ impl> Index for Vec { message = "vector indices are of type `usize` or ranges of `usize`", label = "vector indices are of type `usize` or ranges of `usize`" )] -impl> IndexMut for Vec { +impl, A: Allocator> IndexMut for Vec { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { IndexMut::index_mut(&mut **self, index) @@ -1961,9 +2183,9 @@ impl FromIterator for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for Vec { +impl IntoIterator for Vec { type Item = T; - type IntoIter = IntoIter; + type IntoIter = IntoIter; /// Creates a consuming iterator, that is, one that moves each value out of /// the vector (from start to end). The vector cannot be used after calling @@ -1979,9 +2201,10 @@ impl IntoIterator for Vec { /// } /// ``` #[inline] - fn into_iter(self) -> IntoIter { + fn into_iter(self) -> IntoIter { unsafe { let mut me = ManuallyDrop::new(self); + let alloc = ptr::read(me.allocator()); let begin = me.as_mut_ptr(); let end = if mem::size_of::() == 0 { arith_offset(begin as *const i8, me.len() as isize) as *const T @@ -1993,6 +2216,7 @@ impl IntoIterator for Vec { buf: NonNull::new_unchecked(begin), phantom: PhantomData, cap, + alloc, ptr: begin, end, } @@ -2001,7 +2225,7 @@ impl IntoIterator for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a Vec { +impl<'a, T, A: Allocator> IntoIterator for &'a Vec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -2011,7 +2235,7 @@ impl<'a, T> IntoIterator for &'a Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut Vec { +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; @@ -2021,7 +2245,7 @@ impl<'a, T> IntoIterator for &'a mut Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for Vec { +impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()) @@ -2103,7 +2327,10 @@ where I: TrustedLen, { fn from_iter(iterator: I) -> Self { - let mut vector = Vec::new(); + let mut vector = match iterator.size_hint() { + (_, Some(upper)) => Vec::with_capacity(upper), + _ => Vec::new(), + }; // must delegate to spec_extend() since extend() itself delegates // to spec_from for empty Vecs vector.spec_extend(iterator); @@ -2284,17 +2511,23 @@ where } } -impl<'a, T: 'a> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec -where - T: Copy, -{ - // reuses the extend specialization for T: Copy +// This utilizes `iterator.as_slice().to_vec()` since spec_extend +// must take more steps to reason about the final capacity + length +// and thus do more work. `to_vec()` directly allocates the correct amount +// and fills it exactly. +impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec { + #[cfg(not(test))] fn from_iter(iterator: slice::Iter<'a, T>) -> Self { - let mut vec = Vec::new(); - // must delegate to spec_extend() since extend() itself delegates - // to spec_from for empty Vecs - vec.spec_extend(iterator); - vec + iterator.as_slice().to_vec() + } + + // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is + // required for this method definition, is not available. Instead use the + // `slice::to_vec` function which is only available with cfg(test) + // NB see the slice::hack module in slice.rs for more information + #[cfg(test)] + fn from_iter(iterator: slice::Iter<'a, T>) -> Self { + crate::slice::to_vec(iterator.as_slice(), Global) } } @@ -2303,7 +2536,7 @@ trait SpecExtend { fn spec_extend(&mut self, iter: I); } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: Iterator, { @@ -2312,7 +2545,7 @@ where } } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: TrustedLen, { @@ -2345,7 +2578,7 @@ where } } -impl SpecExtend> for Vec { +impl SpecExtend> for Vec { fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -2354,7 +2587,7 @@ impl SpecExtend> for Vec { } } -impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec +impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, @@ -2364,7 +2597,7 @@ where } } -impl<'a, T: 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec +impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, { @@ -2374,7 +2607,7 @@ where } } -impl Vec { +impl Vec { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply fn extend_desugared>(&mut self, mut iterator: I) { @@ -2434,7 +2667,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "vec_splice", since = "1.21.0")] - pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A> where R: RangeBounds, I: IntoIterator, @@ -2487,7 +2720,7 @@ impl Vec { /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]); /// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F> + pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -2509,7 +2742,7 @@ impl Vec { /// /// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { +impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } @@ -2528,9 +2761,9 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { macro_rules! __impl_slice_eq1 { ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => { #[$stability] - impl PartialEq<$rhs> for $lhs + impl PartialEq<$rhs> for $lhs where - A: PartialEq, + T: PartialEq, $($ty: $bound)? { #[inline] @@ -2541,18 +2774,18 @@ macro_rules! __impl_slice_eq1 { } } -__impl_slice_eq1! { [] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [] Vec, &[B], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [] Vec, &mut [B], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [] &[A], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [] &mut [A], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [] Vec, [B], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [] [A], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [] Cow<'_, [A]>, Vec where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [] Cow<'_, [A]>, &[B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [const N: usize] Vec, [B; N], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [const N: usize] Vec, &[B; N], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &[U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] &[T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] &mut [T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] [T], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } // NOTE: some less important impls are omitted to reduce code bloat // FIXME(Centril): Reconsider this? @@ -2566,27 +2799,27 @@ __impl_slice_eq1! { [const N: usize] Vec, &[B; N], #[stable(feature = "rust1" /// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Vec { +impl PartialOrd for Vec { #[inline] - fn partial_cmp(&self, other: &Vec) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Vec {} +impl Eq for Vec {} /// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Vec { +impl Ord for Vec { #[inline] - fn cmp(&self, other: &Vec) -> Ordering { + fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) } } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T> Drop for Vec { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { fn drop(&mut self) { unsafe { // use drop for [T] @@ -2607,35 +2840,35 @@ impl Default for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Vec { +impl fmt::Debug for Vec { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef> for Vec { - fn as_ref(&self) -> &Vec { +impl AsRef> for Vec { + fn as_ref(&self) -> &Vec { self } } #[stable(feature = "vec_as_mut", since = "1.5.0")] -impl AsMut> for Vec { - fn as_mut(&mut self) -> &mut Vec { +impl AsMut> for Vec { + fn as_mut(&mut self) -> &mut Vec { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<[T]> for Vec { +impl AsRef<[T]> for Vec { fn as_ref(&self) -> &[T] { self } } #[stable(feature = "vec_as_mut", since = "1.5.0")] -impl AsMut<[T]> for Vec { +impl AsMut<[T]> for Vec { fn as_mut(&mut self) -> &mut [T] { self } @@ -2649,7 +2882,7 @@ impl From<&[T]> for Vec { } #[cfg(test)] fn from(s: &[T]) -> Vec { - crate::slice::to_vec(s) + crate::slice::to_vec(s, Global) } } @@ -2661,7 +2894,7 @@ impl From<&mut [T]> for Vec { } #[cfg(test)] fn from(s: &mut [T]) -> Vec { - crate::slice::to_vec(s) + crate::slice::to_vec(s, Global) } } @@ -2690,17 +2923,18 @@ where // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "vec_from_box", since = "1.18.0")] -impl From> for Vec { - fn from(s: Box<[T]>) -> Vec { - s.into_vec() +impl From> for Vec { + fn from(s: Box<[T], A>) -> Self { + let len = s.len(); + Self { buf: RawVec::from_box(s), len } } } // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "box_from_vec", since = "1.20.0")] -impl From> for Box<[T]> { - fn from(v: Vec) -> Box<[T]> { +impl From> for Box<[T], A> { + fn from(v: Vec) -> Self { v.into_boxed_slice() } } @@ -2713,8 +2947,8 @@ impl From<&str> for Vec { } #[stable(feature = "array_try_from_vec", since = "1.48.0")] -impl TryFrom> for [T; N] { - type Error = Vec; +impl TryFrom> for [T; N] { + type Error = Vec; /// Gets the entire contents of the `Vec` as an array, /// if its size exactly matches that of the requested array. @@ -2745,7 +2979,7 @@ impl TryFrom> for [T; N] { /// assert_eq!(a, b' '); /// assert_eq!(b, b'd'); /// ``` - fn try_from(mut vec: Vec) -> Result<[T; N], Vec> { + fn try_from(mut vec: Vec) -> Result<[T; N], Vec> { if vec.len() != N { return Err(vec); } @@ -2814,22 +3048,26 @@ where /// let iter: std::vec::IntoIter<_> = v.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { buf: NonNull, phantom: PhantomData, cap: usize, + alloc: A, ptr: *const T, end: *const T, } #[stable(feature = "vec_intoiter_debug", since = "1.13.0")] -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } -impl IntoIter { +impl IntoIter { /// Returns the remaining items of this iterator as a slice. /// /// # Examples @@ -2864,6 +3102,13 @@ impl IntoIter { unsafe { &mut *self.as_raw_mut_slice() } } + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + &self.alloc + } + fn as_raw_mut_slice(&mut self) -> *mut [T] { ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) } @@ -2886,19 +3131,19 @@ impl IntoIter { } #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] -impl AsRef<[T]> for IntoIter { +impl AsRef<[T]> for IntoIter { fn as_ref(&self) -> &[T] { self.as_slice() } } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IntoIter {} +unsafe impl Send for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IntoIter {} +unsafe impl Sync for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = T; #[inline] @@ -2955,7 +3200,7 @@ impl Iterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { if self.end == self.ptr { @@ -2975,23 +3220,23 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { fn is_empty(&self) -> bool { self.ptr == self.end } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoIter {} +unsafe impl TrustedLen for IntoIter {} #[doc(hidden)] #[unstable(issue = "none", feature = "std_internals")] // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // and thus we can't implement drop-handling -unsafe impl TrustedRandomAccess for IntoIter +unsafe impl TrustedRandomAccess for IntoIter where T: Copy, { @@ -3001,21 +3246,30 @@ where } #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] -impl Clone for IntoIter { - fn clone(&self) -> IntoIter { - self.as_slice().to_owned().into_iter() +impl Clone for IntoIter { + #[cfg(not(test))] + fn clone(&self) -> Self { + self.as_slice().to_vec_in(self.alloc.clone()).into_iter() + } + #[cfg(test)] + fn clone(&self) -> Self { + crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter() } } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T> Drop for IntoIter { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter { fn drop(&mut self) { - struct DropGuard<'a, T>(&'a mut IntoIter); + struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter); - impl Drop for DropGuard<'_, T> { + impl Drop for DropGuard<'_, T, A> { fn drop(&mut self) { - // RawVec handles deallocation - let _ = unsafe { RawVec::from_raw_parts(self.0.buf.as_ptr(), self.0.cap) }; + unsafe { + // `IntoIter::alloc` is not used anymore after this + let alloc = ptr::read(&self.0.alloc); + // RawVec handles deallocation + let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); + } } } @@ -3029,11 +3283,11 @@ unsafe impl<#[may_dangle] T> Drop for IntoIter { } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for IntoIter {} +unsafe impl InPlaceIterable for IntoIter {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for IntoIter { - type Source = IntoIter; +unsafe impl SourceIter for IntoIter { + type Source = Self; #[inline] unsafe fn as_inner(&mut self) -> &mut Self::Source { @@ -3068,24 +3322,28 @@ impl AsIntoIter for IntoIter { /// let iter: std::vec::Drain<_> = v.drain(..); /// ``` #[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a, T: 'a> { +pub struct Drain< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, +> { /// Index of tail to preserve tail_start: usize, /// Length of tail tail_len: usize, /// Current remaining range to remove iter: slice::Iter<'a, T>, - vec: NonNull>, + vec: NonNull>, } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Drain<'_, T> { +impl fmt::Debug for Drain<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } -impl<'a, T> Drain<'a, T> { +impl<'a, T, A: Allocator> Drain<'a, T, A> { /// Returns the remaining items of this iterator as a slice. /// /// # Examples @@ -3101,22 +3359,29 @@ impl<'a, T> Drain<'a, T> { pub fn as_slice(&self) -> &[T] { self.iter.as_slice() } + + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + unsafe { self.vec.as_ref().allocator() } + } } #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] -impl<'a, T> AsRef<[T]> for Drain<'a, T> { +impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { fn as_ref(&self) -> &[T] { self.as_slice() } } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Sync for Drain<'_, T> {} +unsafe impl Sync for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Send for Drain<'_, T> {} +unsafe impl Send for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -impl Iterator for Drain<'_, T> { +impl Iterator for Drain<'_, T, A> { type Item = T; #[inline] @@ -3130,7 +3395,7 @@ impl Iterator for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl DoubleEndedIterator for Drain<'_, T> { +impl DoubleEndedIterator for Drain<'_, T, A> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) @@ -3138,13 +3403,13 @@ impl DoubleEndedIterator for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl Drop for Drain<'_, T> { +impl Drop for Drain<'_, T, A> { fn drop(&mut self) { /// Continues dropping the remaining elements in the `Drain`, then moves back the /// un-`Drain`ed elements to restore the original `Vec`. - struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>); + struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); - impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> { + impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { fn drop(&mut self) { // Continue the same loop we have below. If the loop already finished, this does // nothing. @@ -3180,17 +3445,17 @@ impl Drop for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, T> { +impl ExactSizeIterator for Drain<'_, T, A> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Drain<'_, T> {} +unsafe impl TrustedLen for Drain<'_, T, A> {} #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, T> {} +impl FusedIterator for Drain<'_, T, A> {} /// A splicing iterator for `Vec`. /// @@ -3206,13 +3471,17 @@ impl FusedIterator for Drain<'_, T> {} /// ``` #[derive(Debug)] #[stable(feature = "vec_splice", since = "1.21.0")] -pub struct Splice<'a, I: Iterator + 'a> { - drain: Drain<'a, I::Item>, +pub struct Splice< + 'a, + I: Iterator + 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, +> { + drain: Drain<'a, I::Item, A>, replace_with: I, } #[stable(feature = "vec_splice", since = "1.21.0")] -impl Iterator for Splice<'_, I> { +impl Iterator for Splice<'_, I, A> { type Item = I::Item; fn next(&mut self) -> Option { @@ -3225,17 +3494,17 @@ impl Iterator for Splice<'_, I> { } #[stable(feature = "vec_splice", since = "1.21.0")] -impl DoubleEndedIterator for Splice<'_, I> { +impl DoubleEndedIterator for Splice<'_, I, A> { fn next_back(&mut self) -> Option { self.drain.next_back() } } #[stable(feature = "vec_splice", since = "1.21.0")] -impl ExactSizeIterator for Splice<'_, I> {} +impl ExactSizeIterator for Splice<'_, I, A> {} #[stable(feature = "vec_splice", since = "1.21.0")] -impl Drop for Splice<'_, I> { +impl Drop for Splice<'_, I, A> { fn drop(&mut self) { self.drain.by_ref().for_each(drop); @@ -3276,7 +3545,7 @@ impl Drop for Splice<'_, I> { } /// Private helper methods for `Splice::drop` -impl Drain<'_, T> { +impl Drain<'_, T, A> { /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. /// Fill that range as much as possible with new elements from the `replace_with` iterator. @@ -3331,11 +3600,15 @@ impl Drain<'_, T> { /// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[derive(Debug)] -pub struct DrainFilter<'a, T, F> -where +pub struct DrainFilter< + 'a, + T, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> where F: FnMut(&mut T) -> bool, { - vec: &'a mut Vec, + vec: &'a mut Vec, /// The index of the item that will be inspected by the next call to `next`. idx: usize, /// The number of items that have been drained (removed) thus far. @@ -3352,8 +3625,20 @@ where panic_flag: bool, } +impl DrainFilter<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + self.vec.allocator() + } +} + #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Iterator for DrainFilter<'_, T, F> +impl Iterator for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -3391,19 +3676,19 @@ where } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Drop for DrainFilter<'_, T, F> +impl Drop for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - struct BackshiftOnDrop<'a, 'b, T, F> + struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> where F: FnMut(&mut T) -> bool, { - drain: &'b mut DrainFilter<'a, T, F>, + drain: &'b mut DrainFilter<'a, T, F, A>, } - impl<'a, 'b, T, F> Drop for BackshiftOnDrop<'a, 'b, T, F> + impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> where F: FnMut(&mut T) -> bool, { diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs index a7239a4b14..246b341eeb 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloc/tests/heap.rs @@ -1,4 +1,4 @@ -use std::alloc::{AllocRef, Global, Layout, System}; +use std::alloc::{Allocator, Global, Layout, System}; /// Issue #45955 and #62251. #[test] @@ -11,7 +11,7 @@ fn std_heap_overaligned_request() { check_overalign_requests(Global) } -fn check_overalign_requests(allocator: T) { +fn check_overalign_requests(allocator: T) { for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN` for &size in &[align / 2, align - 1] { @@ -20,7 +20,7 @@ fn check_overalign_requests(allocator: T) { unsafe { let pointers: Vec<_> = (0..iterations) .map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap() }) .collect(); for &ptr in &pointers { @@ -33,7 +33,7 @@ fn check_overalign_requests(allocator: T) { // Clean up for &ptr in &pointers { - allocator.dealloc( + allocator.deallocate( ptr.as_non_null_ptr(), Layout::from_size_align(size, align).unwrap(), ) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 834dd4656f..604835e6cc 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; -use std::str::from_utf8; +use std::str::{from_utf8, from_utf8_unchecked}; #[test] fn test_le() { @@ -1971,3 +1971,102 @@ fn test_str_escapes() { "; assert_eq!(x, r"\\"); // extraneous whitespace stripped } + +#[test] +fn const_str_ptr() { + const A: [u8; 2] = ['h' as u8, 'i' as u8]; + const B: &'static [u8; 2] = &A; + const C: *const u8 = B as *const u8; + + // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) + #[cfg(not(miri))] + { + let foo = &A as *const u8; + assert_eq!(foo, C); + } + + unsafe { + assert_eq!(from_utf8_unchecked(&A), "hi"); + assert_eq!(*C, A[0]); + assert_eq!(*(&B[0] as *const u8), A[0]); + } +} + +#[test] +fn utf8() { + let yen: char = 'Â¥'; // 0xa5 + let c_cedilla: char = 'ç'; // 0xe7 + let thorn: char = 'þ'; // 0xfe + let y_diaeresis: char = 'ÿ'; // 0xff + let pi: char = 'Π'; // 0x3a0 + + assert_eq!(yen as isize, 0xa5); + assert_eq!(c_cedilla as isize, 0xe7); + assert_eq!(thorn as isize, 0xfe); + assert_eq!(y_diaeresis as isize, 0xff); + assert_eq!(pi as isize, 0x3a0); + + assert_eq!(pi as isize, '\u{3a0}' as isize); + assert_eq!('\x0a' as isize, '\n' as isize); + + let bhutan: String = "འབྲུག་ཡུལ།".to_string(); + let japan: String = "日本".to_string(); + let uzbekistan: String = "Ўзбекистон".to_string(); + let austria: String = "Österreich".to_string(); + + let bhutan_e: String = + "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); + let japan_e: String = "\u{65e5}\u{672c}".to_string(); + let uzbekistan_e: String = + "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); + let austria_e: String = "\u{d6}sterreich".to_string(); + + let oo: char = 'Ö'; + assert_eq!(oo as isize, 0xd6); + + fn check_str_eq(a: String, b: String) { + let mut i: isize = 0; + for ab in a.bytes() { + println!("{}", i); + println!("{}", ab); + let bb: u8 = b.as_bytes()[i as usize]; + println!("{}", bb); + assert_eq!(ab, bb); + i += 1; + } + } + + check_str_eq(bhutan, bhutan_e); + check_str_eq(japan, japan_e); + check_str_eq(uzbekistan, uzbekistan_e); + check_str_eq(austria, austria_e); +} + +#[test] +fn utf8_chars() { + // Chars of 1, 2, 3, and 4 bytes + let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; + let s: String = chs.iter().cloned().collect(); + let schs: Vec = s.chars().collect(); + + assert_eq!(s.len(), 10); + assert_eq!(s.chars().count(), 4); + assert_eq!(schs.len(), 4); + assert_eq!(schs.iter().cloned().collect::(), s); + + assert!((from_utf8(s.as_bytes()).is_ok())); + // invalid prefix + assert!((!from_utf8(&[0x80]).is_ok())); + // invalid 2 byte prefix + assert!((!from_utf8(&[0xc0]).is_ok())); + assert!((!from_utf8(&[0xc0, 0x10]).is_ok())); + // invalid 3 byte prefix + assert!((!from_utf8(&[0xe0]).is_ok())); + assert!((!from_utf8(&[0xe0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); + // invalid 4 byte prefix + assert!((!from_utf8(&[0xf0]).is_ok())); + assert!((!from_utf8(&[0xf0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); +} diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 47ebe56f9f..e19406d7a0 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -919,7 +919,7 @@ fn test_from_iter_partially_drained_in_place_specialization() { #[test] fn test_from_iter_specialization_with_iterator_adapters() { - fn assert_in_place_trait(_: &T) {}; + fn assert_in_place_trait(_: &T) {} let src: Vec = vec![0usize; 256]; let srcptr = src.as_ptr(); let iter = src @@ -1198,7 +1198,7 @@ fn drain_filter_consumed_panic() { struct Check { index: usize, drop_counts: Rc>>, - }; + } impl Drop for Check { fn drop(&mut self) { @@ -1250,7 +1250,7 @@ fn drain_filter_unconsumed_panic() { struct Check { index: usize, drop_counts: Rc>>, - }; + } impl Drop for Check { fn drop(&mut self) { diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 705f0d62fb..0919b1325b 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1728,3 +1728,10 @@ fn test_zero_sized_push() { } } } + +#[test] +fn test_from_zero_sized_vec() { + let v = vec![(); 100]; + let queue = VecDeque::from(v); + assert_eq!(queue.len(), 100); +} diff --git a/library/backtrace/.github/workflows/main.yml b/library/backtrace/.github/workflows/main.yml index 948924c34f..d6e39b1c33 100644 --- a/library/backtrace/.github/workflows/main.yml +++ b/library/backtrace/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - thing: [stable, beta, nightly, macos, windows-msvc64, windows-msvc32, windows-gnu64, windows-gnu32] + thing: [stable, beta, nightly, macos, macos-nightly, windows-msvc64, windows-msvc32, windows-gnu64, windows-gnu32] include: - thing: stable os: ubuntu-latest @@ -28,6 +28,9 @@ jobs: - thing: macos os: macos-latest rust: stable + - thing: macos-nightly + os: macos-latest + rust: nightly # Note that these are on nightly due to rust-lang/rust#63700 not being # on stable yet - thing: windows-msvc64 @@ -49,10 +52,12 @@ jobs: - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash + - run: echo RUSTFLAGS=-Dwarnings >> $GITHUB_ENV + shell: bash # full fidelity of backtraces on 32-bit msvc requires frame pointers, so # enable that for our tests - name: Force frame pointers - run: echo "##[set-env name=RUSTFLAGS]-Cforce-frame-pointers" + run: echo RUSTFLAGS="-Cforce-frame-pointers $RUSTFLAGS" >> $GITHUB_ENV shell: bash if: matrix.thing == 'windows-msvc32' - run: cargo build --manifest-path crates/backtrace-sys/Cargo.toml @@ -82,6 +87,8 @@ jobs: if: contains(matrix.os, 'ubuntu') - run: RUSTFLAGS="-C link-arg=-Wl,--compress-debug-sections=zlib-gnu" cargo test --features gimli-symbolize if: contains(matrix.os, 'ubuntu') + - run: cargo clean && RUSTFLAGS="-Z run-dsymutil=no" cargo test --features gimli-symbolize + if: matrix.thing == 'macos-nightly' - run: cargo build --manifest-path crates/as-if-std/Cargo.toml windows_arm64: @@ -94,6 +101,8 @@ jobs: - name: Install Rust run: rustup update stable --no-self-update && rustup default stable shell: bash + - run: echo RUSTFLAGS=-Dwarnings >> $GITHUB_ENV + shell: bash - run: rustup target add aarch64-pc-windows-msvc - run: cargo test --no-run --target aarch64-pc-windows-msvc - run: cargo test --no-run --target aarch64-pc-windows-msvc --features verify-winapi @@ -115,12 +124,9 @@ jobs: - uses: actions/checkout@v1 with: submodules: true - - name: Install Rust ( - run: | - curl https://sh.rustup.rs | sh -s -- -y - echo "##[add-path]$HOME/.cargo/bin" - run: rustup target add ${{ matrix.target }} - run: | + export RUSTFLAGS=-Dwarnings export SDK_PATH=`xcrun --show-sdk-path --sdk ${{ matrix.sdk }}` export RUSTFLAGS="-C link-arg=-isysroot -C link-arg=$SDK_PATH" cargo test --no-run --target ${{ matrix.target }} @@ -138,6 +144,7 @@ jobs: - i586-unknown-linux-gnu - i686-unknown-linux-gnu - powerpc64-unknown-linux-gnu + - s390x-unknown-linux-gnu - x86_64-pc-windows-gnu - x86_64-unknown-linux-gnu - x86_64-unknown-linux-musl @@ -154,6 +161,8 @@ jobs: run: rustup update stable && rustup default stable - run: rustup target add ${{ matrix.target }} - run: cargo generate-lockfile + - run: echo RUSTFLAGS=-Dwarnings >> $GITHUB_ENV + shell: bash - run: ./ci/run-docker.sh ${{ matrix.target }} rustfmt: @@ -180,6 +189,8 @@ jobs: - name: Install Rust run: rustup update nightly && rustup default nightly - run: rustup target add ${{ matrix.target }} + - run: echo RUSTFLAGS=-Dwarnings >> $GITHUB_ENV + shell: bash - run: cargo build --target ${{ matrix.target }} msrv: diff --git a/library/backtrace/Cargo.toml b/library/backtrace/Cargo.toml index 5d01087240..f1b6b15d7f 100644 --- a/library/backtrace/Cargo.toml +++ b/library/backtrace/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "backtrace" -version = "0.3.53" +version = "0.3.55" authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" @@ -35,13 +35,13 @@ cpp_demangle = { default-features = false, version = "0.3.0", optional = true } # Optional dependencies enabled through the `gimli-symbolize` feature, do not # use these features directly. -addr2line = { version = "0.13.0", optional = true, default-features = false } +addr2line = { version = "0.14.0", optional = true, default-features = false } miniz_oxide = { version = "0.4.0", optional = true, default-features = false } [dependencies.object] -version = "0.21" +version = "0.22" optional = true default-features = false -features = ['read_core', 'elf', 'macho', 'pe', 'unaligned'] +features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.3", optional = true } diff --git a/library/backtrace/ci/android-sdk.sh b/library/backtrace/ci/android-sdk.sh index aee133e3a0..7fde9a97f9 100755 --- a/library/backtrace/ci/android-sdk.sh +++ b/library/backtrace/ci/android-sdk.sh @@ -1,13 +1,4 @@ #!/usr/bin/env sh -# Copyright 2016 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. set -ex diff --git a/library/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile b/library/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000..7c19dcbb48 --- /dev/null +++ b/library/backtrace/ci/docker/s390x-unknown-linux-gnu/Dockerfile @@ -0,0 +1,17 @@ +FROM ubuntu:20.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + ca-certificates \ + libc6-dev \ + gcc-s390x-linux-gnu \ + libc6-dev-s390x-cross \ + qemu-user \ + # There seems to be a bug in processing mixed-architecture + # ld.so.cache files that causes crashes in some cases. Work + # around this by simply deleting the cache for now. + && rm /etc/ld.so.cache + +ENV CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc \ + CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="qemu-s390x -L /usr/s390x-linux-gnu" \ + CC=s390x-linux-gnu-gcc diff --git a/library/backtrace/ci/run-docker.sh b/library/backtrace/ci/run-docker.sh index 5a9934b41a..8aa6d84a4d 100755 --- a/library/backtrace/ci/run-docker.sh +++ b/library/backtrace/ci/run-docker.sh @@ -18,6 +18,7 @@ run() { --volume `pwd`/target:/checkout/target \ --workdir /checkout \ --privileged \ + --env RUSTFLAGS \ backtrace \ bash \ -c 'PATH=$PATH:/rust/bin exec ci/run.sh' diff --git a/library/backtrace/crates/as-if-std/Cargo.toml b/library/backtrace/crates/as-if-std/Cargo.toml index c374e75d2f..5871a882f4 100644 --- a/library/backtrace/crates/as-if-std/Cargo.toml +++ b/library/backtrace/crates/as-if-std/Cargo.toml @@ -15,13 +15,13 @@ bench = false cfg-if = "1.0" rustc-demangle = "0.1.4" libc = { version = "0.2.45", default-features = false } -addr2line = { version = "0.13.0", default-features = false } +addr2line = { version = "0.14.0", default-features = false } miniz_oxide = { version = "0.4.0", default-features = false } [dependencies.object] -version = "0.21" +version = "0.22" default-features = false -features = ['read_core', 'elf', 'macho', 'pe', 'unaligned'] +features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] [features] default = ['gimli-symbolize'] diff --git a/library/backtrace/crates/cpp_smoke_test/tests/smoke.rs b/library/backtrace/crates/cpp_smoke_test/tests/smoke.rs index 3257c98e0b..b9aef47f50 100644 --- a/library/backtrace/crates/cpp_smoke_test/tests/smoke.rs +++ b/library/backtrace/crates/cpp_smoke_test/tests/smoke.rs @@ -9,7 +9,6 @@ extern "C" { #[test] #[ignore] // fixme(fitzgen/cpp_demangle#73) -#[cfg(not(target_os = "windows"))] fn smoke_test_cpp() { static RAN_ASSERTS: AtomicBool = AtomicBool::new(false); diff --git a/library/backtrace/crates/dylib-dep/src/lib.rs b/library/backtrace/crates/dylib-dep/src/lib.rs index 264da7bc1a..201807797f 100644 --- a/library/backtrace/crates/dylib-dep/src/lib.rs +++ b/library/backtrace/crates/dylib-dep/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(improper_ctypes_definitions)] + type Pos = (&'static str, u32); macro_rules! pos { diff --git a/library/backtrace/src/backtrace/dbghelp.rs b/library/backtrace/src/backtrace/dbghelp.rs index a4c3bc6a8f..3704d80531 100644 --- a/library/backtrace/src/backtrace/dbghelp.rs +++ b/library/backtrace/src/backtrace/dbghelp.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Backtrace strategy for MSVC platforms. //! //! This module contains the ability to generate a backtrace on MSVC using one diff --git a/library/backtrace/src/backtrace/libunwind.rs b/library/backtrace/src/backtrace/libunwind.rs index b0b5b221ed..7919eb2d1c 100644 --- a/library/backtrace/src/backtrace/libunwind.rs +++ b/library/backtrace/src/backtrace/libunwind.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Backtrace support using libunwind/gcc_s/etc APIs. //! //! This module contains the ability to unwind the stack using libunwind-style @@ -178,7 +168,8 @@ mod uw { #[cfg(all( not(all(target_os = "android", target_arch = "arm")), not(all(target_os = "freebsd", target_arch = "arm")), - not(all(target_os = "linux", target_arch = "arm")) + not(all(target_os = "linux", target_arch = "arm")), + not(all(target_os = "linux", target_arch = "s390x")) ))] // This function is a misnomer: rather than getting this frame's // Canonical Frame Address (aka the caller frame's SP) it @@ -189,6 +180,17 @@ mod uw { pub fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t; } + // s390x uses a biased CFA value, therefore we need to use + // _Unwind_GetGR to get the stack pointer register (%r15) + // instead of relying on _Unwind_GetCFA. + #[cfg(all(target_os = "linux", target_arch = "s390x"))] + pub unsafe fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t { + extern "C" { + pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, index: libc::c_int) -> libc::uintptr_t; + } + _Unwind_GetGR(ctx, 15) + } + // On android and arm, the function `_Unwind_GetIP` and a bunch of others // are macros, so we define functions containing the expansion of the // macros. diff --git a/library/backtrace/src/backtrace/mod.rs b/library/backtrace/src/backtrace/mod.rs index 2d1b88c2d2..ca1e9148e0 100644 --- a/library/backtrace/src/backtrace/mod.rs +++ b/library/backtrace/src/backtrace/mod.rs @@ -152,6 +152,7 @@ cfg_if::cfg_if! { mod dbghelp; use self::dbghelp::trace as trace_imp; pub(crate) use self::dbghelp::Frame as FrameImp; + #[cfg(target_env = "msvc")] // only used in dbghelp symbolize pub(crate) use self::dbghelp::StackFrame; } else { mod noop; diff --git a/library/backtrace/src/capture.rs b/library/backtrace/src/capture.rs index c337be4339..9bd6ce907e 100644 --- a/library/backtrace/src/capture.rs +++ b/library/backtrace/src/capture.rs @@ -472,12 +472,10 @@ mod rustc_serialize_impls { #[cfg(feature = "serde")] mod serde_impls { - extern crate serde; - - use self::serde::de::Deserializer; - use self::serde::ser::Serializer; - use self::serde::{Deserialize, Serialize}; use super::*; + use serde::de::Deserializer; + use serde::ser::Serializer; + use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct SerializedFrame { diff --git a/library/backtrace/src/lib.rs b/library/backtrace/src/lib.rs index 46c2e006b7..9d4153bb9c 100644 --- a/library/backtrace/src/lib.rs +++ b/library/backtrace/src/lib.rs @@ -52,13 +52,15 @@ // When we're building as part of libstd, silence all warnings since they're // irrelevant as this crate is developed out-of-tree. #![cfg_attr(backtrace_in_libstd, allow(warnings))] +#![cfg_attr(not(feature = "std"), allow(dead_code))] #[cfg(feature = "std")] #[macro_use] extern crate std; -// This is only used for gimli right now, so silence warnings elsewhere. -#[cfg_attr(not(target_os = "linux"), allow(unused_extern_crates))] +// This is only used for gimli right now, which is only used on some platforms, +// so don't worry if it's unused in other configurations. +#[allow(unused_extern_crates)] extern crate alloc; pub use self::backtrace::{trace_unsynchronized, Frame}; diff --git a/library/backtrace/src/print.rs b/library/backtrace/src/print.rs index e232adde98..cc677122a9 100644 --- a/library/backtrace/src/print.rs +++ b/library/backtrace/src/print.rs @@ -58,7 +58,7 @@ impl<'a, 'b> BacktraceFmt<'a, 'b> { /// Prints a preamble for the backtrace about to be printed. /// /// This is required on some platforms for backtraces to be fully - /// sumbolicated later, and otherwise this should just be the first method + /// symbolicated later, and otherwise this should just be the first method /// you call after creating a `BacktraceFmt`. pub fn add_context(&mut self) -> fmt::Result { #[cfg(target_os = "fuchsia")] @@ -99,7 +99,7 @@ pub struct BacktraceFrameFmt<'fmt, 'a, 'b> { impl BacktraceFrameFmt<'_, '_, '_> { /// Prints a `BacktraceFrame` with this frame formatter. /// - /// This will recusrively print all `BacktraceSymbol` instances within the + /// This will recursively print all `BacktraceSymbol` instances within the /// `BacktraceFrame`. /// /// # Required features diff --git a/library/backtrace/src/symbolize/dbghelp.rs b/library/backtrace/src/symbolize/dbghelp.rs index e492244137..181dba7314 100644 --- a/library/backtrace/src/symbolize/dbghelp.rs +++ b/library/backtrace/src/symbolize/dbghelp.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Symbolication strategy using `dbghelp.dll` on Windows, only used for MSVC //! //! This symbolication strategy, like with backtraces, uses dynamically loaded @@ -224,3 +214,5 @@ unsafe fn cache(filename: Option<*const [u16]>) -> Option<::std::ffi::OsString> #[cfg(not(feature = "std"))] unsafe fn cache(_filename: Option<*const [u16]>) {} + +pub unsafe fn clear_symbol_cache() {} diff --git a/library/backtrace/src/symbolize/gimli.rs b/library/backtrace/src/symbolize/gimli.rs index 19ec5da610..2330c4f0bc 100644 --- a/library/backtrace/src/symbolize/gimli.rs +++ b/library/backtrace/src/symbolize/gimli.rs @@ -1,8 +1,6 @@ //! Support for symbolication using the `gimli` crate on crates.io //! -//! This implementation is largely a work in progress and is off by default for -//! all platforms, but it's hoped to be developed over time! Long-term this is -//! intended to wholesale replace the `libbacktrace.rs` implementation. +//! This is the default symbolication implementation for Rust. use self::gimli::read::EndianSlice; use self::gimli::NativeEndian as Endian; @@ -54,11 +52,6 @@ mod stash; const MAPPINGS_CACHE_SIZE: usize = 4; -struct Context<'a> { - dwarf: addr2line::Context>, - object: Object<'a>, -} - struct Mapping { // 'static lifetime is a lie to hack around lack of support for self-referential structs. cx: Context<'static>, @@ -66,43 +59,53 @@ struct Mapping { _stash: Stash, } -fn cx<'data>(stash: &'data Stash, object: Object<'data>) -> Option> { - fn load_section<'data, S>(stash: &'data Stash, obj: &Object<'data>) -> S +impl Mapping { + fn mk(data: Mmap, mk: F) -> Option where - S: gimli::Section>, + F: for<'a> Fn(&'a [u8], &'a Stash) -> Option>, { - let data = obj.section(stash, S::section_name()).unwrap_or(&[]); - S::from(EndianSlice::new(data, Endian)) + let stash = Stash::new(); + let cx = mk(&data, &stash)?; + Some(Mapping { + // Convert to 'static lifetimes since the symbols should + // only borrow `map` and `stash` and we're preserving them below. + cx: unsafe { core::mem::transmute::, Context<'static>>(cx) }, + _map: data, + _stash: stash, + }) } +} - let dwarf = addr2line::Context::from_sections( - load_section(stash, &object), - load_section(stash, &object), - load_section(stash, &object), - load_section(stash, &object), - load_section(stash, &object), - load_section(stash, &object), - load_section(stash, &object), - load_section(stash, &object), - load_section(stash, &object), - gimli::EndianSlice::new(&[], Endian), - ) - .ok()?; - Some(Context { dwarf, object }) +struct Context<'a> { + dwarf: addr2line::Context>, + object: Object<'a>, } -macro_rules! mk { - (Mapping { $map:expr, $inner:expr, $stash:expr }) => {{ - fn assert_lifetimes<'a>(_: &'a Mmap, _: &Context<'a>, _: &'a Stash) {} - assert_lifetimes(&$map, &$inner, &$stash); - Mapping { - // Convert to 'static lifetimes since the symbols should - // only borrow `map` and `stash` and we're preserving them below. - cx: unsafe { core::mem::transmute::, Context<'static>>($inner) }, - _map: $map, - _stash: $stash, +impl<'data> Context<'data> { + fn new(stash: &'data Stash, object: Object<'data>) -> Option> { + fn load_section<'data, S>(stash: &'data Stash, obj: &Object<'data>) -> S + where + S: gimli::Section>, + { + let data = obj.section(stash, S::section_name()).unwrap_or(&[]); + S::from(EndianSlice::new(data, Endian)) } - }}; + + let dwarf = addr2line::Context::from_sections( + load_section(stash, &object), + load_section(stash, &object), + load_section(stash, &object), + load_section(stash, &object), + load_section(stash, &object), + load_section(stash, &object), + load_section(stash, &object), + load_section(stash, &object), + load_section(stash, &object), + gimli::EndianSlice::new(&[], Endian), + ) + .ok()?; + Some(Context { dwarf, object }) + } } fn mmap(path: &Path) -> Option { @@ -208,7 +211,7 @@ cfg_if::cfg_if! { target_os = "watchos", ))] { // macOS uses the Mach-O file format and uses DYLD-specific APIs to - // load a list of native libraries that are part of the appplication. + // load a list of native libraries that are part of the application. use mystd::os::unix::prelude::*; use mystd::ffi::{OsStr, CStr}; @@ -372,28 +375,32 @@ cfg_if::cfg_if! { fn native_libraries() -> Vec { let mut ret = Vec::new(); unsafe { - libc::dl_iterate_phdr(Some(callback), &mut ret as *mut _ as *mut _); + libc::dl_iterate_phdr(Some(callback), &mut ret as *mut Vec<_> as *mut _); } return ret; } + // `info` should be a valid pointers. + // `vec` should be a valid pointer to a `std::Vec`. unsafe extern "C" fn callback( info: *mut libc::dl_phdr_info, _size: libc::size_t, vec: *mut libc::c_void, ) -> libc::c_int { + let info = &*info; let libs = &mut *(vec as *mut Vec); - let name = if (*info).dlpi_name.is_null() || *(*info).dlpi_name == 0{ + let is_main_prog = info.dlpi_name.is_null() || *info.dlpi_name == 0; + let name = if is_main_prog { if libs.is_empty() { mystd::env::current_exe().map(|e| e.into()).unwrap_or_default() } else { OsString::new() } } else { - let bytes = CStr::from_ptr((*info).dlpi_name).to_bytes(); + let bytes = CStr::from_ptr(info.dlpi_name).to_bytes(); OsStr::from_bytes(bytes).to_owned() }; - let headers = core::slice::from_raw_parts((*info).dlpi_phdr, (*info).dlpi_phnum as usize); + let headers = core::slice::from_raw_parts(info.dlpi_phdr, info.dlpi_phnum as usize); libs.push(Library { name, segments: headers @@ -403,7 +410,7 @@ cfg_if::cfg_if! { stated_virtual_memory_address: (*header).p_vaddr as usize, }) .collect(), - bias: (*info).dlpi_addr as usize, + bias: info.dlpi_addr as usize, }); 0 } @@ -552,7 +559,7 @@ impl Cache { .next() } - fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<&'a Context<'a>> { + fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<&'a mut Context<'a>> { let idx = self.mappings.iter().position(|(idx, _)| *idx == lib); // Invariant: after this conditional completes without early returning @@ -578,10 +585,10 @@ impl Cache { self.mappings.insert(0, (lib, mapping)); } - let cx: &'a Context<'static> = &self.mappings[0].1.cx; + let cx: &'a mut Context<'static> = &mut self.mappings[0].1.cx; // don't leak the `'static` lifetime, make sure it's scoped to just // ourselves - Some(unsafe { mem::transmute::<&'a Context<'static>, &'a Context<'a>>(cx) }) + Some(unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) }) } } @@ -618,7 +625,20 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) }); } } - + if !any_frames { + if let Some((object_cx, object_addr)) = cx.object.search_object_map(addr as u64) { + if let Ok(mut frames) = object_cx.dwarf.find_frames(object_addr) { + while let Ok(Some(frame)) = frames.next() { + any_frames = true; + call(Symbol::Frame { + addr: addr as *mut c_void, + location: frame.location, + name: frame.function.map(|f| f.name.slice()), + }); + } + } + } + } if !any_frames { if let Some(name) = cx.object.search_symtab(addr as u64) { call(Symbol::Symtab { diff --git a/library/backtrace/src/symbolize/gimli/coff.rs b/library/backtrace/src/symbolize/gimli/coff.rs index 5d6c8fae95..8a6995e13b 100644 --- a/library/backtrace/src/symbolize/gimli/coff.rs +++ b/library/backtrace/src/symbolize/gimli/coff.rs @@ -1,4 +1,4 @@ -use super::{Context, Mapping, Mmap, Path, Stash, Vec}; +use super::{Context, Mapping, Path, Stash, Vec}; use core::convert::TryFrom; use object::pe::{ImageDosHeader, ImageSymbol}; use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable}; @@ -13,9 +13,7 @@ type Pe = object::pe::ImageNtHeaders64; impl Mapping { pub fn new(path: &Path) -> Option { let map = super::mmap(path)?; - let stash = Stash::new(); - let cx = super::cx(&stash, Object::parse(&map)?)?; - Some(mk!(Mapping { map, cx, stash })) + Mapping::mk(map, |data, stash| Context::new(stash, Object::parse(data)?)) } } @@ -52,7 +50,7 @@ impl<'a> Object<'a> { let mut i = 0; let len = symtab.len(); while i < len { - let sym = symtab.symbol(i)?; + let sym = symtab.symbol(i).ok()?; i += 1 + sym.number_of_aux_symbols as usize; let section_number = sym.section_number.get(LE); if sym.derived_type() != object::pe::IMAGE_SYM_DTYPE_FUNCTION || section_number == 0 { @@ -102,4 +100,8 @@ impl<'a> Object<'a> { }; self.symbols[i].1.name(self.strings).ok() } + + pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> { + None + } } diff --git a/library/backtrace/src/symbolize/gimli/elf.rs b/library/backtrace/src/symbolize/gimli/elf.rs index 2ca57f88a4..41a30fe60a 100644 --- a/library/backtrace/src/symbolize/gimli/elf.rs +++ b/library/backtrace/src/symbolize/gimli/elf.rs @@ -1,4 +1,4 @@ -use super::{Context, Mapping, Mmap, Path, Stash, Vec}; +use super::{Context, Mapping, Path, Stash, Vec}; use core::convert::TryFrom; use object::elf::{ELFCOMPRESS_ZLIB, SHF_COMPRESSED}; use object::read::elf::{CompressionHeader, FileHeader, SectionHeader, SectionTable, Sym}; @@ -13,9 +13,7 @@ type Elf = object::elf::FileHeader64; impl Mapping { pub fn new(path: &Path) -> Option { let map = super::mmap(path)?; - let stash = Stash::new(); - let cx = super::cx(&stash, Object::parse(&map)?)?; - Some(mk!(Mapping { map, cx, stash })) + Mapping::mk(map, |data, stash| Context::new(stash, Object::parse(data)?)) } } @@ -162,6 +160,10 @@ impl<'a> Object<'a> { None } } + + pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> { + None + } } fn decompress_zlib(input: &[u8], output: &mut [u8]) -> Option<()> { diff --git a/library/backtrace/src/symbolize/gimli/macho.rs b/library/backtrace/src/symbolize/gimli/macho.rs index 6616f272e1..4b96bf16cc 100644 --- a/library/backtrace/src/symbolize/gimli/macho.rs +++ b/library/backtrace/src/symbolize/gimli/macho.rs @@ -1,4 +1,4 @@ -use super::{Context, Mapping, Mmap, Path, Stash, Vec}; +use super::{Box, Context, Mapping, Path, Stash, Vec}; use core::convert::TryInto; use object::macho; use object::read::macho::{MachHeader, Nlist, Section, Segment as _}; @@ -30,8 +30,25 @@ impl Mapping { // contains and try to find a macho file which has a matching UUID as // the one of our own file. If we find a match that's the dwarf file we // want to return. - let parent = path.parent()?; - for entry in parent.read_dir().ok()? { + if let Some(parent) = path.parent() { + if let Some(mapping) = Mapping::load_dsym(parent, uuid) { + return Some(mapping); + } + } + + // Looks like nothing matched our UUID, so let's at least return our own + // file. This should have the symbol table for at least some + // symbolication purposes. + Mapping::mk(map, |data, stash| { + let (macho, data) = find_header(Bytes(data))?; + let endian = macho.endian().ok()?; + let obj = Object::parse(macho, endian, data)?; + Context::new(stash, obj) + }) + } + + fn load_dsym(dir: &Path, uuid: [u8; 16]) -> Option { + for entry in dir.read_dir().ok()? { let entry = entry.ok()?; let filename = match entry.file_name().into_string() { Ok(name) => name, @@ -41,38 +58,36 @@ impl Mapping { continue; } let candidates = entry.path().join("Contents/Resources/DWARF"); - if let Some(mapping) = load_dsym(&candidates, uuid) { + if let Some(mapping) = Mapping::try_dsym_candidate(&candidates, uuid) { return Some(mapping); } } + None + } - // Looks like nothing matched our UUID, so let's at least return our own - // file. This should have the symbol table for at least some - // symbolication purposes. - let stash = Stash::new(); - let inner = super::cx(&stash, Object::parse(macho, endian, data)?)?; - return Some(mk!(Mapping { map, inner, stash })); - - fn load_dsym(dir: &Path, uuid: [u8; 16]) -> Option { - for entry in dir.read_dir().ok()? { - let entry = entry.ok()?; - let map = super::mmap(&entry.path())?; - let (macho, data) = find_header(Bytes(&map))?; + fn try_dsym_candidate(dir: &Path, uuid: [u8; 16]) -> Option { + // Look for files in the `DWARF` directory which have a matching uuid to + // the original object file. If we find one then we found the debug + // information. + for entry in dir.read_dir().ok()? { + let entry = entry.ok()?; + let map = super::mmap(&entry.path())?; + let candidate = Mapping::mk(map, |data, stash| { + let (macho, data) = find_header(Bytes(data))?; let endian = macho.endian().ok()?; let entry_uuid = macho.uuid(endian, data).ok()??; if entry_uuid != uuid { - continue; - } - let stash = Stash::new(); - if let Some(cx) = - Object::parse(macho, endian, data).and_then(|o| super::cx(&stash, o)) - { - return Some(mk!(Mapping { map, cx, stash })); + return None; } + let obj = Object::parse(macho, endian, data)?; + Context::new(stash, obj) + }); + if let Some(candidate) = candidate { + return Some(candidate); } - - None } + + None } } @@ -137,21 +152,32 @@ fn find_header(mut data: Bytes<'_>) -> Option<(&'_ Mach, Bytes<'_>)> { Mach::parse(data).ok().map(|h| (h, data)) } +// This is used both for executables/libraries and source object files. pub struct Object<'a> { endian: NativeEndian, data: Bytes<'a>, dwarf: Option<&'a [MachSection]>, syms: Vec<(&'a [u8], u64)>, + syms_sort_by_name: bool, + // Only set for executables/libraries, and not the source object files. + object_map: Option>, + // The outer Option is for lazy loading, and the inner Option allows load errors to be cached. + object_mappings: Box<[Option>]>, } impl<'a> Object<'a> { fn parse(mach: &'a Mach, endian: NativeEndian, data: Bytes<'a>) -> Option> { + let is_object = mach.filetype(endian) == object::macho::MH_OBJECT; let mut dwarf = None; let mut syms = Vec::new(); + let mut syms_sort_by_name = false; let mut commands = mach.load_commands(endian, data).ok()?; + let mut object_map = None; + let mut object_mappings = Vec::new(); while let Ok(Some(command)) = commands.next() { if let Some((segment, section_data)) = MachSegment::from_command(command).ok()? { - if segment.name() == b"__DWARF" { + // Object files should have all sections in a single unnamed segment load command. + if segment.name() == b"__DWARF" || (is_object && segment.name() == b"") { dwarf = segment.sections(endian, section_data).ok(); } } else if let Some(symtab) = command.symtab().ok()? { @@ -160,14 +186,25 @@ impl<'a> Object<'a> { .iter() .filter_map(|nlist: &MachNlist| { let name = nlist.name(endian, symbols.strings()).ok()?; - if name.len() > 0 && !nlist.is_undefined() { + if name.len() > 0 && nlist.is_definition() { Some((name, u64::from(nlist.n_value(endian)))) } else { None } }) .collect(); - syms.sort_unstable_by_key(|(_, addr)| *addr); + if is_object { + // We never search object file symbols by address. + // Instead, we already know the symbol name from the executable, and we + // need to search by name to find the matching symbol in the object file. + syms.sort_unstable_by_key(|(name, _)| *name); + syms_sort_by_name = true; + } else { + syms.sort_unstable_by_key(|(_, addr)| *addr); + let map = symbols.object_map(endian); + object_mappings.resize_with(map.objects().len(), || None); + object_map = Some(map); + } } } @@ -176,6 +213,9 @@ impl<'a> Object<'a> { data, dwarf, syms, + syms_sort_by_name, + object_map, + object_mappings: object_mappings.into_boxed_slice(), }) } @@ -194,6 +234,7 @@ impl<'a> Object<'a> { } pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> { + debug_assert!(!self.syms_sort_by_name); let i = match self.syms.binary_search_by_key(&addr, |(_, addr)| *addr) { Ok(i) => i, Err(i) => i.checked_sub(1)?, @@ -201,4 +242,80 @@ impl<'a> Object<'a> { let (sym, _addr) = self.syms.get(i)?; Some(sym) } + + /// Try to load a context for an object file. + /// + /// If dsymutil was not run, then the DWARF may be found in the source object files. + pub(super) fn search_object_map<'b>(&'b mut self, addr: u64) -> Option<(&Context<'b>, u64)> { + // `object_map` contains a map from addresses to symbols and object paths. + // Look up the address and get a mapping for the object. + let object_map = self.object_map.as_ref()?; + let symbol = object_map.get(addr)?; + let object_index = symbol.object_index(); + let mapping = self.object_mappings.get_mut(object_index)?; + if mapping.is_none() { + // No cached mapping, so create it. + *mapping = Some(object_mapping(object_map.objects().get(object_index)?)); + } + let cx: &'b Context<'static> = &mapping.as_ref()?.as_ref()?.cx; + // Don't leak the `'static` lifetime, make sure it's scoped to just ourselves. + let cx = unsafe { core::mem::transmute::<&'b Context<'static>, &'b Context<'b>>(cx) }; + + // We must translate the address in order to be able to look it up + // in the DWARF in the object file. + debug_assert!(cx.object.syms.is_empty() || cx.object.syms_sort_by_name); + let i = cx + .object + .syms + .binary_search_by_key(&symbol.name(), |(name, _)| *name) + .ok()?; + let object_symbol = cx.object.syms.get(i)?; + let object_addr = addr + .wrapping_sub(symbol.address()) + .wrapping_add(object_symbol.1); + Some((cx, object_addr)) + } +} + +fn object_mapping(path: &[u8]) -> Option { + use super::mystd::ffi::OsStr; + use super::mystd::os::unix::prelude::*; + + let map; + + // `N_OSO` symbol names can be either `/path/to/object.o` or `/path/to/archive.a(object.o)`. + let member_name = if let Some((archive_path, member_name)) = split_archive_path(path) { + map = super::mmap(Path::new(OsStr::from_bytes(archive_path)))?; + Some(member_name) + } else { + map = super::mmap(Path::new(OsStr::from_bytes(path)))?; + None + }; + Mapping::mk(map, |data, stash| { + let data = match member_name { + Some(member_name) => { + let archive = object::read::archive::ArchiveFile::parse(data).ok()?; + let member = archive + .members() + .filter_map(Result::ok) + .find(|m| m.name() == member_name)?; + Bytes(member.data()) + } + None => Bytes(data), + }; + let (macho, data) = find_header(data)?; + let endian = macho.endian().ok()?; + let obj = Object::parse(macho, endian, data)?; + Context::new(stash, obj) + }) +} + +fn split_archive_path(path: &[u8]) -> Option<(&[u8], &[u8])> { + let (last, path) = path.split_last()?; + if *last != b')' { + return None; + } + let index = path.iter().position(|&x| x == b'(')?; + let (archive, rest) = path.split_at(index); + Some((archive, &rest[1..])) } diff --git a/library/backtrace/src/symbolize/libbacktrace.rs b/library/backtrace/src/symbolize/libbacktrace.rs index d155b7dc38..665733605c 100644 --- a/library/backtrace/src/symbolize/libbacktrace.rs +++ b/library/backtrace/src/symbolize/libbacktrace.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Symbolication strategy using the DWARF-parsing code in libbacktrace. //! //! The libbacktrace C library, typically distributed with gcc, supports not @@ -466,3 +456,5 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) &mut syminfo_state as *mut _ as *mut _, ); } + +pub unsafe fn clear_symbol_cache() {} diff --git a/library/backtrace/src/symbolize/miri.rs b/library/backtrace/src/symbolize/miri.rs index 8e2e163968..5b0dc3084b 100644 --- a/library/backtrace/src/symbolize/miri.rs +++ b/library/backtrace/src/symbolize/miri.rs @@ -52,3 +52,5 @@ impl<'a> Symbol<'a> { )) } } + +pub unsafe fn clear_symbol_cache() {} diff --git a/library/backtrace/src/symbolize/mod.rs b/library/backtrace/src/symbolize/mod.rs index c051ec8f5d..961c63d995 100644 --- a/library/backtrace/src/symbolize/mod.rs +++ b/library/backtrace/src/symbolize/mod.rs @@ -159,7 +159,7 @@ pub unsafe fn resolve_unsynchronized(addr: *mut c_void, mut cb: F) where F: FnMut(&Symbol), { - resolve_imp(ResolveWhat::Address(addr), &mut cb) + imp::resolve(ResolveWhat::Address(addr), &mut cb) } /// Same as `resolve_frame`, only unsafe as it's unsynchronized. @@ -175,7 +175,7 @@ pub unsafe fn resolve_frame_unsynchronized(frame: &Frame, mut cb: F) where F: FnMut(&Symbol), { - resolve_imp(ResolveWhat::Frame(frame), &mut cb) + imp::resolve(ResolveWhat::Frame(frame), &mut cb) } /// A trait representing the resolution of a symbol in a file. @@ -191,7 +191,7 @@ pub struct Symbol { // TODO: this lifetime bound needs to be persisted eventually to `Symbol`, // but that's currently a breaking change. For now this is safe since // `Symbol` is only ever handed out by reference and can't be cloned. - inner: SymbolImp<'static>, + inner: imp::Symbol<'static>, } impl Symbol { @@ -383,7 +383,7 @@ fn format_symbol_name( cfg_if::cfg_if! { if #[cfg(feature = "cpp_demangle")] { impl<'a> fmt::Display for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(ref s) = self.demangled { s.fmt(f) } else if let Some(ref cpp) = self.cpp_demangled.0 { @@ -409,7 +409,7 @@ cfg_if::cfg_if! { cfg_if::cfg_if! { if #[cfg(all(feature = "std", feature = "cpp_demangle"))] { impl<'a> fmt::Debug for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use std::fmt::Write; if let Some(ref s) = self.demangled { @@ -459,21 +459,17 @@ cfg_if::cfg_if! { pub fn clear_symbol_cache() { let _guard = crate::lock::lock(); unsafe { - clear_symbol_cache_imp(); + imp::clear_symbol_cache(); } } cfg_if::cfg_if! { if #[cfg(miri)] { mod miri; - use self::miri::resolve as resolve_imp; - use self::miri::Symbol as SymbolImp; - unsafe fn clear_symbol_cache_imp() {} + use miri as imp; } else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] { mod dbghelp; - use self::dbghelp::resolve as resolve_imp; - use self::dbghelp::Symbol as SymbolImp; - unsafe fn clear_symbol_cache_imp() {} + use dbghelp as imp; } else if #[cfg(all( feature = "libbacktrace", any(unix, all(windows, not(target_vendor = "uwp"), target_env = "gnu")), @@ -483,9 +479,7 @@ cfg_if::cfg_if! { not(target_env = "libnx"), ))] { mod libbacktrace; - use self::libbacktrace::resolve as resolve_imp; - use self::libbacktrace::Symbol as SymbolImp; - unsafe fn clear_symbol_cache_imp() {} + use libbacktrace as imp; } else if #[cfg(all( feature = "gimli-symbolize", any(unix, windows), @@ -493,14 +487,9 @@ cfg_if::cfg_if! { not(target_os = "emscripten"), ))] { mod gimli; - use self::gimli::resolve as resolve_imp; - use self::gimli::Symbol as SymbolImp; - use self::gimli::clear_symbol_cache as clear_symbol_cache_imp; + use gimli as imp; } else { mod noop; - use self::noop::resolve as resolve_imp; - use self::noop::Symbol as SymbolImp; - #[allow(unused)] - unsafe fn clear_symbol_cache_imp() {} + use noop as imp; } } diff --git a/library/backtrace/src/symbolize/noop.rs b/library/backtrace/src/symbolize/noop.rs index 9a285a1bf9..c53336531b 100644 --- a/library/backtrace/src/symbolize/noop.rs +++ b/library/backtrace/src/symbolize/noop.rs @@ -37,3 +37,5 @@ impl Symbol<'_> { None } } + +pub unsafe fn clear_symbol_cache() {} diff --git a/library/backtrace/tests/concurrent-panics.rs b/library/backtrace/tests/concurrent-panics.rs index 0db0fdd574..470245cc96 100644 --- a/library/backtrace/tests/concurrent-panics.rs +++ b/library/backtrace/tests/concurrent-panics.rs @@ -14,7 +14,12 @@ fn main() { // so just skip these for CI. No other reason this can't run on those // platforms though. // Miri does not have support for re-execing a file - if cfg!(unix) && (cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64")) || cfg!(miri) { + if cfg!(unix) + && (cfg!(target_arch = "arm") + || cfg!(target_arch = "aarch64") + || cfg!(target_arch = "s390x")) + || cfg!(miri) + { println!("test result: ok"); return; } diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index a3fbed2ec1..997c1a16cc 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -19,7 +19,7 @@ const fn size_align() -> (usize, usize) { /// even though `GlobalAlloc` requires that all memory requests /// be non-zero in size. A caller must either ensure that conditions /// like this are met, use specific allocators with looser -/// requirements, or use the more lenient `AllocRef` interface.) +/// requirements, or use the more lenient `Allocator` interface.) #[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[lang = "alloc_layout"] @@ -39,7 +39,7 @@ pub struct Layout { impl Layout { /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `LayoutErr` if any of the following conditions + /// or returns `LayoutError` if any of the following conditions /// are not met: /// /// * `align` must not be zero, @@ -50,11 +50,11 @@ impl Layout { /// must not overflow (i.e., the rounded value must be less than /// or equal to `usize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")] #[inline] - pub const fn from_size_align(size: usize, align: usize) -> Result { + pub const fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { - return Err(LayoutErr { private: () }); + return Err(LayoutError { private: () }); } // (power-of-two implies align != 0.) @@ -72,7 +72,7 @@ impl Layout { // Above implies that checking for summation overflow is both // necessary and sufficient. if size > usize::MAX - (align - 1) { - return Err(LayoutErr { private: () }); + return Err(LayoutError { private: () }); } // SAFETY: the conditions for `from_size_align_unchecked` have been @@ -96,7 +96,7 @@ impl Layout { /// The minimum size in bytes for a memory block of this layout. #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")] #[inline] pub const fn size(&self) -> usize { self.size_ @@ -104,7 +104,7 @@ impl Layout { /// The minimum byte alignment for a memory block of this layout. #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")] #[inline] pub const fn align(&self) -> usize { self.align_.get() @@ -200,7 +200,7 @@ impl Layout { /// `align` violates the conditions listed in [`Layout::from_size_align`]. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] - pub fn align_to(&self, align: usize) -> Result { + pub fn align_to(&self, align: usize) -> Result { Layout::from_size_align(self.size(), cmp::max(self.align(), align)) } @@ -274,16 +274,16 @@ impl Layout { /// layout of the array and `offs` is the distance between the start /// of each element in the array. /// - /// On arithmetic overflow, returns `LayoutErr`. + /// On arithmetic overflow, returns `LayoutError`. #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] - pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { + pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, // > must not overflow (i.e., the rounded value must be less than // > `usize::MAX`) let padded_size = self.size() + self.padding_needed_for(self.align()); - let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?; + let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError { private: () })?; // SAFETY: self.align is already known to be valid and alloc_size has been // padded already. @@ -307,7 +307,7 @@ impl Layout { /// start of the `next` embedded within the concatenated record /// (assuming that the record itself starts at offset 0). /// - /// On arithmetic overflow, returns `LayoutErr`. + /// On arithmetic overflow, returns `LayoutError`. /// /// # Examples /// @@ -315,8 +315,8 @@ impl Layout { /// the fields from its fields' layouts: /// /// ```rust - /// # use std::alloc::{Layout, LayoutErr}; - /// pub fn repr_c(fields: &[Layout]) -> Result<(Layout, Vec), LayoutErr> { + /// # use std::alloc::{Layout, LayoutError}; + /// pub fn repr_c(fields: &[Layout]) -> Result<(Layout, Vec), LayoutError> { /// let mut offsets = Vec::new(); /// let mut layout = Layout::from_size_align(0, 1)?; /// for &field in fields { @@ -337,12 +337,12 @@ impl Layout { /// ``` #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] - pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { + pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { let new_align = cmp::max(self.align(), next.align()); let pad = self.padding_needed_for(next.align()); - let offset = self.size().checked_add(pad).ok_or(LayoutErr { private: () })?; - let new_size = offset.checked_add(next.size()).ok_or(LayoutErr { private: () })?; + let offset = self.size().checked_add(pad).ok_or(LayoutError { private: () })?; + let new_size = offset.checked_add(next.size()).ok_or(LayoutError { private: () })?; let layout = Layout::from_size_align(new_size, new_align)?; Ok((layout, offset)) @@ -359,11 +359,11 @@ impl Layout { /// guaranteed that all elements in the array will be properly /// aligned. /// - /// On arithmetic overflow, returns `LayoutErr`. + /// On arithmetic overflow, returns `LayoutError`. #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] - pub fn repeat_packed(&self, n: usize) -> Result { - let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; + pub fn repeat_packed(&self, n: usize) -> Result { + let size = self.size().checked_mul(n).ok_or(LayoutError { private: () })?; Layout::from_size_align(size, self.align()) } @@ -372,38 +372,46 @@ impl Layout { /// padding is inserted, the alignment of `next` is irrelevant, /// and is not incorporated *at all* into the resulting layout. /// - /// On arithmetic overflow, returns `LayoutErr`. + /// On arithmetic overflow, returns `LayoutError`. #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] - pub fn extend_packed(&self, next: Self) -> Result { - let new_size = self.size().checked_add(next.size()).ok_or(LayoutErr { private: () })?; + pub fn extend_packed(&self, next: Self) -> Result { + let new_size = self.size().checked_add(next.size()).ok_or(LayoutError { private: () })?; Layout::from_size_align(new_size, self.align()) } /// Creates a layout describing the record for a `[T; n]`. /// - /// On arithmetic overflow, returns `LayoutErr`. + /// On arithmetic overflow, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] - pub fn array(n: usize) -> Result { + pub fn array(n: usize) -> Result { let (layout, offset) = Layout::new::().repeat(n)?; debug_assert_eq!(offset, mem::size_of::()); Ok(layout.pad_to_align()) } } +#[stable(feature = "alloc_layout", since = "1.28.0")] +#[rustc_deprecated( + since = "1.52.0", + reason = "Name does not follow std convention, use LayoutError", + suggestion = "LayoutError" +)] +pub type LayoutErr = LayoutError; + /// The parameters given to `Layout::from_size_align` /// or some other `Layout` constructor /// do not satisfy its documented constraints. -#[stable(feature = "alloc_layout", since = "1.28.0")] +#[stable(feature = "alloc_layout_error", since = "1.50.0")] #[derive(Clone, PartialEq, Eq, Debug)] -pub struct LayoutErr { +pub struct LayoutError { private: (), } // (we need this for downstream impl of trait Error) #[stable(feature = "alloc_layout", since = "1.28.0")] -impl fmt::Display for LayoutErr { +impl fmt::Display for LayoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("invalid parameters to Layout::from_size_align") } diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index c61c19cc7d..c1c993bbc5 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -8,7 +8,18 @@ mod layout; #[stable(feature = "global_alloc", since = "1.28.0")] pub use self::global::GlobalAlloc; #[stable(feature = "alloc_layout", since = "1.28.0")] -pub use self::layout::{Layout, LayoutErr}; +pub use self::layout::Layout; +#[stable(feature = "alloc_layout", since = "1.28.0")] +#[rustc_deprecated( + since = "1.52.0", + reason = "Name does not follow std convention, use LayoutError", + suggestion = "LayoutError" +)] +#[allow(deprecated, deprecated_in_future)] +pub use self::layout::LayoutErr; + +#[stable(feature = "alloc_layout_error", since = "1.50.0")] +pub use self::layout::LayoutError; use crate::fmt; use crate::ptr::{self, NonNull}; @@ -29,14 +40,14 @@ impl fmt::Display for AllocError { } } -/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of +/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of /// data described via [`Layout`][]. /// -/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having +/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having /// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the /// allocated memory. /// -/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying +/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying /// allocator does not support this (like jemalloc) or return a null pointer (such as /// `libc::malloc`), this must be caught by the implementation. /// @@ -45,18 +56,18 @@ impl fmt::Display for AllocError { /// Some of the methods require that a memory block be *currently allocated* via an allocator. This /// means that: /// -/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or +/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or /// [`shrink`], and /// /// * the memory block has not been subsequently deallocated, where blocks are either deallocated -/// directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or +/// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or /// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer /// remains valid. /// -/// [`alloc`]: AllocRef::alloc -/// [`grow`]: AllocRef::grow -/// [`shrink`]: AllocRef::shrink -/// [`dealloc`]: AllocRef::dealloc +/// [`allocate`]: Allocator::allocate +/// [`grow`]: Allocator::grow +/// [`shrink`]: Allocator::shrink +/// [`deallocate`]: Allocator::deallocate /// /// ### Memory fitting /// @@ -68,7 +79,7 @@ impl fmt::Display for AllocError { /// /// * The provided [`layout.size()`] must fall in the range `min ..= max`, where: /// - `min` is the size of the layout most recently used to allocate the block, and -/// - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`]. +/// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`]. /// /// [`layout.align()`]: Layout::align /// [`layout.size()`]: Layout::size @@ -86,7 +97,7 @@ impl fmt::Display for AllocError { /// /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] -pub unsafe trait AllocRef { +pub unsafe trait Allocator { /// Attempts to allocate a block of memory. /// /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. @@ -107,9 +118,9 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc(&self, layout: Layout) -> Result, AllocError>; + fn allocate(&self, layout: Layout) -> Result, AllocError>; - /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized. + /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized. /// /// # Errors /// @@ -124,8 +135,8 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { - let ptr = self.alloc(layout)?; + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + let ptr = self.allocate(layout)?; // SAFETY: `alloc` returns a valid memory block unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) } Ok(ptr) @@ -140,7 +151,7 @@ pub unsafe trait AllocRef { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout); + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); /// Attempts to extend the memory block. /// @@ -189,7 +200,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; // SAFETY: because `new_layout.size()` must be greater than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -198,7 +209,7 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) @@ -250,7 +261,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc_zeroed(new_layout)?; + let new_ptr = self.allocate_zeroed(new_layout)?; // SAFETY: because `new_layout.size()` must be greater than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -259,7 +270,7 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) @@ -312,7 +323,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; // SAFETY: because `new_layout.size()` must be lower than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -321,15 +332,15 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) } - /// Creates a "by reference" adaptor for this instance of `AllocRef`. + /// Creates a "by reference" adaptor for this instance of `Allocator`. /// - /// The returned adaptor also implements `AllocRef` and will simply borrow this. + /// The returned adaptor also implements `Allocator` and will simply borrow this. #[inline(always)] fn by_ref(&self) -> &Self { self @@ -337,24 +348,24 @@ pub unsafe trait AllocRef { } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for &A +unsafe impl Allocator for &A where - A: AllocRef + ?Sized, + A: Allocator + ?Sized, { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { - (**self).alloc(layout) + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { - (**self).alloc_zeroed(layout) + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).dealloc(ptr, layout) } + unsafe { (**self).deallocate(ptr, layout) } } #[inline] diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index cafb002c01..706f865b4d 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -69,7 +69,8 @@ impl IntoIter { /// Returns an immutable slice of all elements that have not been yielded /// yet. - fn as_slice(&self) -> &[T] { + #[unstable(feature = "array_value_iter_slice", issue = "65798")] + pub fn as_slice(&self) -> &[T] { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked(self.alive.clone()); @@ -78,7 +79,8 @@ impl IntoIter { } /// Returns a mutable slice of all elements that have not been yielded yet. - fn as_mut_slice(&mut self) -> &mut [T] { + #[unstable(feature = "array_value_iter_slice", issue = "65798")] + pub fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked_mut(self.alive.clone()); diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 123a191dd2..71548bec7a 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -12,6 +12,7 @@ use crate::convert::{Infallible, TryFrom}; use crate::fmt; use crate::hash::{self, Hash}; use crate::marker::Unsize; +use crate::ops::{Index, IndexMut}; use crate::slice::{Iter, IterMut}; mod iter; @@ -208,6 +209,30 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] { } } +#[stable(feature = "index_trait_on_arrays", since = "1.50.0")] +impl Index for [T; N] +where + [T]: Index, +{ + type Output = <[T] as Index>::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + Index::index(self as &[T], index) + } +} + +#[stable(feature = "index_trait_on_arrays", since = "1.50.0")] +impl IndexMut for [T; N] +where + [T]: IndexMut, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + IndexMut::index_mut(self as &mut [T], index) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[B; N]> for [A; N] where @@ -254,22 +279,22 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N] +impl PartialEq<&[B]> for [A; N] where A: PartialEq, { #[inline] - fn eq(&self, other: &&'b [B]) -> bool { + fn eq(&self, other: &&[B]) -> bool { self[..] == other[..] } #[inline] - fn ne(&self, other: &&'b [B]) -> bool { + fn ne(&self, other: &&[B]) -> bool { self[..] != other[..] } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B] +impl PartialEq<[A; N]> for &[B] where B: PartialEq, { @@ -284,22 +309,22 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N] +impl PartialEq<&mut [B]> for [A; N] where A: PartialEq, { #[inline] - fn eq(&self, other: &&'b mut [B]) -> bool { + fn eq(&self, other: &&mut [B]) -> bool { self[..] == other[..] } #[inline] - fn ne(&self, other: &&'b mut [B]) -> bool { + fn ne(&self, other: &&mut [B]) -> bool { self[..] != other[..] } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B] +impl PartialEq<[A; N]> for &mut [B] where B: PartialEq, { @@ -438,6 +463,37 @@ impl [T; N] { unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } } + /// 'Zips up' two arrays into a single array of pairs. + /// + /// `zip()` returns a new array where every element is a tuple where the + /// first element comes from the first array, and the second element comes + /// from the second array. In other words, it zips two arrays together, + /// into a single one. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_zip)] + /// let x = [1, 2, 3]; + /// let y = [4, 5, 6]; + /// let z = x.zip(y); + /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); + /// ``` + #[unstable(feature = "array_zip", issue = "80094")] + pub fn zip(self, rhs: [U; N]) -> [(T, U); N] { + use crate::mem::MaybeUninit; + + let mut dst = MaybeUninit::uninit_array::(); + for (i, (lhs, rhs)) in IntoIter::new(self).zip(IntoIter::new(rhs)).enumerate() { + dst[i].write((lhs, rhs)); + } + // FIXME: Convert to crate::mem::transmute once it works with generics. + // unsafe { crate::mem::transmute::<[MaybeUninit; N], [U; N]>(dst) } + // SAFETY: At this point we've properly initialized the whole array + // and we just need to cast it to the correct type. + unsafe { crate::mem::transmute_copy::<_, [(T, U); N]>(&dst) } + } + /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[unstable(feature = "array_methods", issue = "76118")] pub fn as_slice(&self) -> &[T] { diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index 6e0865e865..00164c631b 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -23,12 +23,10 @@ impl bool { /// # Examples /// /// ``` - /// #![feature(bool_to_option)] - /// /// assert_eq!(false.then(|| 0), None); /// assert_eq!(true.then(|| 0), Some(0)); /// ``` - #[unstable(feature = "bool_to_option", issue = "64260")] + #[stable(feature = "lazy_bool_to_option", since = "1.50.0")] #[inline] pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { None } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index b2afb702ee..c5ab7a39ff 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -929,7 +929,7 @@ impl RefCell { /// Also, please be aware that this method is only for special circumstances and is usually /// not what you want. In case of doubt, use [`borrow_mut`] instead. /// - /// [`borrow_mut`]: #method.borrow_mut + /// [`borrow_mut`]: RefCell::borrow_mut() /// /// # Examples /// @@ -953,7 +953,7 @@ impl RefCell { /// ensure no borrows exist and then resets the state tracking shared borrows. This is relevant /// if some `Ref` or `RefMut` borrows have been leaked. /// - /// [`get_mut`]: #method.get_mut + /// [`get_mut`]: RefCell::get_mut() /// /// # Examples /// @@ -1027,7 +1027,6 @@ impl RefCell { /// # Examples /// /// ``` - /// #![feature(refcell_take)] /// use std::cell::RefCell; /// /// let c = RefCell::new(5); @@ -1036,7 +1035,7 @@ impl RefCell { /// assert_eq!(five, 5); /// assert_eq!(c.into_inner(), 0); /// ``` - #[unstable(feature = "refcell_take", issue = "71395")] + #[stable(feature = "refcell_take", since = "1.50.0")] pub fn take(&self) -> T { self.replace(Default::default()) } @@ -1581,7 +1580,7 @@ impl fmt::Display for RefMut<'_, T> { /// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_ /// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value /// may be aliased for the duration of that `&mut` borrow. -/// This is showcased by the [`.get_mut()`] accessor, which is a non-`unsafe` getter that yields +/// This is showcased by the [`.get_mut()`] accessor, which is a _safe_ getter that yields /// a `&mut T`. /// /// [`.get_mut()`]: `UnsafeCell::get_mut` @@ -1619,7 +1618,6 @@ impl fmt::Display for RefMut<'_, T> { /// implies exclusive access to its `T`: /// /// ```rust -/// #![feature(unsafe_cell_get_mut)] /// #![forbid(unsafe_code)] // with exclusive accesses, /// // `UnsafeCell` is a transparent no-op wrapper, /// // so no need for `unsafe` here. @@ -1723,7 +1721,6 @@ impl UnsafeCell { /// # Examples /// /// ``` - /// #![feature(unsafe_cell_get_mut)] /// use std::cell::UnsafeCell; /// /// let mut c = UnsafeCell::new(5); @@ -1732,7 +1729,7 @@ impl UnsafeCell { /// assert_eq!(*c.get_mut(), 6); /// ``` #[inline] - #[unstable(feature = "unsafe_cell_get_mut", issue = "76943")] + #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] pub fn get_mut(&mut self) -> &mut T { &mut self.value } @@ -1746,7 +1743,7 @@ impl UnsafeCell { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T`. /// - /// [`get`]: #method.get + /// [`get`]: UnsafeCell::get() /// /// # Examples /// diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 1b847addcf..2baea7842a 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -109,8 +109,6 @@ impl char { /// `char`s. `from_u32()` will return `None` if the input is not a valid value /// for a `char`. /// - /// [`u32`]: primitive.u32.html - /// /// For an unsafe version of this function which ignores these checks, see /// [`from_u32_unchecked`]. /// @@ -159,8 +157,6 @@ impl char { /// `char`s. `from_u32_unchecked()` will ignore this, and blindly cast to /// `char`, possibly creating an invalid one. /// - /// [`u32`]: primitive.u32.html - /// /// # Safety /// /// This function is unsafe, as it may construct invalid `char` values. @@ -249,7 +245,7 @@ impl char { /// sixteen, hexadecimal, to give some common values. Arbitrary /// radices are supported. /// - /// Compared to `is_numeric()`, this function only recognizes the characters + /// Compared to [`is_numeric()`], this function only recognizes the characters /// `0-9`, `a-z` and `A-Z`. /// /// 'Digit' is defined to be only the following characters: @@ -258,9 +254,9 @@ impl char { /// * `a-z` /// * `A-Z` /// - /// For a more comprehensive understanding of 'digit', see [`is_numeric`][is_numeric]. + /// For a more comprehensive understanding of 'digit', see [`is_numeric()`]. /// - /// [is_numeric]: #method.is_numeric + /// [`is_numeric()`]: #method.is_numeric /// /// # Panics /// @@ -483,9 +479,9 @@ impl char { /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e` /// inclusive is not escaped. /// * All other characters are given hexadecimal Unicode escapes; see - /// [`escape_unicode`][escape_unicode]. + /// [`escape_unicode`]. /// - /// [escape_unicode]: #method.escape_unicode + /// [`escape_unicode`]: #method.escape_unicode /// /// # Examples /// @@ -504,7 +500,6 @@ impl char { /// println!("{}", '"'.escape_default()); /// ``` /// - /// /// Both are equivalent to: /// /// ``` @@ -584,10 +579,10 @@ impl char { /// Returns the number of 16-bit code units this `char` would need if /// encoded in UTF-16. /// - /// See the documentation for [`len_utf8`] for more explanation of this + /// See the documentation for [`len_utf8()`] for more explanation of this /// concept. This function is a mirror, but for UTF-16 instead of UTF-8. /// - /// [`len_utf8`]: #method.len_utf8 + /// [`len_utf8()`]: #method.len_utf8 /// /// # Examples /// @@ -1075,10 +1070,10 @@ impl char { /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// - /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// To uppercase the value in-place, use [`make_ascii_uppercase()`]. /// /// To uppercase ASCII characters in addition to non-ASCII characters, use - /// [`to_uppercase`]. + /// [`to_uppercase()`]. /// /// # Examples /// @@ -1090,8 +1085,8 @@ impl char { /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); /// ``` /// - /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase - /// [`to_uppercase`]: #method.to_uppercase + /// [`make_ascii_uppercase()`]: #method.make_ascii_uppercase + /// [`to_uppercase()`]: #method.to_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> char { @@ -1103,10 +1098,10 @@ impl char { /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// - /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// To lowercase the value in-place, use [`make_ascii_lowercase()`]. /// /// To lowercase ASCII characters in addition to non-ASCII characters, use - /// [`to_lowercase`]. + /// [`to_lowercase()`]. /// /// # Examples /// @@ -1118,8 +1113,8 @@ impl char { /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); /// ``` /// - /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase - /// [`to_lowercase`]: #method.to_lowercase + /// [`make_ascii_lowercase()`]: #method.make_ascii_lowercase + /// [`to_lowercase()`]: #method.to_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> char { @@ -1153,7 +1148,7 @@ impl char { /// but non-ASCII letters are unchanged. /// /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. + /// [`to_ascii_uppercase()`]. /// /// # Examples /// @@ -1165,7 +1160,7 @@ impl char { /// assert_eq!('A', ascii); /// ``` /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn make_ascii_uppercase(&mut self) { @@ -1178,7 +1173,7 @@ impl char { /// but non-ASCII letters are unchanged. /// /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. + /// [`to_ascii_lowercase()`]. /// /// # Examples /// @@ -1190,7 +1185,7 @@ impl char { /// assert_eq!('a', ascii); /// ``` /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn make_ascii_lowercase(&mut self) { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index bbb3a3dea4..0c459a820c 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -325,6 +325,120 @@ pub enum Ordering { } impl Ordering { + /// Returns `true` if the ordering is the `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_eq(), false); + /// assert_eq!(Ordering::Equal.is_eq(), true); + /// assert_eq!(Ordering::Greater.is_eq(), false); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_eq(self) -> bool { + matches!(self, Equal) + } + + /// Returns `true` if the ordering is not the `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_ne(), true); + /// assert_eq!(Ordering::Equal.is_ne(), false); + /// assert_eq!(Ordering::Greater.is_ne(), true); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_ne(self) -> bool { + !matches!(self, Equal) + } + + /// Returns `true` if the ordering is the `Less` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_lt(), true); + /// assert_eq!(Ordering::Equal.is_lt(), false); + /// assert_eq!(Ordering::Greater.is_lt(), false); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_lt(self) -> bool { + matches!(self, Less) + } + + /// Returns `true` if the ordering is the `Greater` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_gt(), false); + /// assert_eq!(Ordering::Equal.is_gt(), false); + /// assert_eq!(Ordering::Greater.is_gt(), true); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_gt(self) -> bool { + matches!(self, Greater) + } + + /// Returns `true` if the ordering is either the `Less` or `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_le(), true); + /// assert_eq!(Ordering::Equal.is_le(), true); + /// assert_eq!(Ordering::Greater.is_le(), false); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_le(self) -> bool { + !matches!(self, Greater) + } + + /// Returns `true` if the ordering is either the `Greater` or `Equal` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_helpers)] + /// use std::cmp::Ordering; + /// + /// assert_eq!(Ordering::Less.is_ge(), false); + /// assert_eq!(Ordering::Equal.is_ge(), true); + /// assert_eq!(Ordering::Greater.is_ge(), true); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "ordering_helpers", issue = "79885")] + pub const fn is_ge(self) -> bool { + !matches!(self, Less) + } + /// Reverses the `Ordering`. /// /// * `Less` becomes `Greater`. @@ -641,14 +755,12 @@ pub trait Ord: Eq + PartialOrd { /// # Examples /// /// ``` - /// #![feature(clamp)] - /// /// assert!((-3).clamp(-2, 1) == -2); /// assert!(0.clamp(-2, 1) == 0); /// assert!(2.clamp(-2, 1) == 1); /// ``` #[must_use] - #[unstable(feature = "clamp", issue = "44095")] + #[stable(feature = "clamp", since = "1.50.0")] fn clamp(self, min: Self, max: Self) -> Self where Self: Sized, @@ -1124,7 +1236,7 @@ mod impls { impl PartialOrd for bool { #[inline] fn partial_cmp(&self, other: &bool) -> Option { - (*self as u8).partial_cmp(&(*other as u8)) + Some(self.cmp(other)) } } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 506d778068..0c65c1c9eb 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -403,7 +403,7 @@ impl<'a> Arguments<'a> { /// ```rust /// #![feature(fmt_as_str)] /// - /// use core::fmt::Arguments; + /// use std::fmt::Arguments; /// /// fn write_str(_: &str) { /* ... */ } /// @@ -1084,7 +1084,9 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { // a string piece. for (arg, piece) in fmt.iter().zip(args.pieces.iter()) { formatter.buf.write_str(*piece)?; - run(&mut formatter, arg, &args.args)?; + // SAFETY: arg and args.args come from the same Arguments, + // which guarantees the indexes are always within bounds. + unsafe { run(&mut formatter, arg, &args.args) }?; idx += 1; } } @@ -1098,25 +1100,37 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { Ok(()) } -fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result { +unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result { fmt.fill = arg.format.fill; fmt.align = arg.format.align; fmt.flags = arg.format.flags; - fmt.width = getcount(args, &arg.format.width); - fmt.precision = getcount(args, &arg.format.precision); + // SAFETY: arg and args come from the same Arguments, + // which guarantees the indexes are always within bounds. + unsafe { + fmt.width = getcount(args, &arg.format.width); + fmt.precision = getcount(args, &arg.format.precision); + } // Extract the correct argument - let value = args[arg.position]; + debug_assert!(arg.position < args.len()); + // SAFETY: arg and args come from the same Arguments, + // which guarantees its index is always within bounds. + let value = unsafe { args.get_unchecked(arg.position) }; // Then actually do some printing (value.formatter)(value.value, fmt) } -fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option { +unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option { match *cnt { rt::v1::Count::Is(n) => Some(n), rt::v1::Count::Implied => None, - rt::v1::Count::Param(i) => args[i].as_usize(), + rt::v1::Count::Param(i) => { + debug_assert!(i < args.len()); + // SAFETY: cnt and args come from the same Arguments, + // which guarantees this index is always within bounds. + unsafe { args.get_unchecked(i).as_usize() } + } } } @@ -1182,7 +1196,7 @@ impl<'a> Formatter<'a> { /// ``` /// use std::fmt; /// - /// struct Foo { nb: i32 }; + /// struct Foo { nb: i32 } /// /// impl Foo { /// fn new(nb: i32) -> Foo { diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index ab162638a1..560dd25ecf 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -21,7 +21,7 @@ pub struct Pending { /// # Examples /// /// ```no_run -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let future = future::pending(); diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index f302cda09e..9ae118e29f 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -3,7 +3,7 @@ use crate::future::Future; use crate::pin::Pin; use crate::task::{Context, Poll}; -/// Creates a future that wraps a function returning `Poll`. +/// Creates a future that wraps a function returning [`Poll`]. /// /// Polling the future delegates to the wrapped function. /// @@ -13,7 +13,7 @@ use crate::task::{Context, Poll}; /// #![feature(future_poll_fn)] /// # async fn run() { /// use core::future::poll_fn; -/// use core::task::{Context, Poll}; +/// use std::task::{Context, Poll}; /// /// fn read_line(_cx: &mut Context<'_>) -> Poll { /// Poll::Ready("Hello, World!".into()) @@ -21,7 +21,7 @@ use crate::task::{Context, Poll}; /// /// let read_future = poll_fn(read_line); /// assert_eq!(read_future.await, "Hello, World!".to_owned()); -/// # }; +/// # } /// ``` #[unstable(feature = "future_poll_fn", issue = "72302")] pub fn poll_fn(f: F) -> PollFn @@ -31,7 +31,7 @@ where PollFn { f } } -/// A Future that wraps a function returning `Poll`. +/// A Future that wraps a function returning [`Poll`]. /// /// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index e98f5c570b..b0c7fbb1d7 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -33,7 +33,7 @@ impl Future for Ready { /// # Examples /// /// ``` -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let a = future::ready(1); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 433f012930..5292182269 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -815,6 +815,7 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit @@ -1173,133 +1174,133 @@ extern "rust-intrinsic" { /// Returns the square root of an `f32` /// /// The stabilized version of this intrinsic is - /// [`std::f32::sqrt`](../../std/primitive.f32.html#method.sqrt) + /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) pub fn sqrtf32(x: f32) -> f32; /// Returns the square root of an `f64` /// /// The stabilized version of this intrinsic is - /// [`std::f64::sqrt`](../../std/primitive.f64.html#method.sqrt) + /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) pub fn sqrtf64(x: f64) -> f64; /// Raises an `f32` to an integer power. /// /// The stabilized version of this intrinsic is - /// [`std::f32::powi`](../../std/primitive.f32.html#method.powi) + /// [`f32::powi`](../../std/primitive.f32.html#method.powi) pub fn powif32(a: f32, x: i32) -> f32; /// Raises an `f64` to an integer power. /// /// The stabilized version of this intrinsic is - /// [`std::f64::powi`](../../std/primitive.f64.html#method.powi) + /// [`f64::powi`](../../std/primitive.f64.html#method.powi) pub fn powif64(a: f64, x: i32) -> f64; /// Returns the sine of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::sin`](../../std/primitive.f32.html#method.sin) + /// [`f32::sin`](../../std/primitive.f32.html#method.sin) pub fn sinf32(x: f32) -> f32; /// Returns the sine of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::sin`](../../std/primitive.f64.html#method.sin) + /// [`f64::sin`](../../std/primitive.f64.html#method.sin) pub fn sinf64(x: f64) -> f64; /// Returns the cosine of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::cos`](../../std/primitive.f32.html#method.cos) + /// [`f32::cos`](../../std/primitive.f32.html#method.cos) pub fn cosf32(x: f32) -> f32; /// Returns the cosine of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::cos`](../../std/primitive.f64.html#method.cos) + /// [`f64::cos`](../../std/primitive.f64.html#method.cos) pub fn cosf64(x: f64) -> f64; /// Raises an `f32` to an `f32` power. /// /// The stabilized version of this intrinsic is - /// [`std::f32::powf`](../../std/primitive.f32.html#method.powf) + /// [`f32::powf`](../../std/primitive.f32.html#method.powf) pub fn powf32(a: f32, x: f32) -> f32; /// Raises an `f64` to an `f64` power. /// /// The stabilized version of this intrinsic is - /// [`std::f64::powf`](../../std/primitive.f64.html#method.powf) + /// [`f64::powf`](../../std/primitive.f64.html#method.powf) pub fn powf64(a: f64, x: f64) -> f64; /// Returns the exponential of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::exp`](../../std/primitive.f32.html#method.exp) + /// [`f32::exp`](../../std/primitive.f32.html#method.exp) pub fn expf32(x: f32) -> f32; /// Returns the exponential of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::exp`](../../std/primitive.f64.html#method.exp) + /// [`f64::exp`](../../std/primitive.f64.html#method.exp) pub fn expf64(x: f64) -> f64; /// Returns 2 raised to the power of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::exp2`](../../std/primitive.f32.html#method.exp2) + /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) pub fn exp2f32(x: f32) -> f32; /// Returns 2 raised to the power of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::exp2`](../../std/primitive.f64.html#method.exp2) + /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) pub fn exp2f64(x: f64) -> f64; /// Returns the natural logarithm of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::ln`](../../std/primitive.f32.html#method.ln) + /// [`f32::ln`](../../std/primitive.f32.html#method.ln) pub fn logf32(x: f32) -> f32; /// Returns the natural logarithm of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::ln`](../../std/primitive.f64.html#method.ln) + /// [`f64::ln`](../../std/primitive.f64.html#method.ln) pub fn logf64(x: f64) -> f64; /// Returns the base 10 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::log10`](../../std/primitive.f32.html#method.log10) + /// [`f32::log10`](../../std/primitive.f32.html#method.log10) pub fn log10f32(x: f32) -> f32; /// Returns the base 10 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::log10`](../../std/primitive.f64.html#method.log10) + /// [`f64::log10`](../../std/primitive.f64.html#method.log10) pub fn log10f64(x: f64) -> f64; /// Returns the base 2 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::log2`](../../std/primitive.f32.html#method.log2) + /// [`f32::log2`](../../std/primitive.f32.html#method.log2) pub fn log2f32(x: f32) -> f32; /// Returns the base 2 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::log2`](../../std/primitive.f64.html#method.log2) + /// [`f64::log2`](../../std/primitive.f64.html#method.log2) pub fn log2f64(x: f64) -> f64; /// Returns `a * b + c` for `f32` values. /// /// The stabilized version of this intrinsic is - /// [`std::f32::mul_add`](../../std/primitive.f32.html#method.mul_add) + /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values. /// /// The stabilized version of this intrinsic is - /// [`std::f64::mul_add`](../../std/primitive.f64.html#method.mul_add) + /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; /// Returns the absolute value of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::abs`](../../std/primitive.f32.html#method.abs) + /// [`f32::abs`](../../std/primitive.f32.html#method.abs) pub fn fabsf32(x: f32) -> f32; /// Returns the absolute value of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::abs`](../../std/primitive.f64.html#method.abs) + /// [`f64::abs`](../../std/primitive.f64.html#method.abs) pub fn fabsf64(x: f64) -> f64; /// Returns the minimum of two `f32` values. @@ -1326,45 +1327,45 @@ extern "rust-intrinsic" { /// Copies the sign from `y` to `x` for `f32` values. /// /// The stabilized version of this intrinsic is - /// [`std::f32::copysign`](../../std/primitive.f32.html#method.copysign) + /// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) pub fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. /// /// The stabilized version of this intrinsic is - /// [`std::f64::copysign`](../../std/primitive.f64.html#method.copysign) + /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) pub fn copysignf64(x: f64, y: f64) -> f64; /// Returns the largest integer less than or equal to an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::floor`](../../std/primitive.f32.html#method.floor) + /// [`f32::floor`](../../std/primitive.f32.html#method.floor) pub fn floorf32(x: f32) -> f32; /// Returns the largest integer less than or equal to an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::floor`](../../std/primitive.f64.html#method.floor) + /// [`f64::floor`](../../std/primitive.f64.html#method.floor) pub fn floorf64(x: f64) -> f64; /// Returns the smallest integer greater than or equal to an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::ceil`](../../std/primitive.f32.html#method.ceil) + /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) pub fn ceilf32(x: f32) -> f32; /// Returns the smallest integer greater than or equal to an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::ceil`](../../std/primitive.f64.html#method.ceil) + /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) pub fn ceilf64(x: f64) -> f64; /// Returns the integer part of an `f32`. /// /// The stabilized version of this intrinsic is - /// [`std::f32::trunc`](../../std/primitive.f32.html#method.trunc) + /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) pub fn truncf32(x: f32) -> f32; /// Returns the integer part of an `f64`. /// /// The stabilized version of this intrinsic is - /// [`std::f64::trunc`](../../std/primitive.f64.html#method.trunc) + /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) pub fn truncf64(x: f64) -> f64; /// Returns the nearest integer to an `f32`. May raise an inexact floating-point exception @@ -1386,12 +1387,12 @@ extern "rust-intrinsic" { /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is - /// [`std::f32::round`](../../std/primitive.f32.html#method.round) + /// [`f32::round`](../../std/primitive.f32.html#method.round) pub fn roundf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is - /// [`std::f64::round`](../../std/primitive.f64.html#method.round) + /// [`f64::round`](../../std/primitive.f64.html#method.round) pub fn roundf64(x: f64) -> f64; /// Float addition that allows optimizations based on algebraic rules. @@ -1486,7 +1487,7 @@ extern "rust-intrinsic" { /// let num_leading = unsafe { ctlz_nonzero(x) }; /// assert_eq!(num_leading, 3); /// ``` - #[rustc_const_unstable(feature = "constctlz", issue = "none")] + #[rustc_const_stable(feature = "constctlz", since = "1.50.0")] pub fn ctlz_nonzero(x: T) -> T; /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. @@ -1732,6 +1733,11 @@ extern "rust-intrinsic" { /// See documentation of `<*const T>::guaranteed_ne` for details. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; + + /// Allocate at compile time. Should not be called at runtime. + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + #[cfg(not(bootstrap))] + pub fn const_allocate(size: usize, align: usize) -> *mut u8; } // Some functions are defined here because they accidentally got made diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 2e070d7122..9753e1b43b 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -1,6 +1,5 @@ use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen}; -use crate::ops::Try; -use crate::usize; +use crate::{ops::Try, usize}; /// An iterator that links two iterators together, in a chain. /// diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs new file mode 100644 index 0000000000..7da47dcd2d --- /dev/null +++ b/library/core/src/iter/adapters/cloned.rs @@ -0,0 +1,139 @@ +use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::{FusedIterator, TrustedLen}; +use crate::ops::Try; + +/// An iterator that clones the elements of an underlying iterator. +/// +/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cloned`]: Iterator::cloned +/// [`Iterator`]: trait.Iterator.html +#[stable(feature = "iter_cloned", since = "1.1.0")] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[derive(Clone, Debug)] +pub struct Cloned { + it: I, +} + +impl Cloned { + pub(in crate::iter) fn new(it: I) -> Cloned { + Cloned { it } + } +} + +fn clone_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { + move |acc, elt| f(acc, elt.clone()) +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> Iterator for Cloned +where + I: Iterator, + T: Clone, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.it.next().cloned() + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_fold(init, clone_try_fold(f)) + } + + fn fold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.map(T::clone).fold(init, f) + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { try_get_unchecked(&mut self.it, idx).clone() } + } +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> DoubleEndedIterator for Cloned +where + I: DoubleEndedIterator, + T: Clone, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().cloned() + } + + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_rfold(init, clone_try_fold(f)) + } + + fn rfold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.map(T::clone).rfold(init, f) + } +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> ExactSizeIterator for Cloned +where + I: ExactSizeIterator, + T: Clone, +{ + fn len(&self) -> usize { + self.it.len() + } + + fn is_empty(&self) -> bool { + self.it.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, I, T: 'a> FusedIterator for Cloned +where + I: FusedIterator, + T: Clone, +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Cloned +where + I: TrustedRandomAccess, +{ + #[inline] + fn may_have_side_effect() -> bool { + true + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, I, T: 'a> TrustedLen for Cloned +where + I: TrustedLen, + T: Clone, +{ +} diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs new file mode 100644 index 0000000000..46f2235411 --- /dev/null +++ b/library/core/src/iter/adapters/copied.rs @@ -0,0 +1,155 @@ +use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::{FusedIterator, TrustedLen}; +use crate::ops::Try; + +/// An iterator that copies the elements of an underlying iterator. +/// +/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`copied`]: Iterator::copied +/// [`Iterator`]: trait.Iterator.html +#[stable(feature = "iter_copied", since = "1.36.0")] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[derive(Clone, Debug)] +pub struct Copied { + it: I, +} + +impl Copied { + pub(in crate::iter) fn new(it: I) -> Copied { + Copied { it } + } +} + +fn copy_fold(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc { + move |acc, &elt| f(acc, elt) +} + +fn copy_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { + move |acc, &elt| f(acc, elt) +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> Iterator for Copied +where + I: Iterator, + T: Copy, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.it.next().copied() + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_fold(init, copy_try_fold(f)) + } + + fn fold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.fold(init, copy_fold(f)) + } + + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() + } + + fn last(self) -> Option { + self.it.last().copied() + } + + fn count(self) -> usize { + self.it.count() + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + *unsafe { try_get_unchecked(&mut self.it, idx) } + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> DoubleEndedIterator for Copied +where + I: DoubleEndedIterator, + T: Copy, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().copied() + } + + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.it.try_rfold(init, copy_try_fold(f)) + } + + fn rfold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.rfold(init, copy_fold(f)) + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> ExactSizeIterator for Copied +where + I: ExactSizeIterator, + T: Copy, +{ + fn len(&self) -> usize { + self.it.len() + } + + fn is_empty(&self) -> bool { + self.it.is_empty() + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +impl<'a, I, T: 'a> FusedIterator for Copied +where + I: FusedIterator, + T: Copy, +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Copied +where + I: TrustedRandomAccess, +{ + #[inline] + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[stable(feature = "iter_copied", since = "1.36.0")] +unsafe impl<'a, I, T: 'a> TrustedLen for Copied +where + I: TrustedLen, + T: Copy, +{ +} diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs new file mode 100644 index 0000000000..6e9a011f81 --- /dev/null +++ b/library/core/src/iter/adapters/cycle.rs @@ -0,0 +1,87 @@ +use crate::{iter::FusedIterator, ops::Try}; + +/// An iterator that repeats endlessly. +/// +/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cycle`]: Iterator::cycle +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Cycle { + orig: I, + iter: I, +} + +impl Cycle { + pub(in crate::iter) fn new(iter: I) -> Cycle { + Cycle { orig: iter.clone(), iter } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Cycle +where + I: Clone + Iterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + match self.iter.next() { + None => { + self.iter = self.orig.clone(); + self.iter.next() + } + y => y, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // the cycle iterator is either empty or infinite + match self.orig.size_hint() { + sz @ (0, Some(0)) => sz, + (0, _) => (0, None), + _ => (usize::MAX, None), + } + } + + #[inline] + fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + // fully iterate the current iterator. this is necessary because + // `self.iter` may be empty even when `self.orig` isn't + acc = self.iter.try_fold(acc, &mut f)?; + self.iter = self.orig.clone(); + + // complete a full cycle, keeping track of whether the cycled + // iterator is empty or not. we need to return early in case + // of an empty iterator to prevent an infinite loop + let mut is_empty = true; + acc = self.iter.try_fold(acc, |acc, x| { + is_empty = false; + f(acc, x) + })?; + + if is_empty { + return try { acc }; + } + + loop { + self.iter = self.orig.clone(); + acc = self.iter.try_fold(acc, &mut f)?; + } + } + + // No `fold` override, because `fold` doesn't make much sense for `Cycle`, + // and we can't do anything better than the default. +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Cycle where I: Clone + Iterator {} diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs new file mode 100644 index 0000000000..5978c2da98 --- /dev/null +++ b/library/core/src/iter/adapters/enumerate.rs @@ -0,0 +1,238 @@ +use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::{Add, AddAssign, Try}; + +/// An iterator that yields the current count and the element during iteration. +/// +/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`enumerate`]: Iterator::enumerate +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Enumerate { + iter: I, + count: usize, +} +impl Enumerate { + pub(in crate::iter) fn new(iter: I) -> Enumerate { + Enumerate { iter, count: 0 } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Enumerate +where + I: Iterator, +{ + type Item = (usize, ::Item); + + /// # Overflow Behavior + /// + /// The method does no guarding against overflows, so enumerating more than + /// `usize::MAX` elements either produces the wrong result or panics. If + /// debug assertions are enabled, a panic is guaranteed. + /// + /// # Panics + /// + /// Might panic if the index of the element overflows a `usize`. + #[inline] + fn next(&mut self) -> Option<(usize, ::Item)> { + let a = self.iter.next()?; + let i = self.count; + // Possible undefined overflow. + AddAssign::add_assign(&mut self.count, 1); + Some((i, a)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> { + let a = self.iter.nth(n)?; + // Possible undefined overflow. + let i = Add::add(self.count, n); + self.count = Add::add(i, 1); + Some((i, a)) + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn enumerate<'a, T, Acc, R>( + count: &'a mut usize, + mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| { + let acc = fold(acc, (*count, item)); + // Possible undefined overflow. + AddAssign::add_assign(count, 1); + acc + } + } + + self.iter.try_fold(init, enumerate(&mut self.count, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + let acc = fold(acc, (count, item)); + // Possible undefined overflow. + AddAssign::add_assign(&mut count, 1); + acc + } + } + + self.iter.fold(init, enumerate(self.count, fold)) + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; + (Add::add(self.count, idx), value) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Enumerate +where + I: ExactSizeIterator + DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Option<(usize, ::Item)> { + let a = self.iter.next_back()?; + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + Some((self.count + len, a)) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<(usize, ::Item)> { + let a = self.iter.nth_back(n)?; + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + Some((self.count + len, a)) + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + // Can safely add and subtract the count, as `ExactSizeIterator` promises + // that the number of elements fits into a `usize`. + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> R, + ) -> impl FnMut(Acc, T) -> R { + move |acc, item| { + count -= 1; + fold(acc, (count, item)) + } + } + + let count = self.count + self.iter.len(); + self.iter.try_rfold(init, enumerate(count, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + // Can safely add and subtract the count, as `ExactSizeIterator` promises + // that the number of elements fits into a `usize`. + fn enumerate( + mut count: usize, + mut fold: impl FnMut(Acc, (usize, T)) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + count -= 1; + fold(acc, (count, item)) + } + } + + let count = self.count + self.iter.len(); + self.iter.rfold(init, enumerate(count, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Enumerate +where + I: ExactSizeIterator, +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Enumerate +where + I: TrustedRandomAccess, +{ + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Enumerate where I: FusedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Enumerate where I: TrustedLen {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Enumerate +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Enumerate {} diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs new file mode 100644 index 0000000000..f8d684fcdd --- /dev/null +++ b/library/core/src/iter/adapters/filter.rs @@ -0,0 +1,152 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::Try; + +/// An iterator that filters the elements of `iter` with `predicate`. +/// +/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter`]: Iterator::filter +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Filter { + iter: I, + predicate: P, +} +impl Filter { + pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter { + Filter { iter, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Filter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Filter").field("iter", &self.iter).finish() + } +} + +fn filter_fold( + mut predicate: impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } +} + +fn filter_try_fold<'a, T, Acc, R: Try>( + predicate: &'a mut impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Filter +where + P: FnMut(&I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.find(&mut self.predicate) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + // this special case allows the compiler to make `.filter(_).count()` + // branchless. Barring perfect branch prediction (which is unattainable in + // the general case), this will be much faster in >90% of cases (containing + // virtually all real workloads) and only a tiny bit slower in the rest. + // + // Having this specialization thus allows us to write `.filter(p).count()` + // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is + // less readable and also less backwards-compatible to Rust before 1.10. + // + // Using the branchless version will also simplify the LLVM byte code, thus + // leaving more budget for LLVM optimizations. + #[inline] + fn count(self) -> usize { + #[inline] + fn to_usize(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize { + move |x| predicate(&x) as usize + } + + self.iter.map(to_usize(self.predicate)).sum() + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, filter_fold(self.predicate, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Filter +where + P: FnMut(&I::Item) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.iter.rfind(&mut self.predicate) + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, filter_fold(self.predicate, fold)) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Filter +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Filter where P: FnMut(&I::Item) -> bool {} diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs new file mode 100644 index 0000000000..0dccf2c533 --- /dev/null +++ b/library/core/src/iter/adapters/filter_map.rs @@ -0,0 +1,150 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that uses `f` to both filter and map elements from `iter`. +/// +/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter_map`]: Iterator::filter_map +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct FilterMap { + iter: I, + f: F, +} +impl FilterMap { + pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap { + FilterMap { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for FilterMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FilterMap").field("iter", &self.iter).finish() + } +} + +fn filter_map_fold( + mut f: impl FnMut(T) -> Option, + mut fold: impl FnMut(Acc, B) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => acc, + } +} + +fn filter_map_try_fold<'a, T, B, Acc, R: Try>( + f: &'a mut impl FnMut(T) -> Option, + mut fold: impl FnMut(Acc, B) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => try { acc }, + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for FilterMap +where + F: FnMut(I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + self.iter.find_map(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, filter_map_fold(self.f, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for FilterMap +where + F: FnMut(I::Item) -> Option, +{ + #[inline] + fn next_back(&mut self) -> Option { + #[inline] + fn find( + f: &mut impl FnMut(T) -> Option, + ) -> impl FnMut((), T) -> ControlFlow + '_ { + move |(), x| match f(x) { + Some(x) => ControlFlow::Break(x), + None => ControlFlow::CONTINUE, + } + } + + self.iter.try_rfold((), find(&mut self.f)).break_value() + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, filter_map_fold(self.f, fold)) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for FilterMap +where + F: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for FilterMap where + F: FnMut(I::Item) -> Option +{ +} diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 96d0a60a32..29e191db0f 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,9 +1,7 @@ use crate::fmt; +use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map}; use crate::ops::Try; -use super::super::{DoubleEndedIterator, Fuse, FusedIterator, Iterator}; -use super::Map; - /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// @@ -14,8 +12,9 @@ use super::Map; pub struct FlatMap { inner: FlattenCompat, ::IntoIter>, } + impl U> FlatMap { - pub(in super::super) fn new(iter: I, f: F) -> FlatMap { + pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap { FlatMap { inner: FlattenCompat::new(iter.map(f)) } } } @@ -121,8 +120,7 @@ where /// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`flatten`]: Iterator::flatten -/// [`Iterator`]: trait.Iterator.html +/// [`flatten`]: Iterator::flatten() #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "iterator_flatten", since = "1.29.0")] pub struct Flatten> { diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 60ac3524e6..ae07406531 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,9 +1,6 @@ -use super::InPlaceIterable; use crate::intrinsics; -use crate::iter::adapters::zip::try_get_unchecked; -use crate::iter::adapters::SourceIter; -use crate::iter::TrustedRandomAccess; -use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; +use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter}; +use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedRandomAccess}; use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs new file mode 100644 index 0000000000..88f5ee61b6 --- /dev/null +++ b/library/core/src/iter/adapters/inspect.rs @@ -0,0 +1,167 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::Try; + +/// An iterator that calls a function with a reference to each element before +/// yielding it. +/// +/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`inspect`]: Iterator::inspect +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Inspect { + iter: I, + f: F, +} +impl Inspect { + pub(in crate::iter) fn new(iter: I, f: F) -> Inspect { + Inspect { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Inspect { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Inspect").field("iter", &self.iter).finish() + } +} + +impl Inspect +where + F: FnMut(&I::Item), +{ + #[inline] + fn do_inspect(&mut self, elt: Option) -> Option { + if let Some(ref a) = elt { + (self.f)(a); + } + + elt + } +} + +fn inspect_fold( + mut f: impl FnMut(&T), + mut fold: impl FnMut(Acc, T) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, item| { + f(&item); + fold(acc, item) + } +} + +fn inspect_try_fold<'a, T, Acc, R>( + f: &'a mut impl FnMut(&T), + mut fold: impl FnMut(Acc, T) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, item| { + f(&item); + fold(acc, item) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Inspect +where + F: FnMut(&I::Item), +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + let next = self.iter.next(); + self.do_inspect(next) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold)) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, inspect_fold(self.f, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Inspect +where + F: FnMut(&I::Item), +{ + #[inline] + fn next_back(&mut self) -> Option { + let next = self.iter.next_back(); + self.do_inspect(next) + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold)) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, inspect_fold(self.f, fold)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Inspect +where + F: FnMut(&I::Item), +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Inspect where F: FnMut(&I::Item) {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Inspect +where + F: FnMut(&I::Item), + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Inspect where F: FnMut(&I::Item) {} diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs new file mode 100644 index 0000000000..12673806ec --- /dev/null +++ b/library/core/src/iter/adapters/map.rs @@ -0,0 +1,213 @@ +use crate::fmt; +use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::Try; + +/// An iterator that maps the values of `iter` with `f`. +/// +/// This `struct` is created by the [`map`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`map`]: Iterator::map +/// [`Iterator`]: trait.Iterator.html +/// +/// # Notes about side effects +/// +/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that +/// you can also [`map`] backwards: +/// +/// ```rust +/// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); +/// +/// assert_eq!(v, [4, 3, 2]); +/// ``` +/// +/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html +/// +/// But if your closure has state, iterating backwards may act in a way you do +/// not expect. Let's go through an example. First, in the forward direction: +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) { +/// println!("{:?}", pair); +/// } +/// ``` +/// +/// This will print "('a', 1), ('b', 2), ('c', 3)". +/// +/// Now consider this twist where we add a call to `rev`. This version will +/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, +/// but the values of the counter still go in order. This is because `map()` is +/// still being called lazily on each item, but we are popping items off the +/// back of the vector now, instead of shifting them from the front. +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) +/// .rev() { +/// println!("{:?}", pair); +/// } +/// ``` +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Map { + iter: I, + f: F, +} +impl Map { + pub(in crate::iter) fn new(iter: I, f: F) -> Map { + Map { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Map { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Map").field("iter", &self.iter).finish() + } +} + +fn map_fold( + mut f: impl FnMut(T) -> B, + mut g: impl FnMut(Acc, B) -> Acc, +) -> impl FnMut(Acc, T) -> Acc { + move |acc, elt| g(acc, f(elt)) +} + +fn map_try_fold<'a, T, B, Acc, R>( + f: &'a mut impl FnMut(T) -> B, + mut g: impl FnMut(Acc, B) -> R + 'a, +) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, elt| g(acc, f(elt)) +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Map +where + F: FnMut(I::Item) -> B, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn try_fold(&mut self, init: Acc, g: G) -> R + where + Self: Sized, + G: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, map_try_fold(&mut self.f, g)) + } + + fn fold(self, init: Acc, g: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, map_fold(self.f, g)) + } + + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Map +where + F: FnMut(I::Item) -> B, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(&mut self.f) + } + + fn try_rfold(&mut self, init: Acc, g: G) -> R + where + Self: Sized, + G: FnMut(Acc, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) + } + + fn rfold(self, init: Acc, g: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, map_fold(self.f, g)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Map +where + F: FnMut(I::Item) -> B, +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Map where F: FnMut(I::Item) -> B {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Map +where + I: TrustedLen, + F: FnMut(I::Item) -> B, +{ +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Map +where + I: TrustedRandomAccess, +{ + #[inline] + fn may_have_side_effect() -> bool { + true + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Map +where + F: FnMut(I::Item) -> B, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Map where F: FnMut(I::Item) -> B {} diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs new file mode 100644 index 0000000000..26114d5328 --- /dev/null +++ b/library/core/src/iter/adapters/map_while.rs @@ -0,0 +1,101 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that only accepts elements while `predicate` returns `Some(_)`. +/// +/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`map_while`]: Iterator::map_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[derive(Clone)] +pub struct MapWhile { + iter: I, + predicate: P, +} + +impl MapWhile { + pub(in crate::iter) fn new(iter: I, predicate: P) -> MapWhile { + MapWhile { iter, predicate } + } +} + +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +impl fmt::Debug for MapWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("MapWhile").field("iter", &self.iter).finish() + } +} + +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +impl Iterator for MapWhile +where + P: FnMut(I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + let x = self.iter.next()?; + (self.predicate)(x) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + let Self { iter, predicate } = self; + iter.try_fold(init, |acc, x| match predicate(x) { + Some(item) => ControlFlow::from_try(fold(acc, item)), + None => ControlFlow::Break(try { acc }), + }) + .into_try() + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for MapWhile +where + P: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for MapWhile where + P: FnMut(I::Item) -> Option +{ +} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 9586284e1d..b8d3430f91 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,26 +1,51 @@ -use crate::cmp; -use crate::fmt; -use crate::intrinsics; -use crate::ops::{Add, AddAssign, ControlFlow, Try}; - -use super::from_fn; -use super::{ - DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, TrustedLen, -}; +use crate::iter::{InPlaceIterable, Iterator}; +use crate::ops::{ControlFlow, Try}; mod chain; +mod cloned; +mod copied; +mod cycle; +mod enumerate; +mod filter; +mod filter_map; mod flatten; mod fuse; +mod inspect; +mod map; +mod map_while; +mod peekable; +mod rev; +mod scan; +mod skip; +mod skip_while; +mod step_by; +mod take; +mod take_while; mod zip; -pub use self::chain::Chain; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::flatten::{FlatMap, Flatten}; -pub use self::fuse::Fuse; -use self::zip::try_get_unchecked; +pub use self::{ + chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap, + flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev, + scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip, +}; + +#[stable(feature = "iter_cloned", since = "1.1.0")] +pub use self::cloned::Cloned; + +#[stable(feature = "iterator_step_by", since = "1.28.0")] +pub use self::step_by::StepBy; + +#[stable(feature = "iterator_flatten", since = "1.29.0")] +pub use self::flatten::Flatten; + +#[stable(feature = "iter_copied", since = "1.36.0")] +pub use self::copied::Copied; + +#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +pub use self::map_while::MapWhile; + #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::zip::TrustedRandomAccess; -pub use self::zip::Zip; /// This trait provides transitive access to source-stage in an interator-adapter pipeline /// under the conditions that @@ -85,2814 +110,10 @@ pub unsafe trait SourceIter { /// * whatever remains in the source after iteration has stopped /// * the memory that has become unused by advancing a consuming iterator /// - /// [`next()`]: Iterator::next + /// [`next()`]: Iterator::next() unsafe fn as_inner(&mut self) -> &mut Self::Source; } -/// A double-ended iterator with the direction inverted. -/// -/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`rev`]: Iterator::rev -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Rev { - iter: T, -} -impl Rev { - pub(super) fn new(iter: T) -> Rev { - Rev { iter } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Rev -where - I: DoubleEndedIterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - self.iter.next_back() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - self.iter.advance_back_by(n) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<::Item> { - self.iter.nth_back(n) - } - - fn try_fold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, f) - } - - fn fold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, f) - } - - #[inline] - fn find

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.iter.rfind(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Rev -where - I: DoubleEndedIterator, -{ - #[inline] - fn next_back(&mut self) -> Option<::Item> { - self.iter.next() - } - - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - self.iter.advance_by(n) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<::Item> { - self.iter.nth(n) - } - - fn try_rfold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, f) - } - - fn rfold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, f) - } - - fn rfind

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.iter.find(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Rev -where - I: ExactSizeIterator + DoubleEndedIterator, -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Rev where I: TrustedLen + DoubleEndedIterator {} - -/// An iterator that copies the elements of an underlying iterator. -/// -/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`copied`]: Iterator::copied -/// [`Iterator`]: trait.Iterator.html -#[stable(feature = "iter_copied", since = "1.36.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Clone, Debug)] -pub struct Copied { - it: I, -} - -impl Copied { - pub(super) fn new(it: I) -> Copied { - Copied { it } - } -} - -fn copy_fold(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc { - move |acc, &elt| f(acc, elt) -} - -fn copy_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { - move |acc, &elt| f(acc, elt) -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> Iterator for Copied -where - I: Iterator, - T: Copy, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.it.next().copied() - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } - - fn try_fold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_fold(init, copy_try_fold(f)) - } - - fn fold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.fold(init, copy_fold(f)) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() - } - - fn last(self) -> Option { - self.it.last().copied() - } - - fn count(self) -> usize { - self.it.count() - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - *unsafe { try_get_unchecked(&mut self.it, idx) } - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> DoubleEndedIterator for Copied -where - I: DoubleEndedIterator, - T: Copy, -{ - fn next_back(&mut self) -> Option { - self.it.next_back().copied() - } - - fn try_rfold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_rfold(init, copy_try_fold(f)) - } - - fn rfold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.rfold(init, copy_fold(f)) - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> ExactSizeIterator for Copied -where - I: ExactSizeIterator, - T: Copy, -{ - fn len(&self) -> usize { - self.it.len() - } - - fn is_empty(&self) -> bool { - self.it.is_empty() - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -impl<'a, I, T: 'a> FusedIterator for Copied -where - I: FusedIterator, - T: Copy, -{ -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Copied -where - I: TrustedRandomAccess, -{ - #[inline] - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[stable(feature = "iter_copied", since = "1.36.0")] -unsafe impl<'a, I, T: 'a> TrustedLen for Copied -where - I: TrustedLen, - T: Copy, -{ -} - -/// An iterator that clones the elements of an underlying iterator. -/// -/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`cloned`]: Iterator::cloned -/// [`Iterator`]: trait.Iterator.html -#[stable(feature = "iter_cloned", since = "1.1.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Clone, Debug)] -pub struct Cloned { - it: I, -} -impl Cloned { - pub(super) fn new(it: I) -> Cloned { - Cloned { it } - } -} - -fn clone_try_fold(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R { - move |acc, elt| f(acc, elt.clone()) -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> Iterator for Cloned -where - I: Iterator, - T: Clone, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.it.next().cloned() - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } - - fn try_fold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_fold(init, clone_try_fold(f)) - } - - fn fold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.map(T::clone).fold(init, f) - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { try_get_unchecked(&mut self.it, idx).clone() } - } -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> DoubleEndedIterator for Cloned -where - I: DoubleEndedIterator, - T: Clone, -{ - fn next_back(&mut self) -> Option { - self.it.next_back().cloned() - } - - fn try_rfold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.it.try_rfold(init, clone_try_fold(f)) - } - - fn rfold(self, init: Acc, f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.map(T::clone).rfold(init, f) - } -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> ExactSizeIterator for Cloned -where - I: ExactSizeIterator, - T: Clone, -{ - fn len(&self) -> usize { - self.it.len() - } - - fn is_empty(&self) -> bool { - self.it.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, I, T: 'a> FusedIterator for Cloned -where - I: FusedIterator, - T: Clone, -{ -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Cloned -where - I: TrustedRandomAccess, -{ - #[inline] - fn may_have_side_effect() -> bool { - true - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, I, T: 'a> TrustedLen for Cloned -where - I: TrustedLen, - T: Clone, -{ -} - -/// An iterator that repeats endlessly. -/// -/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`cycle`]: Iterator::cycle -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Cycle { - orig: I, - iter: I, -} -impl Cycle { - pub(super) fn new(iter: I) -> Cycle { - Cycle { orig: iter.clone(), iter } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Cycle -where - I: Clone + Iterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - match self.iter.next() { - None => { - self.iter = self.orig.clone(); - self.iter.next() - } - y => y, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // the cycle iterator is either empty or infinite - match self.orig.size_hint() { - sz @ (0, Some(0)) => sz, - (0, _) => (0, None), - _ => (usize::MAX, None), - } - } - - #[inline] - fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R - where - F: FnMut(Acc, Self::Item) -> R, - R: Try, - { - // fully iterate the current iterator. this is necessary because - // `self.iter` may be empty even when `self.orig` isn't - acc = self.iter.try_fold(acc, &mut f)?; - self.iter = self.orig.clone(); - - // complete a full cycle, keeping track of whether the cycled - // iterator is empty or not. we need to return early in case - // of an empty iterator to prevent an infinite loop - let mut is_empty = true; - acc = self.iter.try_fold(acc, |acc, x| { - is_empty = false; - f(acc, x) - })?; - - if is_empty { - return try { acc }; - } - - loop { - self.iter = self.orig.clone(); - acc = self.iter.try_fold(acc, &mut f)?; - } - } - - // No `fold` override, because `fold` doesn't make much sense for `Cycle`, - // and we can't do anything better than the default. -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Cycle where I: Clone + Iterator {} - -/// An iterator for stepping iterators by a custom amount. -/// -/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See -/// its documentation for more. -/// -/// [`step_by`]: Iterator::step_by -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "iterator_step_by", since = "1.28.0")] -#[derive(Clone, Debug)] -pub struct StepBy { - iter: I, - step: usize, - first_take: bool, -} -impl StepBy { - pub(super) fn new(iter: I, step: usize) -> StepBy { - assert!(step != 0); - StepBy { iter, step: step - 1, first_take: true } - } -} - -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl Iterator for StepBy -where - I: Iterator, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.first_take { - self.first_take = false; - self.iter.next() - } else { - self.iter.nth(self.step) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - #[inline] - fn first_size(step: usize) -> impl Fn(usize) -> usize { - move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } - } - - #[inline] - fn other_size(step: usize) -> impl Fn(usize) -> usize { - move |n| n / (step + 1) - } - - let (low, high) = self.iter.size_hint(); - - if self.first_take { - let f = first_size(self.step); - (f(low), high.map(f)) - } else { - let f = other_size(self.step); - (f(low), high.map(f)) - } - } - - #[inline] - fn nth(&mut self, mut n: usize) -> Option { - if self.first_take { - self.first_take = false; - let first = self.iter.next(); - if n == 0 { - return first; - } - n -= 1; - } - // n and self.step are indices, we need to add 1 to get the amount of elements - // When calling `.nth`, we need to subtract 1 again to convert back to an index - // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` - let mut step = self.step + 1; - // n + 1 could overflow - // thus, if n is usize::MAX, instead of adding one, we call .nth(step) - if n == usize::MAX { - self.iter.nth(step - 1); - } else { - n += 1; - } - - // overflow handling - loop { - let mul = n.checked_mul(step); - { - if intrinsics::likely(mul.is_some()) { - return self.iter.nth(mul.unwrap() - 1); - } - } - let div_n = usize::MAX / n; - let div_step = usize::MAX / step; - let nth_n = div_n * n; - let nth_step = div_step * step; - let nth = if nth_n > nth_step { - step -= div_n; - nth_n - } else { - n -= div_step; - nth_step - }; - self.iter.nth(nth - 1); - } - } - - fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R - where - F: FnMut(Acc, Self::Item) -> R, - R: Try, - { - #[inline] - fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { - move || iter.nth(step) - } - - if self.first_take { - self.first_take = false; - match self.iter.next() { - None => return try { acc }, - Some(x) => acc = f(acc, x)?, - } - } - from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) - } - - fn fold(mut self, mut acc: Acc, mut f: F) -> Acc - where - F: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { - move || iter.nth(step) - } - - if self.first_take { - self.first_take = false; - match self.iter.next() { - None => return acc, - Some(x) => acc = f(acc, x), - } - } - from_fn(nth(&mut self.iter, self.step)).fold(acc, f) - } -} - -impl StepBy -where - I: ExactSizeIterator, -{ - // The zero-based index starting from the end of the iterator of the - // last element. Used in the `DoubleEndedIterator` implementation. - fn next_back_index(&self) -> usize { - let rem = self.iter.len() % (self.step + 1); - if self.first_take { - if rem == 0 { self.step } else { rem - 1 } - } else { - rem - } - } -} - -#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] -impl DoubleEndedIterator for StepBy -where - I: DoubleEndedIterator + ExactSizeIterator, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.nth_back(self.next_back_index()) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - // `self.iter.nth_back(usize::MAX)` does the right thing here when `n` - // is out of bounds because the length of `self.iter` does not exceed - // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is - // zero-indexed - let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index()); - self.iter.nth_back(n) - } - - fn try_rfold(&mut self, init: Acc, mut f: F) -> R - where - F: FnMut(Acc, Self::Item) -> R, - R: Try, - { - #[inline] - fn nth_back( - iter: &mut I, - step: usize, - ) -> impl FnMut() -> Option + '_ { - move || iter.nth_back(step) - } - - match self.next_back() { - None => try { init }, - Some(x) => { - let acc = f(init, x)?; - from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) - } - } - } - - #[inline] - fn rfold(mut self, init: Acc, mut f: F) -> Acc - where - Self: Sized, - F: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn nth_back( - iter: &mut I, - step: usize, - ) -> impl FnMut() -> Option + '_ { - move || iter.nth_back(step) - } - - match self.next_back() { - None => init, - Some(x) => { - let acc = f(init, x); - from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f) - } - } - } -} - -// StepBy can only make the iterator shorter, so the len will still fit. -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} - -/// An iterator that maps the values of `iter` with `f`. -/// -/// This `struct` is created by the [`map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`map`]: Iterator::map -/// [`Iterator`]: trait.Iterator.html -/// -/// # Notes about side effects -/// -/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that -/// you can also [`map`] backwards: -/// -/// ```rust -/// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); -/// -/// assert_eq!(v, [4, 3, 2]); -/// ``` -/// -/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html -/// -/// But if your closure has state, iterating backwards may act in a way you do -/// not expect. Let's go through an example. First, in the forward direction: -/// -/// ```rust -/// let mut c = 0; -/// -/// for pair in vec!['a', 'b', 'c'].into_iter() -/// .map(|letter| { c += 1; (letter, c) }) { -/// println!("{:?}", pair); -/// } -/// ``` -/// -/// This will print "('a', 1), ('b', 2), ('c', 3)". -/// -/// Now consider this twist where we add a call to `rev`. This version will -/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, -/// but the values of the counter still go in order. This is because `map()` is -/// still being called lazily on each item, but we are popping items off the -/// back of the vector now, instead of shifting them from the front. -/// -/// ```rust -/// let mut c = 0; -/// -/// for pair in vec!['a', 'b', 'c'].into_iter() -/// .map(|letter| { c += 1; (letter, c) }) -/// .rev() { -/// println!("{:?}", pair); -/// } -/// ``` -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Map { - iter: I, - f: F, -} -impl Map { - pub(super) fn new(iter: I, f: F) -> Map { - Map { iter, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Map { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Map").field("iter", &self.iter).finish() - } -} - -fn map_fold( - mut f: impl FnMut(T) -> B, - mut g: impl FnMut(Acc, B) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, elt| g(acc, f(elt)) -} - -fn map_try_fold<'a, T, B, Acc, R>( - f: &'a mut impl FnMut(T) -> B, - mut g: impl FnMut(Acc, B) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, elt| g(acc, f(elt)) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Map -where - F: FnMut(I::Item) -> B, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(&mut self.f) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn try_fold(&mut self, init: Acc, g: G) -> R - where - Self: Sized, - G: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, map_try_fold(&mut self.f, g)) - } - - fn fold(self, init: Acc, g: G) -> Acc - where - G: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, map_fold(self.f, g)) - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Map -where - F: FnMut(I::Item) -> B, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(&mut self.f) - } - - fn try_rfold(&mut self, init: Acc, g: G) -> R - where - Self: Sized, - G: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) - } - - fn rfold(self, init: Acc, g: G) -> Acc - where - G: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, map_fold(self.f, g)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Map -where - F: FnMut(I::Item) -> B, -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Map where F: FnMut(I::Item) -> B {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Map -where - I: TrustedLen, - F: FnMut(I::Item) -> B, -{ -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Map -where - I: TrustedRandomAccess, -{ - #[inline] - fn may_have_side_effect() -> bool { - true - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Map -where - F: FnMut(I::Item) -> B, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Map where F: FnMut(I::Item) -> B {} - -/// An iterator that filters the elements of `iter` with `predicate`. -/// -/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`filter`]: Iterator::filter -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Filter { - iter: I, - predicate: P, -} -impl Filter { - pub(super) fn new(iter: I, predicate: P) -> Filter { - Filter { iter, predicate } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Filter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Filter").field("iter", &self.iter).finish() - } -} - -fn filter_fold( - mut predicate: impl FnMut(&T) -> bool, - mut fold: impl FnMut(Acc, T) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } -} - -fn filter_try_fold<'a, T, Acc, R: Try>( - predicate: &'a mut impl FnMut(&T) -> bool, - mut fold: impl FnMut(Acc, T) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Filter -where - P: FnMut(&I::Item) -> bool, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - self.iter.find(&mut self.predicate) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - // this special case allows the compiler to make `.filter(_).count()` - // branchless. Barring perfect branch prediction (which is unattainable in - // the general case), this will be much faster in >90% of cases (containing - // virtually all real workloads) and only a tiny bit slower in the rest. - // - // Having this specialization thus allows us to write `.filter(p).count()` - // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is - // less readable and also less backwards-compatible to Rust before 1.10. - // - // Using the branchless version will also simplify the LLVM byte code, thus - // leaving more budget for LLVM optimizations. - #[inline] - fn count(self) -> usize { - #[inline] - fn to_usize(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize { - move |x| predicate(&x) as usize - } - - self.iter.map(to_usize(self.predicate)).sum() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, filter_fold(self.predicate, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Filter -where - P: FnMut(&I::Item) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.rfind(&mut self.predicate) - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, filter_fold(self.predicate, fold)) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Filter -where - P: FnMut(&I::Item) -> bool, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Filter where P: FnMut(&I::Item) -> bool {} - -/// An iterator that uses `f` to both filter and map elements from `iter`. -/// -/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`filter_map`]: Iterator::filter_map -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct FilterMap { - iter: I, - f: F, -} -impl FilterMap { - pub(super) fn new(iter: I, f: F) -> FilterMap { - FilterMap { iter, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FilterMap { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FilterMap").field("iter", &self.iter).finish() - } -} - -fn filter_map_fold( - mut f: impl FnMut(T) -> Option, - mut fold: impl FnMut(Acc, B) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => acc, - } -} - -fn filter_map_try_fold<'a, T, B, Acc, R: Try>( - f: &'a mut impl FnMut(T) -> Option, - mut fold: impl FnMut(Acc, B) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => try { acc }, - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FilterMap -where - F: FnMut(I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - self.iter.find_map(&mut self.f) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, filter_map_fold(self.f, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for FilterMap -where - F: FnMut(I::Item) -> Option, -{ - #[inline] - fn next_back(&mut self) -> Option { - #[inline] - fn find( - f: &mut impl FnMut(T) -> Option, - ) -> impl FnMut((), T) -> ControlFlow + '_ { - move |(), x| match f(x) { - Some(x) => ControlFlow::Break(x), - None => ControlFlow::CONTINUE, - } - } - - self.iter.try_rfold((), find(&mut self.f)).break_value() - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, filter_map_fold(self.f, fold)) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for FilterMap -where - F: FnMut(I::Item) -> Option, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for FilterMap where - F: FnMut(I::Item) -> Option -{ -} - -/// An iterator that yields the current count and the element during iteration. -/// -/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`enumerate`]: Iterator::enumerate -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Enumerate { - iter: I, - count: usize, -} -impl Enumerate { - pub(super) fn new(iter: I) -> Enumerate { - Enumerate { iter, count: 0 } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Enumerate -where - I: Iterator, -{ - type Item = (usize, ::Item); - - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so enumerating more than - /// `usize::MAX` elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. - /// - /// # Panics - /// - /// Might panic if the index of the element overflows a `usize`. - #[inline] - fn next(&mut self) -> Option<(usize, ::Item)> { - let a = self.iter.next()?; - let i = self.count; - // Possible undefined overflow. - AddAssign::add_assign(&mut self.count, 1); - Some((i, a)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> { - let a = self.iter.nth(n)?; - // Possible undefined overflow. - let i = Add::add(self.count, n); - self.count = Add::add(i, 1); - Some((i, a)) - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - #[inline] - fn enumerate<'a, T, Acc, R>( - count: &'a mut usize, - mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a, - ) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| { - let acc = fold(acc, (*count, item)); - // Possible undefined overflow. - AddAssign::add_assign(count, 1); - acc - } - } - - self.iter.try_fold(init, enumerate(&mut self.count, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn enumerate( - mut count: usize, - mut fold: impl FnMut(Acc, (usize, T)) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| { - let acc = fold(acc, (count, item)); - // Possible undefined overflow. - AddAssign::add_assign(&mut count, 1); - acc - } - } - - self.iter.fold(init, enumerate(self.count, fold)) - } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; - (Add::add(self.count, idx), value) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Enumerate -where - I: ExactSizeIterator + DoubleEndedIterator, -{ - #[inline] - fn next_back(&mut self) -> Option<(usize, ::Item)> { - let a = self.iter.next_back()?; - let len = self.iter.len(); - // Can safely add, `ExactSizeIterator` promises that the number of - // elements fits into a `usize`. - Some((self.count + len, a)) - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<(usize, ::Item)> { - let a = self.iter.nth_back(n)?; - let len = self.iter.len(); - // Can safely add, `ExactSizeIterator` promises that the number of - // elements fits into a `usize`. - Some((self.count + len, a)) - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - // Can safely add and subtract the count, as `ExactSizeIterator` promises - // that the number of elements fits into a `usize`. - fn enumerate( - mut count: usize, - mut fold: impl FnMut(Acc, (usize, T)) -> R, - ) -> impl FnMut(Acc, T) -> R { - move |acc, item| { - count -= 1; - fold(acc, (count, item)) - } - } - - let count = self.count + self.iter.len(); - self.iter.try_rfold(init, enumerate(count, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - // Can safely add and subtract the count, as `ExactSizeIterator` promises - // that the number of elements fits into a `usize`. - fn enumerate( - mut count: usize, - mut fold: impl FnMut(Acc, (usize, T)) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| { - count -= 1; - fold(acc, (count, item)) - } - } - - let count = self.count + self.iter.len(); - self.iter.rfold(init, enumerate(count, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Enumerate -where - I: ExactSizeIterator, -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Enumerate -where - I: TrustedRandomAccess, -{ - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Enumerate where I: FusedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Enumerate where I: TrustedLen {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Enumerate -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Enumerate {} - -/// An iterator with a `peek()` that returns an optional reference to the next -/// element. -/// -/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`peekable`]: Iterator::peekable -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Peekable { - iter: I, - /// Remember a peeked value, even if it was None. - peeked: Option>, -} -impl Peekable { - pub(super) fn new(iter: I) -> Peekable { - Peekable { iter, peeked: None } - } -} - -// Peekable must remember if a None has been seen in the `.peek()` method. -// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the -// underlying iterator at most once. This does not by itself make the iterator -// fused. -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Peekable { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.peeked.take() { - Some(v) => v, - None => self.iter.next(), - } - } - - #[inline] - #[rustc_inherit_overflow_checks] - fn count(mut self) -> usize { - match self.peeked.take() { - Some(None) => 0, - Some(Some(_)) => 1 + self.iter.count(), - None => self.iter.count(), - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - match self.peeked.take() { - Some(None) => None, - Some(v @ Some(_)) if n == 0 => v, - Some(Some(_)) => self.iter.nth(n - 1), - None => self.iter.nth(n), - } - } - - #[inline] - fn last(mut self) -> Option { - let peek_opt = match self.peeked.take() { - Some(None) => return None, - Some(v) => v, - None => None, - }; - self.iter.last().or(peek_opt) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let peek_len = match self.peeked { - Some(None) => return (0, Some(0)), - Some(Some(_)) => 1, - None => 0, - }; - let (lo, hi) = self.iter.size_hint(); - let lo = lo.saturating_add(peek_len); - let hi = match hi { - Some(x) => x.checked_add(peek_len), - None => None, - }; - (lo, hi) - } - - #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - let acc = match self.peeked.take() { - Some(None) => return try { init }, - Some(Some(v)) => f(init, v)?, - None => init, - }; - self.iter.try_fold(acc, f) - } - - #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - let acc = match self.peeked { - Some(None) => return init, - Some(Some(v)) => fold(init, v), - None => init, - }; - self.iter.fold(acc, fold) - } -} - -#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")] -impl DoubleEndedIterator for Peekable -where - I: DoubleEndedIterator, -{ - #[inline] - fn next_back(&mut self) -> Option { - match self.peeked.as_mut() { - Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()), - Some(None) => None, - None => self.iter.next_back(), - } - } - - #[inline] - fn try_rfold(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, - { - match self.peeked.take() { - Some(None) => try { init }, - Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { - Ok(acc) => f(acc, v), - Err(e) => { - self.peeked = Some(Some(v)); - Try::from_error(e) - } - }, - None => self.iter.try_rfold(init, f), - } - } - - #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - match self.peeked { - Some(None) => init, - Some(Some(v)) => { - let acc = self.iter.rfold(init, &mut fold); - fold(acc, v) - } - None => self.iter.rfold(init, fold), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Peekable {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Peekable {} - -impl Peekable { - /// Returns a reference to the next() value without advancing the iterator. - /// - /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. - /// But if the iteration is over, `None` is returned. - /// - /// [`next`]: Iterator::next - /// - /// Because `peek()` returns a reference, and many iterators iterate over - /// references, there can be a possibly confusing situation where the - /// return value is a double reference. You can see this effect in the - /// examples below. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let xs = [1, 2, 3]; - /// - /// let mut iter = xs.iter().peekable(); - /// - /// // peek() lets us see into the future - /// assert_eq!(iter.peek(), Some(&&1)); - /// assert_eq!(iter.next(), Some(&1)); - /// - /// assert_eq!(iter.next(), Some(&2)); - /// - /// // The iterator does not advance even if we `peek` multiple times - /// assert_eq!(iter.peek(), Some(&&3)); - /// assert_eq!(iter.peek(), Some(&&3)); - /// - /// assert_eq!(iter.next(), Some(&3)); - /// - /// // After the iterator is finished, so is `peek()` - /// assert_eq!(iter.peek(), None); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn peek(&mut self) -> Option<&I::Item> { - let iter = &mut self.iter; - self.peeked.get_or_insert_with(|| iter.next()).as_ref() - } - - /// Consume and return the next value of this iterator if a condition is true. - /// - /// If `func` returns `true` for the next value of this iterator, consume and return it. - /// Otherwise, return `None`. - /// - /// # Examples - /// Consume a number if it's equal to 0. - /// ``` - /// #![feature(peekable_next_if)] - /// let mut iter = (0..5).peekable(); - /// // The first item of the iterator is 0; consume it. - /// assert_eq!(iter.next_if(|&x| x == 0), Some(0)); - /// // The next item returned is now 1, so `consume` will return `false`. - /// assert_eq!(iter.next_if(|&x| x == 0), None); - /// // `next_if` saves the value of the next item if it was not equal to `expected`. - /// assert_eq!(iter.next(), Some(1)); - /// ``` - /// - /// Consume any number less than 10. - /// ``` - /// #![feature(peekable_next_if)] - /// let mut iter = (1..20).peekable(); - /// // Consume all numbers less than 10 - /// while iter.next_if(|&x| x < 10).is_some() {} - /// // The next value returned will be 10 - /// assert_eq!(iter.next(), Some(10)); - /// ``` - #[unstable(feature = "peekable_next_if", issue = "72480")] - pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { - match self.next() { - Some(matched) if func(&matched) => Some(matched), - other => { - // Since we called `self.next()`, we consumed `self.peeked`. - assert!(self.peeked.is_none()); - self.peeked = Some(other); - None - } - } - } - - /// Consume and return the next item if it is equal to `expected`. - /// - /// # Example - /// Consume a number if it's equal to 0. - /// ``` - /// #![feature(peekable_next_if)] - /// let mut iter = (0..5).peekable(); - /// // The first item of the iterator is 0; consume it. - /// assert_eq!(iter.next_if_eq(&0), Some(0)); - /// // The next item returned is now 1, so `consume` will return `false`. - /// assert_eq!(iter.next_if_eq(&0), None); - /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. - /// assert_eq!(iter.next(), Some(1)); - /// ``` - #[unstable(feature = "peekable_next_if", issue = "72480")] - pub fn next_if_eq(&mut self, expected: &T) -> Option - where - T: ?Sized, - I::Item: PartialEq, - { - self.next_if(|next| next == expected) - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Peekable where I: TrustedLen {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Peekable -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Peekable {} - -/// An iterator that rejects elements while `predicate` returns `true`. -/// -/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`skip_while`]: Iterator::skip_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct SkipWhile { - iter: I, - flag: bool, - predicate: P, -} -impl SkipWhile { - pub(super) fn new(iter: I, predicate: P) -> SkipWhile { - SkipWhile { iter, flag: false, predicate } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SkipWhile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SkipWhile").field("iter", &self.iter).field("flag", &self.flag).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for SkipWhile -where - P: FnMut(&I::Item) -> bool, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - fn check<'a, T>( - flag: &'a mut bool, - pred: &'a mut impl FnMut(&T) -> bool, - ) -> impl FnMut(&T) -> bool + 'a { - move |x| { - if *flag || !pred(x) { - *flag = true; - true - } else { - false - } - } - } - - let flag = &mut self.flag; - let pred = &mut self.predicate; - self.iter.find(check(flag, pred)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - if !self.flag { - match self.next() { - Some(v) => init = fold(init, v)?, - None => return try { init }, - } - } - self.iter.try_fold(init, fold) - } - - #[inline] - fn fold(mut self, mut init: Acc, mut fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if !self.flag { - match self.next() { - Some(v) => init = fold(init, v), - None => return init, - } - } - self.iter.fold(init, fold) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SkipWhile -where - I: FusedIterator, - P: FnMut(&I::Item) -> bool, -{ -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for SkipWhile -where - P: FnMut(&I::Item) -> bool, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for SkipWhile where - F: FnMut(&I::Item) -> bool -{ -} - -/// An iterator that only accepts elements while `predicate` returns `true`. -/// -/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`take_while`]: Iterator::take_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct TakeWhile { - iter: I, - flag: bool, - predicate: P, -} -impl TakeWhile { - pub(super) fn new(iter: I, predicate: P) -> TakeWhile { - TakeWhile { iter, flag: false, predicate } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for TakeWhile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TakeWhile").field("iter", &self.iter).field("flag", &self.flag).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for TakeWhile -where - P: FnMut(&I::Item) -> bool, -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.flag { - None - } else { - let x = self.iter.next()?; - if (self.predicate)(&x) { - Some(x) - } else { - self.flag = true; - None - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.flag { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn check<'a, T, Acc, R: Try>( - flag: &'a mut bool, - p: &'a mut impl FnMut(&T) -> bool, - mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { - move |acc, x| { - if p(&x) { - ControlFlow::from_try(fold(acc, x)) - } else { - *flag = true; - ControlFlow::Break(try { acc }) - } - } - } - - if self.flag { - try { init } - } else { - let flag = &mut self.flag; - let p = &mut self.predicate; - self.iter.try_fold(init, check(flag, p, fold)).into_try() - } - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for TakeWhile -where - I: FusedIterator, - P: FnMut(&I::Item) -> bool, -{ -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for TakeWhile -where - P: FnMut(&I::Item) -> bool, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for TakeWhile where - F: FnMut(&I::Item) -> bool -{ -} - -/// An iterator that only accepts elements while `predicate` returns `Some(_)`. -/// -/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`map_while`]: Iterator::map_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] -#[derive(Clone)] -pub struct MapWhile { - iter: I, - predicate: P, -} - -impl MapWhile { - pub(super) fn new(iter: I, predicate: P) -> MapWhile { - MapWhile { iter, predicate } - } -} - -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] -impl fmt::Debug for MapWhile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MapWhile").field("iter", &self.iter).finish() - } -} - -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] -impl Iterator for MapWhile -where - P: FnMut(I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - let x = self.iter.next()?; - (self.predicate)(x) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - let Self { iter, predicate } = self; - iter.try_fold(init, |acc, x| match predicate(x) { - Some(item) => ControlFlow::from_try(fold(acc, item)), - None => ControlFlow::Break(try { acc }), - }) - .into_try() - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for MapWhile -where - P: FnMut(I::Item) -> Option, - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for MapWhile where - P: FnMut(I::Item) -> Option -{ -} - -/// An iterator that skips over `n` elements of `iter`. -/// -/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`skip`]: Iterator::skip -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Skip { - iter: I, - n: usize, -} -impl Skip { - pub(super) fn new(iter: I, n: usize) -> Skip { - Skip { iter, n } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Skip -where - I: Iterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.n == 0 { - self.iter.next() - } else { - let old_n = self.n; - self.n = 0; - self.iter.nth(old_n) - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - // Can't just add n + self.n due to overflow. - if self.n > 0 { - let to_skip = self.n; - self.n = 0; - // nth(n) skips n+1 - self.iter.nth(to_skip - 1)?; - } - self.iter.nth(n) - } - - #[inline] - fn count(mut self) -> usize { - if self.n > 0 { - // nth(n) skips n+1 - if self.iter.nth(self.n - 1).is_none() { - return 0; - } - } - self.iter.count() - } - - #[inline] - fn last(mut self) -> Option { - if self.n > 0 { - // nth(n) skips n+1 - self.iter.nth(self.n - 1)?; - } - self.iter.last() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.iter.size_hint(); - - let lower = lower.saturating_sub(self.n); - let upper = match upper { - Some(x) => Some(x.saturating_sub(self.n)), - None => None, - }; - - (lower, upper) - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - let n = self.n; - self.n = 0; - if n > 0 { - // nth(n) skips n+1 - if self.iter.nth(n - 1).is_none() { - return try { init }; - } - } - self.iter.try_fold(init, fold) - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if self.n > 0 { - // nth(n) skips n+1 - if self.iter.nth(self.n - 1).is_none() { - return init; - } - } - self.iter.fold(init, fold) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Skip where I: ExactSizeIterator {} - -#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")] -impl DoubleEndedIterator for Skip -where - I: DoubleEndedIterator + ExactSizeIterator, -{ - fn next_back(&mut self) -> Option { - if self.len() > 0 { self.iter.next_back() } else { None } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n < len { - self.iter.nth_back(n) - } else { - if len > 0 { - // consume the original iterator - self.iter.nth_back(len - 1); - } - None - } - } - - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn check>( - mut n: usize, - mut fold: impl FnMut(Acc, T) -> R, - ) -> impl FnMut(Acc, T) -> ControlFlow { - move |acc, x| { - n -= 1; - let r = fold(acc, x); - if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } - } - } - - let n = self.len(); - if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() } - } - - fn rfold(mut self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_rfold(init, ok(fold)).unwrap() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Skip where I: FusedIterator {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Skip -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Skip {} - -/// An iterator that only iterates over the first `n` iterations of `iter`. -/// -/// This `struct` is created by the [`take`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`take`]: Iterator::take -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Take { - pub(super) iter: I, - pub(super) n: usize, -} -impl Take { - pub(super) fn new(iter: I, n: usize) -> Take { - Take { iter, n } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Take -where - I: Iterator, -{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - if self.n != 0 { - self.n -= 1; - self.iter.next() - } else { - None - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - if self.n > n { - self.n -= n + 1; - self.iter.nth(n) - } else { - if self.n > 0 { - self.iter.nth(self.n - 1); - self.n = 0; - } - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.n == 0 { - return (0, Some(0)); - } - - let (lower, upper) = self.iter.size_hint(); - - let lower = cmp::min(lower, self.n); - - let upper = match upper { - Some(x) if x < self.n => Some(x), - _ => Some(self.n), - }; - - (lower, upper) - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn check<'a, T, Acc, R: Try>( - n: &'a mut usize, - mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { - move |acc, x| { - *n -= 1; - let r = fold(acc, x); - if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } - } - } - - if self.n == 0 { - try { init } - } else { - let n = &mut self.n; - self.iter.try_fold(init, check(n, fold)).into_try() - } - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Take -where - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Take {} - -#[stable(feature = "double_ended_take_iterator", since = "1.38.0")] -impl DoubleEndedIterator for Take -where - I: DoubleEndedIterator + ExactSizeIterator, -{ - #[inline] - fn next_back(&mut self) -> Option { - if self.n == 0 { - None - } else { - let n = self.n; - self.n -= 1; - self.iter.nth_back(self.iter.len().saturating_sub(n)) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.iter.len(); - if self.n > n { - let m = len.saturating_sub(self.n) + n; - self.n -= n + 1; - self.iter.nth_back(m) - } else { - if len > 0 { - self.iter.nth_back(len - 1); - } - None - } - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - if self.n == 0 { - try { init } - } else { - let len = self.iter.len(); - if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { - try { init } - } else { - self.iter.try_rfold(init, fold) - } - } - } - - #[inline] - fn rfold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if self.n == 0 { - init - } else { - let len = self.iter.len(); - if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { - init - } else { - self.iter.rfold(init, fold) - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Take where I: ExactSizeIterator {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Take where I: FusedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Take {} - -/// An iterator to maintain state while iterating another iterator. -/// -/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`scan`]: Iterator::scan -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Scan { - iter: I, - f: F, - state: St, -} -impl Scan { - pub(super) fn new(iter: I, state: St, f: F) -> Scan { - Scan { iter, state, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Scan { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Scan").field("iter", &self.iter).field("state", &self.state).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Scan -where - I: Iterator, - F: FnMut(&mut St, I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - let a = self.iter.next()?; - (self.f)(&mut self.state, a) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the scan function - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - fn scan<'a, T, St, B, Acc, R: Try>( - state: &'a mut St, - f: &'a mut impl FnMut(&mut St, T) -> Option, - mut fold: impl FnMut(Acc, B) -> R + 'a, - ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { - move |acc, x| match f(state, x) { - None => ControlFlow::Break(try { acc }), - Some(x) => ControlFlow::from_try(fold(acc, x)), - } - } - - let state = &mut self.state; - let f = &mut self.f; - self.iter.try_fold(init, scan(state, f, fold)).into_try() - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> Acc, - { - #[inline] - fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { - move |acc, x| Ok(f(acc, x)) - } - - self.try_fold(init, ok(fold)).unwrap() - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Scan -where - I: SourceIter, - F: FnMut(&mut St, I::Item) -> Option, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Scan where - F: FnMut(&mut St, I::Item) -> Option -{ -} - -/// An iterator that calls a function with a reference to each element before -/// yielding it. -/// -/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`inspect`]: Iterator::inspect -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Inspect { - iter: I, - f: F, -} -impl Inspect { - pub(super) fn new(iter: I, f: F) -> Inspect { - Inspect { iter, f } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Inspect { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Inspect").field("iter", &self.iter).finish() - } -} - -impl Inspect -where - F: FnMut(&I::Item), -{ - #[inline] - fn do_inspect(&mut self, elt: Option) -> Option { - if let Some(ref a) = elt { - (self.f)(a); - } - - elt - } -} - -fn inspect_fold( - mut f: impl FnMut(&T), - mut fold: impl FnMut(Acc, T) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, item| { - f(&item); - fold(acc, item) - } -} - -fn inspect_try_fold<'a, T, Acc, R>( - f: &'a mut impl FnMut(&T), - mut fold: impl FnMut(Acc, T) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| { - f(&item); - fold(acc, item) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Inspect -where - F: FnMut(&I::Item), -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - let next = self.iter.next(); - self.do_inspect(next) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold)) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, inspect_fold(self.f, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Inspect -where - F: FnMut(&I::Item), -{ - #[inline] - fn next_back(&mut self) -> Option { - let next = self.iter.next_back(); - self.do_inspect(next) - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R - where - Self: Sized, - Fold: FnMut(Acc, Self::Item) -> R, - R: Try, - { - self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold)) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, inspect_fold(self.f, fold)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Inspect -where - F: FnMut(&I::Item), -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Inspect where F: FnMut(&I::Item) {} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Inspect -where - F: FnMut(&I::Item), - I: SourceIter, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.iter) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Inspect where F: FnMut(&I::Item) {} - /// An iterator adapter that produces output as long as the underlying /// iterator produces `Result::Ok` values. /// diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs new file mode 100644 index 0000000000..2f8b9653c5 --- /dev/null +++ b/library/core/src/iter/adapters/peekable.rs @@ -0,0 +1,342 @@ +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::Try; + +/// An iterator with a `peek()` that returns an optional reference to the next +/// element. +/// +/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`peekable`]: Iterator::peekable +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Peekable { + iter: I, + /// Remember a peeked value, even if it was None. + peeked: Option>, +} + +impl Peekable { + pub(in crate::iter) fn new(iter: I) -> Peekable { + Peekable { iter, peeked: None } + } +} + +// Peekable must remember if a None has been seen in the `.peek()` method. +// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the +// underlying iterator at most once. This does not by itself make the iterator +// fused. +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Peekable { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.peeked.take() { + Some(v) => v, + None => self.iter.next(), + } + } + + #[inline] + #[rustc_inherit_overflow_checks] + fn count(mut self) -> usize { + match self.peeked.take() { + Some(None) => 0, + Some(Some(_)) => 1 + self.iter.count(), + None => self.iter.count(), + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + match self.peeked.take() { + Some(None) => None, + Some(v @ Some(_)) if n == 0 => v, + Some(Some(_)) => self.iter.nth(n - 1), + None => self.iter.nth(n), + } + } + + #[inline] + fn last(mut self) -> Option { + let peek_opt = match self.peeked.take() { + Some(None) => return None, + Some(v) => v, + None => None, + }; + self.iter.last().or(peek_opt) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let peek_len = match self.peeked { + Some(None) => return (0, Some(0)), + Some(Some(_)) => 1, + None => 0, + }; + let (lo, hi) = self.iter.size_hint(); + let lo = lo.saturating_add(peek_len); + let hi = match hi { + Some(x) => x.checked_add(peek_len), + None => None, + }; + (lo, hi) + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let acc = match self.peeked.take() { + Some(None) => return try { init }, + Some(Some(v)) => f(init, v)?, + None => init, + }; + self.iter.try_fold(acc, f) + } + + #[inline] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let acc = match self.peeked { + Some(None) => return init, + Some(Some(v)) => fold(init, v), + None => init, + }; + self.iter.fold(acc, fold) + } +} + +#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")] +impl DoubleEndedIterator for Peekable +where + I: DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + match self.peeked.as_mut() { + Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()), + Some(None) => None, + None => self.iter.next_back(), + } + } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + match self.peeked.take() { + Some(None) => try { init }, + Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { + Ok(acc) => f(acc, v), + Err(e) => { + self.peeked = Some(Some(v)); + Try::from_error(e) + } + }, + None => self.iter.try_rfold(init, f), + } + } + + #[inline] + fn rfold(self, init: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + match self.peeked { + Some(None) => init, + Some(Some(v)) => { + let acc = self.iter.rfold(init, &mut fold); + fold(acc, v) + } + None => self.iter.rfold(init, fold), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Peekable {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Peekable {} + +impl Peekable { + /// Returns a reference to the next() value without advancing the iterator. + /// + /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. + /// But if the iteration is over, `None` is returned. + /// + /// [`next`]: Iterator::next + /// + /// Because `peek()` returns a reference, and many iterators iterate over + /// references, there can be a possibly confusing situation where the + /// return value is a double reference. You can see this effect in the + /// examples below. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let xs = [1, 2, 3]; + /// + /// let mut iter = xs.iter().peekable(); + /// + /// // peek() lets us see into the future + /// assert_eq!(iter.peek(), Some(&&1)); + /// assert_eq!(iter.next(), Some(&1)); + /// + /// assert_eq!(iter.next(), Some(&2)); + /// + /// // The iterator does not advance even if we `peek` multiple times + /// assert_eq!(iter.peek(), Some(&&3)); + /// assert_eq!(iter.peek(), Some(&&3)); + /// + /// assert_eq!(iter.next(), Some(&3)); + /// + /// // After the iterator is finished, so is `peek()` + /// assert_eq!(iter.peek(), None); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn peek(&mut self) -> Option<&I::Item> { + let iter = &mut self.iter; + self.peeked.get_or_insert_with(|| iter.next()).as_ref() + } + + /// Returns a mutable reference to the next() value without advancing the iterator. + /// + /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. + /// But if the iteration is over, `None` is returned. + /// + /// Because `peek_mut()` returns a reference, and many iterators iterate over + /// references, there can be a possibly confusing situation where the + /// return value is a double reference. You can see this effect in the examples + /// below. + /// + /// [`next`]: Iterator::next + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(peekable_peek_mut)] + /// let mut iter = [1, 2, 3].iter().peekable(); + /// + /// // Like with `peek()`, we can see into the future without advancing the iterator. + /// assert_eq!(iter.peek_mut(), Some(&mut &1)); + /// assert_eq!(iter.peek_mut(), Some(&mut &1)); + /// assert_eq!(iter.next(), Some(&1)); + /// + /// // Peek into the iterator and set the value behind the mutable reference. + /// if let Some(p) = iter.peek_mut() { + /// assert_eq!(*p, &2); + /// *p = &5; + /// } + /// + /// // The value we put in reappears as the iterator continues. + /// assert_eq!(iter.collect::>(), vec![&5, &3]); + /// ``` + #[inline] + #[unstable(feature = "peekable_peek_mut", issue = "78302")] + pub fn peek_mut(&mut self) -> Option<&mut I::Item> { + let iter = &mut self.iter; + self.peeked.get_or_insert_with(|| iter.next()).as_mut() + } + + /// Consume and return the next value of this iterator if a condition is true. + /// + /// If `func` returns `true` for the next value of this iterator, consume and return it. + /// Otherwise, return `None`. + /// + /// # Examples + /// Consume a number if it's equal to 0. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (0..5).peekable(); + /// // The first item of the iterator is 0; consume it. + /// assert_eq!(iter.next_if(|&x| x == 0), Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(iter.next_if(|&x| x == 0), None); + /// // `next_if` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(iter.next(), Some(1)); + /// ``` + /// + /// Consume any number less than 10. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (1..20).peekable(); + /// // Consume all numbers less than 10 + /// while iter.next_if(|&x| x < 10).is_some() {} + /// // The next value returned will be 10 + /// assert_eq!(iter.next(), Some(10)); + /// ``` + #[unstable(feature = "peekable_next_if", issue = "72480")] + pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { + match self.next() { + Some(matched) if func(&matched) => Some(matched), + other => { + // Since we called `self.next()`, we consumed `self.peeked`. + assert!(self.peeked.is_none()); + self.peeked = Some(other); + None + } + } + } + + /// Consume and return the next item if it is equal to `expected`. + /// + /// # Example + /// Consume a number if it's equal to 0. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (0..5).peekable(); + /// // The first item of the iterator is 0; consume it. + /// assert_eq!(iter.next_if_eq(&0), Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(iter.next_if_eq(&0), None); + /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(iter.next(), Some(1)); + /// ``` + #[unstable(feature = "peekable_next_if", issue = "72480")] + pub fn next_if_eq(&mut self, expected: &T) -> Option + where + T: ?Sized, + I::Item: PartialEq, + { + self.next_if(|next| next == expected) + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Peekable where I: TrustedLen {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Peekable +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Peekable {} diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs new file mode 100644 index 0000000000..105ed40a3e --- /dev/null +++ b/library/core/src/iter/adapters/rev.rs @@ -0,0 +1,137 @@ +use crate::iter::{FusedIterator, TrustedLen}; +use crate::ops::Try; + +/// A double-ended iterator with the direction inverted. +/// +/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`rev`]: Iterator::rev +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Rev { + iter: T, +} + +impl Rev { + pub(in crate::iter) fn new(iter: T) -> Rev { + Rev { iter } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Rev +where + I: DoubleEndedIterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + self.iter.next_back() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_back_by(n) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<::Item> { + self.iter.nth_back(n) + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_rfold(init, f) + } + + fn fold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, f) + } + + #[inline] + fn find

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.iter.rfind(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Rev +where + I: DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Option<::Item> { + self.iter.next() + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_by(n) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<::Item> { + self.iter.nth(n) + } + + fn try_rfold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, f) + } + + fn rfold(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, f) + } + + fn rfind

["AVX512BW"]

+ + * [x] [`_mm512_abs_epi16`] + * [x] [`_mm512_mask_abs_epi16`] + * [x] [`_mm512_maskz_abs_epi16`] + * [x] [`_mm_mask_abs_epi16`] + * [x] [`_mm_maskz_abs_epi16`] + * [x] [`_mm256_mask_abs_epi16`] + * [x] [`_mm256_maskz_abs_epi16`] + * [x] [`_mm512_abs_epi8`] + * [x] [`_mm512_mask_abs_epi8`] + * [x] [`_mm512_maskz_abs_epi8`] + * [x] [`_mm_mask_abs_epi8`] + * [x] [`_mm_maskz_abs_epi8`] + * [x] [`_mm256_mask_abs_epi8`] + * [x] [`_mm256_maskz_abs_epi8`] + * [x] [`_mm512_add_epi16`] + * [x] [`_mm512_mask_add_epi16`] + * [x] [`_mm512_maskz_add_epi16`] + * [x] [`_mm_mask_add_epi16`] + * [x] [`_mm_maskz_add_epi16`] + * [x] [`_mm256_mask_add_epi16`] + * [x] [`_mm256_maskz_add_epi16`] + * [x] [`_mm512_add_epi8`] + * [x] [`_mm512_mask_add_epi8`] + * [x] [`_mm512_maskz_add_epi8`] + * [x] [`_mm_mask_add_epi8`] + * [x] [`_mm_maskz_add_epi8`] + * [x] [`_mm256_mask_add_epi8`] + * [x] [`_mm256_maskz_add_epi8`] + * [x] [`_mm512_adds_epi16`] + * [x] [`_mm512_mask_adds_epi16`] + * [x] [`_mm512_maskz_adds_epi16`] + * [x] [`_mm_mask_adds_epi16`] + * [x] [`_mm_maskz_adds_epi16`] + * [x] [`_mm256_mask_adds_epi16`] + * [x] [`_mm256_maskz_adds_epi16`] + * [x] [`_mm512_adds_epi8`] + * [x] [`_mm512_mask_adds_epi8`] + * [x] [`_mm512_maskz_adds_epi8`] + * [x] [`_mm_mask_adds_epi8`] + * [x] [`_mm_maskz_adds_epi8`] + * [x] [`_mm256_mask_adds_epi8`] + * [x] [`_mm256_maskz_adds_epi8`] + * [x] [`_mm512_adds_epu16`] + * [x] [`_mm512_mask_adds_epu16`] + * [x] [`_mm512_maskz_adds_epu16`] + * [x] [`_mm_mask_adds_epu16`] + * [x] [`_mm_maskz_adds_epu16`] + * [x] [`_mm256_mask_adds_epu16`] + * [x] [`_mm256_maskz_adds_epu16`] + * [x] [`_mm512_adds_epu8`] + * [x] [`_mm512_mask_adds_epu8`] + * [x] [`_mm512_maskz_adds_epu8`] + * [x] [`_mm_mask_adds_epu8`] + * [x] [`_mm_maskz_adds_epu8`] + * [x] [`_mm256_mask_adds_epu8`] + * [x] [`_mm256_maskz_adds_epu8`] + * [x] [`_mm512_alignr_epi8`] + * [x] [`_mm512_mask_alignr_epi8`] + * [x] [`_mm512_maskz_alignr_epi8`] + * [x] [`_mm512_avg_epu16`] + * [x] [`_mm512_mask_avg_epu16`] + * [x] [`_mm512_maskz_avg_epu16`] + * [x] [`_mm_mask_avg_epu16`] + * [x] [`_mm_maskz_avg_epu16`] + * [x] [`_mm256_mask_avg_epu16`] + * [x] [`_mm256_maskz_avg_epu16`] + * [x] [`_mm512_avg_epu8`] + * [x] [`_mm512_mask_avg_epu8`] + * [x] [`_mm512_maskz_avg_epu8`] + * [x] [`_mm_mask_avg_epu8`] + * [x] [`_mm_maskz_avg_epu8`] + * [x] [`_mm256_mask_avg_epu8`] + * [x] [`_mm256_maskz_avg_epu8`] + * [x] [`_mm512_mask_blend_epi16`] + * [x] [`_mm_mask_blend_epi16`] + * [x] [`_mm256_mask_blend_epi16`] + * [x] [`_mm512_mask_blend_epi8`] + * [x] [`_mm512_broadcastb_epi8`] + * [x] [`_mm_mask_blend_epi8`] + * [x] [`_mm256_mask_blend_epi8`] + * [x] [`_mm512_mask_broadcastb_epi8`] + * [x] [`_mm512_maskz_broadcastb_epi8`] + * [x] [`_mm_mask_broadcastb_epi8`] + * [x] [`_mm_maskz_broadcastb_epi8`] + * [x] [`_mm256_mask_broadcastb_epi8`] + * [x] [`_mm256_maskz_broadcastb_epi8`] + * [x] [`_mm512_broadcastw_epi16`] + * [x] [`_mm512_mask_broadcastw_epi16`] + * [x] [`_mm512_maskz_broadcastw_epi16`] + * [x] [`_mm_mask_broadcastw_epi16`] + * [x] [`_mm_maskz_broadcastw_epi16`] + * [x] [`_mm256_mask_broadcastw_epi16`] + * [x] [`_mm256_maskz_broadcastw_epi16`] + * [x] [`_mm512_bslli_epi128`] + * [x] [`_mm512_bsrli_epi128`] + * [x] [`_mm512_cmp_epi16_mask`] + * [x] [`_mm512_mask_cmp_epi16_mask`] + * [x] [`_mm512_cmp_epi8_mask`] + * [x] [`_mm512_mask_cmp_epi8_mask`] + * [x] [`_mm512_cmp_epu16_mask`] + * [x] [`_mm512_mask_cmp_epu16_mask`] + * [x] [`_mm512_cmp_epu8_mask`] + * [x] [`_mm512_mask_cmp_epu8_mask`] + * [x] [`_mm512_cmpeq_epi16_mask`] + * [x] [`_mm512_mask_cmpeq_epi16_mask`] + * [x] [`_mm512_cmpeq_epi8_mask`] + * [x] [`_mm512_mask_cmpeq_epi8_mask`] + * [x] [`_mm512_cmpeq_epu16_mask`] + * [x] [`_mm512_mask_cmpeq_epu16_mask`] + * [x] [`_mm512_cmpeq_epu8_mask`] + * [x] [`_mm512_mask_cmpeq_epu8_mask`] + * [x] [`_mm512_cmpge_epi16_mask`] + * [x] [`_mm512_mask_cmpge_epi16_mask`] + * [x] [`_mm512_cmpge_epi8_mask`] + * [x] [`_mm512_mask_cmpge_epi8_mask`] + * [x] [`_mm512_cmpge_epu16_mask`] + * [x] [`_mm512_mask_cmpge_epu16_mask`] + * [x] [`_mm512_cmpge_epu8_mask`] + * [x] [`_mm512_mask_cmpge_epu8_mask`] + * [x] [`_mm512_cmpgt_epi16_mask`] + * [x] [`_mm512_mask_cmpgt_epi16_mask`] + * [x] [`_mm512_cmpgt_epi8_mask`] + * [x] [`_mm512_mask_cmpgt_epi8_mask`] + * [x] [`_mm512_cmpgt_epu16_mask`] + * [x] [`_mm512_mask_cmpgt_epu16_mask`] + * [x] [`_mm512_cmpgt_epu8_mask`] + * [x] [`_mm512_mask_cmpgt_epu8_mask`] + * [x] [`_mm512_cmple_epi16_mask`] + * [x] [`_mm512_mask_cmple_epi16_mask`] + * [x] [`_mm512_cmple_epi8_mask`] + * [x] [`_mm512_mask_cmple_epi8_mask`] + * [x] [`_mm512_cmple_epu16_mask`] + * [x] [`_mm512_mask_cmple_epu16_mask`] + * [x] [`_mm512_cmple_epu8_mask`] + * [x] [`_mm512_mask_cmple_epu8_mask`] + * [x] [`_mm512_cmplt_epi16_mask`] + * [x] [`_mm512_mask_cmplt_epi16_mask`] + * [x] [`_mm512_cmplt_epi8_mask`] + * [x] [`_mm512_mask_cmplt_epi8_mask`] + * [x] [`_mm512_cmplt_epu16_mask`] + * [x] [`_mm512_mask_cmplt_epu16_mask`] + * [x] [`_mm512_cmplt_epu8_mask`] + * [x] [`_mm512_mask_cmplt_epu8_mask`] + * [x] [`_mm512_cmpneq_epi16_mask`] + * [x] [`_mm512_mask_cmpneq_epi16_mask`] + * [x] [`_mm512_cmpneq_epi8_mask`] + * [x] [`_mm512_mask_cmpneq_epi8_mask`] + * [x] [`_mm512_cmpneq_epu16_mask`] + * [x] [`_mm512_mask_cmpneq_epu16_mask`] + * [x] [`_mm512_cmpneq_epu8_mask`] + * [x] [`_mm512_mask_cmpneq_epu8_mask`] + * [x] [`_mm512_cvtepi16_epi8`] + * [x] [`_mm512_mask_cvtepi16_epi8`] + * [x] [`_mm512_maskz_cvtepi16_epi8`] + * [_] [`_mm512_mask_cvtepi16_storeu_epi8`] + * [x] [`_mm512_cvtepi8_epi16`] + * [x] [`_mm512_mask_cvtepi8_epi16`] + * [x] [`_mm512_maskz_cvtepi8_epi16`] + * [x] [`_mm512_cvtepu8_epi16`] + * [x] [`_mm512_mask_cvtepu8_epi16`] + * [x] [`_mm512_maskz_cvtepu8_epi16`] + * [_] [`_cvtmask32_u32`] + * [_] [`_cvtmask64_u64`] + * [x] [`_mm512_cvtsepi16_epi8`] + * [x] [`_mm512_mask_cvtsepi16_epi8`] + * [x] [`_mm512_maskz_cvtsepi16_epi8`] + * [_] [`_mm512_mask_cvtsepi16_storeu_epi8`] + * [_] [`_cvtu32_mask32`] + * [_] [`_cvtu64_mask64`] + * [x] [`_mm512_cvtusepi16_epi8`] + * [x] [`_mm512_mask_cvtusepi16_epi8`] + * [x] [`_mm512_maskz_cvtusepi16_epi8`] + * [_] [`_mm512_mask_cvtusepi16_storeu_epi8`] + * [x] [`_mm512_dbsad_epu8`] + * [x] [`_mm512_mask_dbsad_epu8`] + * [x] [`_mm512_maskz_dbsad_epu8`] + * [x] [`_kadd_mask32`] + * [x] [`_kadd_mask64`] + * [x] [`_kand_mask32`] + * [x] [`_kand_mask64`] + * [x] [`_kandn_mask32`] + * [x] [`_kandn_mask64`] + * [x] [`_knot_mask32`] + * [x] [`_knot_mask64`] + * [x] [`_kor_mask32`] + * [x] [`_kor_mask64`] + * [_] [`_kortest_mask32_u8`] + * [_] [`_kortest_mask64_u8`] + * [_] [`_kortestc_mask32_u8`] + * [_] [`_kortestc_mask64_u8`] + * [_] [`_kortestz_mask32_u8`] + * [_] [`_kortestz_mask64_u8`] + * [_] [`_kshiftli_mask32`] + * [_] [`_kshiftli_mask64`] + * [_] [`_kshiftri_mask32`] + * [_] [`_kshiftri_mask64`] + * [_] [`_ktest_mask32_u8`] + * [_] [`_ktest_mask64_u8`] + * [_] [`_ktestc_mask32_u8`] + * [_] [`_ktestc_mask64_u8`] + * [_] [`_ktestz_mask32_u8`] + * [_] [`_ktestz_mask64_u8`] + * [_] [`_mm512_kunpackd`] + * [_] [`_mm512_kunpackw`] + * [x] [`_kxnor_mask32`] + * [x] [`_kxnor_mask64`] + * [x] [`_kxor_mask32`] + * [x] [`_kxor_mask64`] + * [x] [`_load_mask32`] + * [x] [`_load_mask64`] + * [x] [`_mm512_loadu_epi16`] + * [_] [`_mm512_mask_loadu_epi16`] + * [_] [`_mm512_maskz_loadu_epi16`] + * [x] [`_mm512_loadu_epi8`] + * [_] [`_mm512_mask_loadu_epi8`] + * [_] [`_mm512_maskz_loadu_epi8`] + * [x] [`_mm512_madd_epi16`] + * [x] [`_mm512_mask_madd_epi16`] + * [x] [`_mm512_maskz_madd_epi16`] + * [x] [`_mm_mask_madd_epi16`] + * [x] [`_mm_maskz_madd_epi16`] + * [x] [`_mm256_mask_madd_epi16`] + * [x] [`_mm256_maskz_madd_epi16`] + * [x] [`_mm512_maddubs_epi16`] + * [x] [`_mm512_mask_maddubs_epi16`] + * [x] [`_mm512_maskz_maddubs_epi16`] + * [x] [`_mm_mask_maddubs_epi16`] + * [x] [`_mm_maskz_maddubs_epi16`] + * [x] [`_mm256_mask_maddubs_epi16`] + * [x] [`_mm256_maskz_maddubs_epi16`] + * [x] [`_mm512_mask_max_epi16`] + * [x] [`_mm512_maskz_max_epi16`] + * [x] [`_mm512_max_epi16`] + * [x] [`_mm_mask_max_epi16`] + * [x] [`_mm_maskz_max_epi16`] + * [x] [`_mm256_mask_max_epi16`] + * [x] [`_mm256_maskz_max_epi16`] + * [x] [`_mm512_mask_max_epi8`] + * [x] [`_mm512_maskz_max_epi8`] + * [x] [`_mm512_max_epi8`] + * [x] [`_mm_mask_max_epi8`] + * [x] [`_mm_maskz_max_epi8`] + * [x] [`_mm256_mask_max_epi8`] + * [x] [`_mm256_maskz_max_epi8`] + * [x] [`_mm512_mask_max_epu16`] + * [x] [`_mm512_maskz_max_epu16`] + * [x] [`_mm512_max_epu16`] + * [x] [`_mm_mask_max_epu16`] + * [x] [`_mm_maskz_max_epu16`] + * [x] [`_mm256_mask_max_epu16`] + * [x] [`_mm256_maskz_max_epu16`] + * [x] [`_mm512_mask_max_epu8`] + * [x] [`_mm512_maskz_max_epu8`] + * [x] [`_mm512_max_epu8`] + * [x] [`_mm_mask_max_epu8`] + * [x] [`_mm_maskz_max_epu8`] + * [x] [`_mm256_mask_max_epu8`] + * [x] [`_mm256_maskz_max_epu8`] + * [x] [`_mm512_mask_min_epi16`] + * [x] [`_mm512_maskz_min_epi16`] + * [x] [`_mm512_min_epi16`] + * [x] [`_mm_mask_min_epi16`] + * [x] [`_mm_maskz_min_epi16`] + * [x] [`_mm256_mask_min_epi16`] + * [x] [`_mm256_maskz_min_epi16`] + * [x] [`_mm512_mask_min_epi8`] + * [x] [`_mm512_maskz_min_epi8`] + * [x] [`_mm512_min_epi8`] + * [x] [`_mm_mask_min_epi8`] + * [x] [`_mm_maskz_min_epi8`] + * [x] [`_mm256_mask_min_epi8`] + * [x] [`_mm256_maskz_min_epi8`] + * [x] [`_mm512_mask_min_epu16`] + * [x] [`_mm512_maskz_min_epu16`] + * [x] [`_mm512_min_epu16`] + * [x] [`_mm_mask_min_epu16`] + * [x] [`_mm_maskz_min_epu16`] + * [x] [`_mm256_mask_min_epu16`] + * [x] [`_mm256_maskz_min_epu16`] + * [x] [`_mm512_mask_min_epu8`] + * [x] [`_mm512_maskz_min_epu8`] + * [x] [`_mm512_min_epu8`] + * [x] [`_mm_mask_min_epu8`] + * [x] [`_mm_maskz_min_epu8`] + * [x] [`_mm256_mask_min_epu8`] + * [x] [`_mm256_maskz_min_epu8`] + * [x] [`_mm512_mask_mov_epi16`] + * [x] [`_mm512_maskz_mov_epi16`] + * [x] [`_mm_mask_mov_epi16`] + * [x] [`_mm_maskz_mov_epi16`] + * [x] [`_mm256_mask_mov_epi16`] + * [x] [`_mm256_maskz_mov_epi16`] + * [x] [`_mm512_mask_mov_epi8`] + * [x] [`_mm512_maskz_mov_epi8`] + * [x] [`_mm_mask_mov_epi8`] + * [x] [`_mm_maskz_mov_epi8`] + * [x] [`_mm256_mask_mov_epi8`] + * [x] [`_mm256_maskz_mov_epi8`] + * [x] [`_mm512_movepi16_mask`] + * [x] [`_mm512_movepi8_mask`] + * [x] [`_mm512_movm_epi16`] + * [x] [`_mm512_movm_epi8`] + * [x] [`_mm512_mask_mulhi_epi16`] + * [x] [`_mm512_maskz_mulhi_epi16`] + * [x] [`_mm512_mulhi_epi16`] + * [x] [`_mm512_mask_mulhi_epu16`] + * [x] [`_mm512_maskz_mulhi_epu16`] + * [x] [`_mm_mask_mulhi_epi16`] + * [x] [`_mm_maskz_mulhi_epi16`] + * [x] [`_mm256_mask_mulhi_epi16`] + * [x] [`_mm256_maskz_mulhi_epi16`] + * [x] [`_mm512_mulhi_epu16`] + * [x] [`_mm_mask_mulhi_epu16`] + * [x] [`_mm_maskz_mulhi_epu16`] + * [x] [`_mm256_mask_mulhi_epu16`] + * [x] [`_mm256_maskz_mulhi_epu16`] + * [x] [`_mm512_mask_mulhrs_epi16`] + * [x] [`_mm512_maskz_mulhrs_epi16`] + * [x] [`_mm512_mulhrs_epi16`] + * [x] [`_mm_mask_mulhrs_epi16`] + * [x] [`_mm_maskz_mulhrs_epi16`] + * [x] [`_mm256_mask_mulhrs_epi16`] + * [x] [`_mm256_maskz_mulhrs_epi16`] + * [x] [`_mm512_mask_mullo_epi16`] + * [x] [`_mm512_maskz_mullo_epi16`] + * [x] [`_mm512_mullo_epi16`] + * [x] [`_mm_mask_mullo_epi16`] + * [x] [`_mm_maskz_mullo_epi16`] + * [x] [`_mm256_mask_mullo_epi16`] + * [x] [`_mm256_maskz_mullo_epi16`] + * [x] [`_mm512_mask_packs_epi16`] + * [x] [`_mm512_maskz_packs_epi16`] + * [x] [`_mm512_packs_epi16`] + * [x] [`_mm_mask_packs_epi16`] + * [x] [`_mm_maskz_packs_epi16`] + * [x] [`_mm256_mask_packs_epi16`] + * [x] [`_mm256_maskz_packs_epi16`] + * [x] [`_mm512_mask_packs_epi32`] + * [x] [`_mm512_maskz_packs_epi32`] + * [x] [`_mm512_packs_epi32`] + * [x] [`_mm_mask_packs_epi32`] + * [x] [`_mm_maskz_packs_epi32`] + * [x] [`_mm256_mask_packs_epi32`] + * [x] [`_mm256_maskz_packs_epi32`] + * [x] [`_mm512_mask_packus_epi16`] + * [x] [`_mm512_maskz_packus_epi16`] + * [x] [`_mm512_packus_epi16`] + * [x] [`_mm_mask_packus_epi16`] + * [x] [`_mm_maskz_packus_epi16`] + * [x] [`_mm256_mask_packus_epi16`] + * [x] [`_mm256_maskz_packus_epi16`] + * [x] [`_mm512_mask_packus_epi32`] + * [x] [`_mm512_maskz_packus_epi32`] + * [x] [`_mm512_packus_epi32`] + * [x] [`_mm_mask_packus_epi32`] + * [x] [`_mm_maskz_packus_epi32`] + * [x] [`_mm256_mask_packus_epi32`] + * [x] [`_mm256_maskz_packus_epi32`] + * [x] [`_mm512_mask_permutex2var_epi16`] + * [x] [`_mm512_mask2_permutex2var_epi16`] + * [x] [`_mm512_maskz_permutex2var_epi16`] + * [x] [`_mm512_permutex2var_epi16`] + * [x] [`_mm_mask_permutex2var_epi16`] + * [x] [`_mm_mask2_permutex2var_epi16`] + * [x] [`_mm_maskz_permutex2var_epi16`] + * [x] [`_mm_permutex2var_epi16`] + * [x] [`_mm256_mask_permutex2var_epi16`] + * [x] [`_mm256_mask2_permutex2var_epi16`] + * [x] [`_mm256_maskz_permutex2var_epi16`] + * [x] [`_mm256_permutex2var_epi16`] + * [x] [`_mm512_mask_permutexvar_epi16`] + * [x] [`_mm512_maskz_permutexvar_epi16`] + * [x] [`_mm512_permutexvar_epi16`] + * [x] [`_mm_mask_permutexvar_epi16`] + * [x] [`_mm_maskz_permutexvar_epi16`] + * [x] [`_mm_permutexvar_epi16`] + * [x] [`_mm256_mask_permutexvar_epi16`] + * [x] [`_mm256_maskz_permutexvar_epi16`] + * [x] [`_mm256_permutexvar_epi16`] + * [x] [`_mm512_sad_epu8`] + * [x] [`_mm512_mask_set1_epi16`] + * [x] [`_mm512_maskz_set1_epi16`] + * [x] [`_mm_mask_set1_epi16`] + * [x] [`_mm_maskz_set1_epi16`] + * [x] [`_mm256_mask_set1_epi16`] + * [x] [`_mm256_maskz_set1_epi16`] + * [x] [`_mm512_mask_set1_epi8`] + * [x] [`_mm512_maskz_set1_epi8`] + * [x] [`_mm_mask_set1_epi8`] + * [x] [`_mm_maskz_set1_epi8`] + * [x] [`_mm256_mask_set1_epi8`] + * [x] [`_mm256_maskz_set1_epi8`] + * [x] [`_mm512_mask_shuffle_epi8`] + * [x] [`_mm512_maskz_shuffle_epi8`] + * [x] [`_mm512_shuffle_epi8`] + * [x] [`_mm512_mask_shufflehi_epi16`] + * [x] [`_mm512_maskz_shufflehi_epi16`] + * [x] [`_mm512_shufflehi_epi16`] + * [x] [`_mm512_mask_shufflelo_epi16`] + * [x] [`_mm512_maskz_shufflelo_epi16`] + * [x] [`_mm512_shufflelo_epi16`] + * [x] [`_mm512_mask_sll_epi16`] + * [x] [`_mm512_maskz_sll_epi16`] + * [x] [`_mm512_sll_epi16`] + * [x] [`_mm_mask_sll_epi16`] + * [x] [`_mm_maskz_sll_epi16`] + * [x] [`_mm256_mask_sll_epi16`] + * [x] [`_mm256_maskz_sll_epi16`] + * [x] [`_mm512_mask_slli_epi16`] + * [x] [`_mm512_maskz_slli_epi16`] + * [x] [`_mm512_slli_epi16`] + * [x] [`_mm_mask_slli_epi16 + * [x] [`_mm_maskz_slli_epi16 + * [x] [`_mm256_mask_slli_epi16 + * [x] [`_mm256_maskz_slli_epi16 + * [x] [`_mm512_mask_sllv_epi16`] + * [x] [`_mm512_maskz_sllv_epi16`] + * [x] [`_mm512_sllv_epi16`] + * [x] [`_mm_mask_sllv_epi16`] + * [x] [`_mm_maskz_sllv_epi16`] + * [x] [`_mm_sllv_epi16`] + * [x] [`_mm256_mask_sllv_epi16`] + * [x] [`_mm256_maskz_sllv_epi16`] + * [x] [`_mm256_sllv_epi16`] + * [x] [`_mm512_mask_sra_epi16`] + * [x] [`_mm512_maskz_sra_epi16`] + * [x] [`_mm512_sra_epi16`] + * [x] [`_mm_mask_sra_epi16`] + * [x] [`_mm_maskz_sra_epi16`] + * [x] [`_mm256_mask_sra_epi16`] + * [x] [`_mm256_maskz_sra_epi16`] + * [x] [`_mm512_mask_srai_epi16`] + * [x] [`_mm512_maskz_srai_epi16`] + * [x] [`_mm512_srai_epi16`] + * [x] [`_mm_mask_srai_epi16`] + * [x] [`_mm_maskz_srai_epi16`] + * [x] [`_mm256_mask_srai_epi16`] + * [x] [`_mm256_maskz_srai_epi16`] + * [x] [`_mm512_mask_srav_epi16`] + * [x] [`_mm512_maskz_srav_epi16`] + * [x] [`_mm512_srav_epi16`] + * [_] [`_mm_mask_srav_epi16`] + * [_] [`_mm_maskz_srav_epi16`] + * [_] [`_mm_srav_epi16`] + * [_] [`_mm256_mask_srav_epi16`] + * [_] [`_mm256_maskz_srav_epi16`] + * [_] [`_mm256_srav_epi16`] + * [x] [`_mm512_mask_srl_epi16`] + * [x] [`_mm512_maskz_srl_epi16`] + * [x] [`_mm512_srl_epi16`] + * [x] [`_mm_mask_srl_epi16`] + * [x] [`_mm_maskz_srl_epi16`] + * [x] [`_mm256_mask_srl_epi16`] + * [x] [`_mm256_maskz_srl_epi16`] + * [x] [`_mm512_mask_srli_epi16`] + * [x] [`_mm512_maskz_srli_epi16`] + * [x] [`_mm512_srli_epi16`] + * [x] [`_mm_mask_srli_epi16`] + * [x] [`_mm_maskz_srli_epi16`] + * [x] [`_mm256_mask_srli_epi16`] + * [x] [`_mm256_maskz_srli_epi16`] + * [x] [`_mm512_mask_srlv_epi16`] + * [x] [`_mm512_maskz_srlv_epi16`] + * [x] [`_mm512_srlv_epi16`] + * [x] [`_mm_mask_srlv_epi16`] + * [x] [`_mm_maskz_srlv_epi16`] + * [x] [`_mm_srlv_epi16`] + * [x] [`_mm256_mask_srlv_epi16`] + * [x] [`_mm256_maskz_srlv_epi16`] + * [x] [`_mm256_srlv_epi16`] + * [x] [`_store_mask32`] + * [x] [`_store_mask64`] + * [_] [`_mm512_mask_storeu_epi16`] + * [x] [`_mm512_storeu_epi16`] + * [_] [`_mm512_mask_storeu_epi8`] + * [x] [`_mm512_storeu_epi8`] + * [x] [`_mm512_mask_sub_epi16`] + * [x] [`_mm512_maskz_sub_epi16`] + * [x] [`_mm512_sub_epi16`] + * [x] [`_mm_mask_sub_epi16`] + * [x] [`_mm_maskz_sub_epi16`] + * [x] [`_mm256_mask_sub_epi16`] + * [x] [`_mm256_maskz_sub_epi16`] + * [x] [`_mm512_mask_sub_epi8`] + * [x] [`_mm512_maskz_sub_epi8`] + * [x] [`_mm_mask_sub_epi8`] + * [x] [`_mm_maskz_sub_epi8`] + * [x] [`_mm256_mask_sub_epi8`] + * [x] [`_mm256_maskz_sub_epi8`] + * [x] [`_mm512_sub_epi8`] + * [x] [`_mm512_mask_subs_epi16`] + * [x] [`_mm512_maskz_subs_epi16`] + * [x] [`_mm512_subs_epi16`] + * [x] [`_mm_mask_subs_epi16`] + * [x] [`_mm_maskz_subs_epi16`] + * [x] [`_mm256_mask_subs_epi16`] + * [x] [`_mm256_maskz_subs_epi16`] + * [x] [`_mm512_mask_subs_epi8`] + * [x] [`_mm512_maskz_subs_epi8`] + * [x] [`_mm512_subs_epi8`] + * [x] [`_mm_mask_subs_epi8`] + * [x] [`_mm_maskz_subs_epi8`] + * [x] [`_mm256_mask_subs_epi8`] + * [x] [`_mm256_maskz_subs_epi8`] + * [x] [`_mm512_mask_subs_epu16`] + * [x] [`_mm512_maskz_subs_epu16`] + * [x] [`_mm512_subs_epu16`] + * [x] [`_mm_mask_subs_epu16`] + * [x] [`_mm_maskz_subs_epu16`] + * [x] [`_mm256_mask_subs_epu16`] + * [x] [`_mm256_maskz_subs_epu16`] + * [x] [`_mm512_mask_subs_epu8`] + * [x] [`_mm512_maskz_subs_epu8`] + * [x] [`_mm512_subs_epu8`] + * [x] [`_mm_mask_subs_epu8`] + * [x] [`_mm_maskz_subs_epu8`] + * [x] [`_mm256_mask_subs_epu8`] + * [x] [`_mm256_maskz_subs_epu8`] + * [x] [`_mm512_mask_test_epi16_mask`] + * [x] [`_mm512_test_epi16_mask`] + * [x] [`_mm512_mask_test_epi8_mask`] + * [x] [`_mm512_test_epi8_mask`] + * [x] [`_mm512_mask_testn_epi16_mask`] + * [x] [`_mm512_testn_epi16_mask`] + * [x] [`_mm512_mask_testn_epi8_mask`] + * [x] [`_mm512_testn_epi8_mask`] + * [x] [`_mm512_mask_unpackhi_epi16`] + * [x] [`_mm512_maskz_unpackhi_epi16`] + * [x] [`_mm512_unpackhi_epi16`] + * [x] [`_mm_mask_unpackhi_epi16`] + * [x] [`_mm_maskz_unpackhi_epi16`] + * [x] [`_mm256_mask_unpackhi_epi16`] + * [x] [`_mm256_maskz_unpackhi_epi16`] + * [x] [`_mm512_mask_unpackhi_epi8`] + * [x] [`_mm512_maskz_unpackhi_epi8`] + * [x] [`_mm512_unpackhi_epi8`] + * [x] [`_mm_mask_unpackhi_epi8`] + * [x] [`_mm_maskz_unpackhi_epi8`] + * [x] [`_mm256_mask_unpackhi_epi8`] + * [x] [`_mm256_maskz_unpackhi_epi8`] + * [x] [`_mm512_mask_unpacklo_epi16`] + * [x] [`_mm512_maskz_unpacklo_epi16`] + * [x] [`_mm512_unpacklo_epi16`] + * [x] [`_mm_mask_unpacklo_epi16`] + * [x] [`_mm_maskz_unpacklo_epi16`] + * [x] [`_mm256_mask_unpacklo_epi16`] + * [x] [`_mm256_maskz_unpacklo_epi16`] + * [x] [`_mm512_mask_unpacklo_epi8`] + * [x] [`_mm512_maskz_unpacklo_epi8`] + * [x] [`_mm512_unpacklo_epi8`] + * [x] [`_mm_mask_unpacklo_epi8`] + * [x] [`_mm_maskz_unpacklo_epi8`] + * [x] [`_mm256_mask_unpacklo_epi8`] + * [x] [`_mm256_maskz_unpacklo_epi8`] + +

diff --git a/library/stdarch/crates/core_arch/avx512f.md b/library/stdarch/crates/core_arch/avx512f.md index f8612abba3..6dd08b67f6 100644 --- a/library/stdarch/crates/core_arch/avx512f.md +++ b/library/stdarch/crates/core_arch/avx512f.md @@ -10,8 +10,8 @@ * [x] [`_mm512_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_ps&expand=5236) * [x] [`_mm512_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_round_pd&expand=5236) * [x] [`_mm512_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_round_ps&expand=5236) - * [ ] [`_mm512_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi32&expand=5236) - * [ ] [`_mm512_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi64&expand=5236) + * [x] [`_mm512_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi32&expand=5236) + * [x] [`_mm512_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi64&expand=5236) * [x] [`_mm512_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_epi32&expand=5236) * [x] [`_mm512_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_epi64&expand=5236) * [x] [`_mm512_and_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_si512&expand=5236) @@ -92,52 +92,52 @@ * [x] [`_mm512_cmpord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpord_ps_mask&expand=5236) * [x] [`_mm512_cmpunord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_pd_mask&expand=5236) * [x] [`_mm512_cmpunord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_ps_mask&expand=5236) - * [ ] [`_mm512_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepi32_ps&expand=5236) - * [ ] [`_mm512_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepu32_ps&expand=5236) - * [ ] [`_mm512_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epi32&expand=5236) - * [ ] [`_mm512_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epu32&expand=5236) - * [ ] [`_mm512_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_ps&expand=5236) - * [ ] [`_mm512_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepi32_ps&expand=5236) + * [x] [`_mm512_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepu32_ps&expand=5236) + * [x] [`_mm512_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epi32&expand=5236) + * [x] [`_mm512_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epu32&expand=5236) + * [x] [`_mm512_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_ps&expand=5236) + * [x] [`_mm512_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundph_ps&expand=5236) * [x] [`_mm512_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_epi32&expand=5236) * [x] [`_mm512_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_epu32&expand=5236) * [x] [`_mm512_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_pd&expand=5236) - * [ ] [`_mm512_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_ph&expand=5236) - * [ ] [`_mm512_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi32&expand=5236) - * [ ] [`_mm512_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi64&expand=5236) - * [ ] [`_mm512_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi16&expand=5236) - * [ ] [`_mm512_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi64&expand=5236) - * [ ] [`_mm512_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi8&expand=5236) - * [ ] [`_mm512_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_pd&expand=5236) - * [ ] [`_mm512_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_ps&expand=5236) - * [ ] [`_mm512_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32lo_pd&expand=5236) - * [ ] [`_mm512_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi16&expand=5236) - * [ ] [`_mm512_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi32&expand=5236) - * [ ] [`_mm512_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi8&expand=5236) - * [ ] [`_mm512_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi32&expand=5236) - * [ ] [`_mm512_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi64&expand=5236) - * [ ] [`_mm512_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi32&expand=5236) - * [ ] [`_mm512_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi64&expand=5236) - * [ ] [`_mm512_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_epi64&expand=5236) - * [ ] [`_mm512_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_pd&expand=5236) - * [ ] [`_mm512_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_ps&expand=5236) - * [ ] [`_mm512_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32lo_pd&expand=5236) - * [ ] [`_mm512_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi32&expand=5236) - * [ ] [`_mm512_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_ph&expand=5236) + * [x] [`_mm512_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi32&expand=5236) + * [x] [`_mm512_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi64&expand=5236) + * [x] [`_mm512_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi16&expand=5236) + * [x] [`_mm512_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi64&expand=5236) + * [x] [`_mm512_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi8&expand=5236) + * [x] [`_mm512_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_pd&expand=5236) + * [x] [`_mm512_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_ps&expand=5236) + * [x] [`_mm512_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32lo_pd&expand=5236) + * [x] [`_mm512_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi16&expand=5236) + * [x] [`_mm512_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi32&expand=5236) + * [x] [`_mm512_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi8&expand=5236) + * [x] [`_mm512_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi32&expand=5236) + * [x] [`_mm512_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi64&expand=5236) + * [x] [`_mm512_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi32&expand=5236) + * [x] [`_mm512_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi64&expand=5236) + * [x] [`_mm512_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_epi64&expand=5236) + * [x] [`_mm512_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_pd&expand=5236) + * [x] [`_mm512_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_ps&expand=5236) + * [x] [`_mm512_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32lo_pd&expand=5236) + * [x] [`_mm512_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi32&expand=5236) + * [x] [`_mm512_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi64&expand=5236) * [x] [`_mm512_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_epi32&expand=5236) * [x] [`_mm512_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_epu32&expand=5236) - * [ ] [`_mm512_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_ps&expand=5236) - * [ ] [`_mm512_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_pslo&expand=5236) - * [ ] [`_mm512_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtph_ps&expand=5236) + * [x] [`_mm512_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_ps&expand=5236) + * [x] [`_mm512_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_pslo&expand=5236) + * [x] [`_mm512_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtph_ps&expand=5236) * [x] [`_mm512_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_epi32&expand=5236) * [x] [`_mm512_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_epu32&expand=5236) - * [ ] [`_mm512_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_pd&expand=5236) - * [ ] [`_mm512_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_ph&expand=5236) - * [ ] [`_mm512_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpslo_pd&expand=5236) - * [ ] [`_mm512_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi16&expand=5236) - * [ ] [`_mm512_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi8&expand=5236) - * [ ] [`_mm512_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi16&expand=5236) - * [ ] [`_mm512_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi32&expand=5236) - * [ ] [`_mm512_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi8&expand=5236) + * [x] [`_mm512_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_pd&expand=5236) + * [x] [`_mm512_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_ph&expand=5236) + * [x] [`_mm512_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpslo_pd&expand=5236) + * [x] [`_mm512_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi16&expand=5236) + * [x] [`_mm512_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi8&expand=5236) + * [x] [`_mm512_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi16&expand=5236) + * [x] [`_mm512_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi32&expand=5236) + * [x] [`_mm512_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi8&expand=5236) * [x] [`_mm512_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundpd_epi32&expand=5236) * [x] [`_mm512_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundpd_epu32&expand=5236) * [x] [`_mm512_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundps_epi32&expand=5236) @@ -146,23 +146,23 @@ * [x] [`_mm512_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttpd_epu32&expand=5236) * [x] [`_mm512_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttps_epi32&expand=5236) * [x] [`_mm512_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttps_epu32&expand=5236) - * [ ] [`_mm512_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi16&expand=5236) - * [ ] [`_mm512_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi8&expand=5236) - * [ ] [`_mm512_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi16&expand=5236) - * [ ] [`_mm512_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi32&expand=5236) - * [ ] [`_mm512_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi8&expand=5236) + * [x] [`_mm512_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi16&expand=5236) + * [x] [`_mm512_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi8&expand=5236) + * [x] [`_mm512_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi16&expand=5236) + * [x] [`_mm512_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi32&expand=5236) + * [x] [`_mm512_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi8&expand=5236) * [x] [`_mm512_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_pd&expand=5236) * [x] [`_mm512_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_ps&expand=5236) * [x] [`_mm512_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_round_pd&expand=5236) * [x] [`_mm512_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_round_ps&expand=5236) * [x] [`_mm512_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extractf32x4_ps&expand=5236) - * [ ] [`_mm512_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extractf64x4_pd&expand=5236) - * [ ] [`_mm512_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti32x4_epi32&expand=5236) - * [ ] [`_mm512_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti64x4_epi64&expand=5236) - * [ ] [`_mm512_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_pd&expand=5236) - * [ ] [`_mm512_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_ps&expand=5236) - * [ ] [`_mm512_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_pd&expand=5236) - * [ ] [`_mm512_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extractf64x4_pd&expand=5236) + * [x] [`_mm512_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti32x4_epi32&expand=5236) + * [x] [`_mm512_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti64x4_epi64&expand=5236) + * [x] [`_mm512_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_pd&expand=5236) + * [x] [`_mm512_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_ps&expand=5236) + * [x] [`_mm512_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_pd&expand=5236) + * [x] [`_mm512_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_ps&expand=5236) * [x] [`_mm512_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_pd&expand=5236) * [x] [`_mm512_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_ps&expand=5236) * [x] [`_mm512_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_round_pd&expand=5236) @@ -226,30 +226,32 @@ * [x] [`_mm512_insertf64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_insertf64x4&expand=5236) * [x] [`_mm512_inserti32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_inserti32x4&expand=5236) * [x] [`_mm512_inserti64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_inserti64x4&expand=5236) - * [ ] [`_mm512_int2mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_int2mask&expand=5236) + * [x] [`_mm512_int2mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_int2mask&expand=5236) * [x] [`_mm512_kand`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kand&expand=5236) * [x] [`_mm512_kandn`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kandn&expand=5236) * [x] [`_mm512_kmov`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kmov&expand=5236) * [x] [`_mm512_knot`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_knot&expand=5236) * [x] [`_mm512_kor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kor&expand=5236) - * [ ] [`_mm512_kortestc`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kortestc&expand=5236) + * [x] [`_mm512_kortestc`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kortestc&expand=5236) * [ ] [`_mm512_kortestz`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kortestz&expand=5236) - * [ ] [`_mm512_kunpackb`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kunpackb&expand=5236) + * [x] [`_mm512_kunpackb`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kunpackb&expand=5236) * [x] [`_mm512_kxnor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kxnor&expand=5236) * [x] [`_mm512_kxor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kxor&expand=5236) - * [ ] [`_mm512_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi32&expand=5236) - * [ ] [`_mm512_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi64&expand=5236) - * [ ] [`_mm512_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_pd&expand=5236) - * [ ] [`_mm512_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_ps&expand=5236) - * [ ] [`_mm512_load_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_si512&expand=5236) + * [x] [`_mm512_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi32&expand=5236) + * [x] [`_mm512_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi64&expand=5236) + * [x] [`_mm512_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_pd&expand=5236) + * [x] [`_mm512_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_ps&expand=5236) + * [x] [`_mm512_load_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_si512&expand=5236) * [x] [`_mm512_loadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_pd&expand=5236) * [x] [`_mm512_loadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_ps&expand=5236) - * [ ] [`_mm512_loadu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_si512&expand=5236) + * [x] [`_mm512_loadu_epi32`] + * [x] [`_mm512_loadu_epi64`] + * [x] [`_mm512_loadu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_si512&expand=5236) * [x] [`_mm512_mask2_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_epi32&expand=5236) * [x] [`_mm512_mask2_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_epi64&expand=5236) * [x] [`_mm512_mask2_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_pd&expand=5236) * [x] [`_mm512_mask2_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_ps&expand=5236) - * [ ] [`_mm512_mask2int`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2int&expand=5236) + * [x] [`_mm512_mask2int`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2int&expand=5236) * [x] [`_mm512_mask3_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_pd&expand=5236) * [x] [`_mm512_mask3_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_ps&expand=5236) * [x] [`_mm512_mask3_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_round_pd&expand=5236) @@ -284,8 +286,8 @@ * [x] [`_mm512_mask_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_ps&expand=5236) * [x] [`_mm512_mask_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_round_pd&expand=5236) * [x] [`_mm512_mask_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_round_ps&expand=5236) - * [ ] [`_mm512_mask_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi32&expand=5236) - * [ ] [`_mm512_mask_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi64&expand=5236) + * [x] [`_mm512_mask_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi32&expand=5236) + * [x] [`_mm512_mask_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi64&expand=5236) * [x] [`_mm512_mask_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_and_epi32&expand=5236) * [x] [`_mm512_mask_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_and_epi64&expand=5236) * [x] [`_mm512_mask_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_andnot_epi32&expand=5236) @@ -350,67 +352,67 @@ * [x] [`_mm512_mask_cmpord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpord_ps_mask&expand=5236) * [x] [`_mm512_mask_cmpunord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_pd_mask&expand=5236) * [x] [`_mm512_mask_cmpunord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_ps_mask&expand=5236) - * [ ] [`_mm512_mask_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi32&expand=5236) - * [ ] [`_mm512_mask_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi64&expand=5236) - * [ ] [`_mm512_mask_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_pd&expand=5236) - * [ ] [`_mm512_mask_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_ps&expand=5236) + * [x] [`_mm512_mask_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi32&expand=5236) + * [x] [`_mm512_mask_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi64&expand=5236) + * [x] [`_mm512_mask_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_pd&expand=5236) + * [x] [`_mm512_mask_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_ps&expand=5236) * [ ] [`_mm512_mask_compressstoreu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi32&expand=5236) * [ ] [`_mm512_mask_compressstoreu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi64&expand=5236) * [ ] [`_mm512_mask_compressstoreu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_pd&expand=5236) * [ ] [`_mm512_mask_compressstoreu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_ps&expand=5236) - * [ ] [`_mm512_mask_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepi32_ps&expand=5236) - * [ ] [`_mm512_mask_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepu32_ps&expand=5236) - * [ ] [`_mm512_mask_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epi32&expand=5236) - * [ ] [`_mm512_mask_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epu32&expand=5236) - * [ ] [`_mm512_mask_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_ps&expand=5236) - * [ ] [`_mm512_mask_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_mask_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepi32_ps&expand=5236) + * [x] [`_mm512_mask_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepu32_ps&expand=5236) + * [x] [`_mm512_mask_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epi32&expand=5236) + * [x] [`_mm512_mask_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epu32&expand=5236) + * [x] [`_mm512_mask_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_ps&expand=5236) + * [x] [`_mm512_mask_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundph_ps&expand=5236) * [x] [`_mm512_mask_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_epi32&expand=5236) * [x] [`_mm512_mask_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_epu32&expand=5236) - * [ ] [`_mm512_mask_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_pd&expand=5236) - * [ ] [`_mm512_mask_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_ph&expand=5236) - * [ ] [`_mm512_mask_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi32&expand=5236) - * [ ] [`_mm512_mask_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi64&expand=5236) - * [ ] [`_mm512_mask_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi16&expand=5236) - * [ ] [`_mm512_mask_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi64&expand=5236) - * [ ] [`_mm512_mask_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi8&expand=5236) - * [ ] [`_mm512_mask_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_pd&expand=5236) - * [ ] [`_mm512_mask_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_ps&expand=5236) + * [x] [`_mm512_mask_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_pd&expand=5236) + * [x] [`_mm512_mask_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_ph&expand=5236) + * [x] [`_mm512_mask_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi32&expand=5236) + * [x] [`_mm512_mask_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi64&expand=5236) + * [x] [`_mm512_mask_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi16&expand=5236) + * [x] [`_mm512_mask_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi64&expand=5236) + * [x] [`_mm512_mask_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi8&expand=5236) + * [x] [`_mm512_mask_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_pd&expand=5236) + * [x] [`_mm512_mask_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_ps&expand=5236) * [ ] [`_mm512_mask_cvtepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_storeu_epi16&expand=5236) * [ ] [`_mm512_mask_cvtepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_storeu_epi8&expand=5236) - * [ ] [`_mm512_mask_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32lo_pd&expand=5236) - * [ ] [`_mm512_mask_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi16&expand=5236) - * [ ] [`_mm512_mask_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi32&expand=5236) - * [ ] [`_mm512_mask_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi8&expand=5236) + * [x] [`_mm512_mask_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32lo_pd&expand=5236) + * [x] [`_mm512_mask_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi16&expand=5236) + * [x] [`_mm512_mask_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi32&expand=5236) + * [x] [`_mm512_mask_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi8&expand=5236) * [ ] [`_mm512_mask_cvtepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi16&expand=5236) * [ ] [`_mm512_mask_cvtepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi32&expand=5236) * [ ] [`_mm512_mask_cvtepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi8&expand=5236) - * [ ] [`_mm512_mask_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi32&expand=5236) - * [ ] [`_mm512_mask_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi64&expand=5236) - * [ ] [`_mm512_mask_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi32&expand=5236) - * [ ] [`_mm512_mask_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi64&expand=5236) - * [ ] [`_mm512_mask_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_epi64&expand=5236) - * [ ] [`_mm512_mask_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_pd&expand=5236) - * [ ] [`_mm512_mask_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_ps&expand=5236) - * [ ] [`_mm512_mask_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32lo_pd&expand=5236) - * [ ] [`_mm512_mask_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi32&expand=5236) - * [ ] [`_mm512_mask_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_mask_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi32&expand=5236) + * [x] [`_mm512_mask_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi64&expand=5236) + * [x] [`_mm512_mask_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi32&expand=5236) + * [x] [`_mm512_mask_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi64&expand=5236) + * [x] [`_mm512_mask_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_epi64&expand=5236) + * [x] [`_mm512_mask_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_pd&expand=5236) + * [x] [`_mm512_mask_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_ps&expand=5236) + * [x] [`_mm512_mask_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32lo_pd&expand=5236) + * [x] [`_mm512_mask_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi32&expand=5236) + * [x] [`_mm512_mask_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi64&expand=5236) * [x] [`_mm512_mask_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_epi32&expand=5236) * [x] [`_mm512_mask_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_epu32&expand=5236) - * [ ] [`_mm512_mask_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_ps&expand=5236) - * [ ] [`_mm512_mask_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_pslo&expand=5236) - * [ ] [`_mm512_mask_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtph_ps&expand=5236) + * [x] [`_mm512_mask_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_ps&expand=5236) + * [x] [`_mm512_mask_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_pslo&expand=5236) + * [x] [`_mm512_mask_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtph_ps&expand=5236) * [x] [`_mm512_mask_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_epi32&expand=5236) * [x] [`_mm512_mask_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_epu32&expand=5236) * [x] [`_mm512_mask_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_pd&expand=5236) - * [ ] [`_mm512_mask_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_ph&expand=5236) - * [ ] [`_mm512_mask_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpslo_pd&expand=5236) - * [ ] [`_mm512_mask_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi16&expand=5236) - * [ ] [`_mm512_mask_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi8&expand=5236) + * [x] [`_mm512_mask_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_ph&expand=5236) + * [x] [`_mm512_mask_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpslo_pd&expand=5236) + * [x] [`_mm512_mask_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi16&expand=5236) + * [x] [`_mm512_mask_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi8&expand=5236) * [ ] [`_mm512_mask_cvtsepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_storeu_epi16&expand=5236) * [ ] [`_mm512_mask_cvtsepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_storeu_epi8&expand=5236) - * [ ] [`_mm512_mask_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi16&expand=5236) - * [ ] [`_mm512_mask_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi32&expand=5236) - * [ ] [`_mm512_mask_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi8&expand=5236) + * [x] [`_mm512_mask_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi16&expand=5236) + * [x] [`_mm512_mask_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi32&expand=5236) + * [x] [`_mm512_mask_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi8&expand=5236) * [ ] [`_mm512_mask_cvtsepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi16&expand=5236) * [ ] [`_mm512_mask_cvtsepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi32&expand=5236) * [ ] [`_mm512_mask_cvtsepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi8&expand=5236) @@ -422,13 +424,13 @@ * [x] [`_mm512_mask_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttpd_epu32&expand=5236) * [x] [`_mm512_mask_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttps_epi32&expand=5236) * [x] [`_mm512_mask_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttps_epu32&expand=5236) - * [ ] [`_mm512_mask_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi16&expand=5236) - * [ ] [`_mm512_mask_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi8&expand=5236) + * [x] [`_mm512_mask_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi16&expand=5236) + * [x] [`_mm512_mask_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi8&expand=5236) * [ ] [`_mm512_mask_cvtusepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_storeu_epi16&expand=5236) * [ ] [`_mm512_mask_cvtusepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_storeu_epi8&expand=5236) - * [ ] [`_mm512_mask_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi16&expand=5236) - * [ ] [`_mm512_mask_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi32&expand=5236) - * [ ] [`_mm512_mask_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi8&expand=5236) + * [x] [`_mm512_mask_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi16&expand=5236) + * [x] [`_mm512_mask_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi32&expand=5236) + * [x] [`_mm512_mask_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi8&expand=5236) * [ ] [`_mm512_mask_cvtusepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi16&expand=5236) * [ ] [`_mm512_mask_cvtusepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi32&expand=5236) * [ ] [`_mm512_mask_cvtusepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi8&expand=5236) @@ -436,22 +438,22 @@ * [x] [`_mm512_mask_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_ps&expand=5236) * [x] [`_mm512_mask_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_round_pd&expand=5236) * [x] [`_mm512_mask_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_round_ps&expand=5236) - * [ ] [`_mm512_mask_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi32&expand=5236) - * [ ] [`_mm512_mask_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi64&expand=5236) - * [ ] [`_mm512_mask_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_pd&expand=5236) - * [ ] [`_mm512_mask_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_ps&expand=5236) + * [x] [`_mm512_mask_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi32&expand=5236) + * [x] [`_mm512_mask_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi64&expand=5236) + * [x] [`_mm512_mask_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_pd&expand=5236) + * [x] [`_mm512_mask_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_ps&expand=5236) * [ ] [`_mm512_mask_expandloadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi32&expand=5236) * [ ] [`_mm512_mask_expandloadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi64&expand=5236) * [ ] [`_mm512_mask_expandloadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_pd&expand=5236) * [ ] [`_mm512_mask_expandloadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_ps&expand=5236) - * [ ] [`_mm512_mask_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf32x4_ps&expand=5236) - * [ ] [`_mm512_mask_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf64x4_pd&expand=5236) - * [ ] [`_mm512_mask_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti32x4_epi32&expand=5236) - * [ ] [`_mm512_mask_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti64x4_epi64&expand=5236) - * [ ] [`_mm512_mask_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_pd&expand=5236) - * [ ] [`_mm512_mask_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_ps&expand=5236) - * [ ] [`_mm512_mask_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_pd&expand=5236) - * [ ] [`_mm512_mask_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_mask_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf32x4_ps&expand=5236) + * [x] [`_mm512_mask_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf64x4_pd&expand=5236) + * [x] [`_mm512_mask_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti32x4_epi32&expand=5236) + * [x] [`_mm512_mask_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti64x4_epi64&expand=5236) + * [x] [`_mm512_mask_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_pd&expand=5236) + * [x] [`_mm512_mask_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_ps&expand=5236) + * [x] [`_mm512_mask_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_pd&expand=5236) + * [x] [`_mm512_mask_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_ps&expand=5236) * [x] [`_mm512_mask_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_pd&expand=5236) * [x] [`_mm512_mask_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_ps&expand=5236) * [x] [`_mm512_mask_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_round_pd&expand=5236) @@ -539,10 +541,10 @@ * [x] [`_mm512_mask_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_ps&expand=5236) * [x] [`_mm512_mask_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_round_pd&expand=5236) * [x] [`_mm512_mask_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_round_ps&expand=5236) - * [ ] [`_mm512_mask_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi32&expand=5236) - * [ ] [`_mm512_mask_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi64&expand=5236) - * [ ] [`_mm512_mask_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_pd&expand=5236) - * [ ] [`_mm512_mask_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_ps&expand=5236) + * [x] [`_mm512_mask_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi32&expand=5236) + * [x] [`_mm512_mask_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi64&expand=5236) + * [x] [`_mm512_mask_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_pd&expand=5236) + * [x] [`_mm512_mask_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_ps&expand=5236) * [x] [`_mm512_mask_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_movedup_pd&expand=5236) * [x] [`_mm512_mask_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_movehdup_ps&expand=5236) * [x] [`_mm512_mask_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_moveldup_ps&expand=5236) @@ -573,30 +575,30 @@ * [x] [`_mm512_mask_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_ps&expand=5236) * [x] [`_mm512_mask_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rcp14_pd&expand=5236) * [x] [`_mm512_mask_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rcp14_ps&expand=5236) - * [ ] [`_mm512_mask_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi32&expand=5236) - * [ ] [`_mm512_mask_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi64&expand=5236) - * [ ] [`_mm512_mask_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_pd&expand=5236) - * [ ] [`_mm512_mask_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_ps&expand=5236) - * [ ] [`_mm512_mask_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi32&expand=5236) - * [ ] [`_mm512_mask_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi64&expand=5236) - * [ ] [`_mm512_mask_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi32&expand=5236) - * [ ] [`_mm512_mask_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi64&expand=5236) - * [ ] [`_mm512_mask_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu32&expand=5236) - * [ ] [`_mm512_mask_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu64&expand=5236) - * [ ] [`_mm512_mask_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_pd&expand=5236) - * [ ] [`_mm512_mask_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_ps&expand=5236) - * [ ] [`_mm512_mask_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi32&expand=5236) - * [ ] [`_mm512_mask_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi64&expand=5236) - * [ ] [`_mm512_mask_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu32&expand=5236) - * [ ] [`_mm512_mask_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu64&expand=5236) - * [ ] [`_mm512_mask_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_pd&expand=5236) - * [ ] [`_mm512_mask_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_ps&expand=5236) - * [ ] [`_mm512_mask_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi32&expand=5236) - * [ ] [`_mm512_mask_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi64&expand=5236) - * [ ] [`_mm512_mask_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_pd&expand=5236) - * [ ] [`_mm512_mask_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_ps&expand=5236) - * [ ] [`_mm512_mask_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi32&expand=5236) - * [ ] [`_mm512_mask_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi64&expand=5236) + * [x] [`_mm512_mask_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi32&expand=5236) + * [x] [`_mm512_mask_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi64&expand=5236) + * [x] [`_mm512_mask_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_pd&expand=5236) + * [x] [`_mm512_mask_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_ps&expand=5236) + * [x] [`_mm512_mask_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi32&expand=5236) + * [x] [`_mm512_mask_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi64&expand=5236) + * [x] [`_mm512_mask_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi32&expand=5236) + * [x] [`_mm512_mask_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi64&expand=5236) + * [x] [`_mm512_mask_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu32&expand=5236) + * [x] [`_mm512_mask_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu64&expand=5236) + * [x] [`_mm512_mask_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_pd&expand=5236) + * [x] [`_mm512_mask_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_ps&expand=5236) + * [x] [`_mm512_mask_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi32&expand=5236) + * [x] [`_mm512_mask_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi64&expand=5236) + * [x] [`_mm512_mask_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu32&expand=5236) + * [x] [`_mm512_mask_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu64&expand=5236) + * [x] [`_mm512_mask_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_pd&expand=5236) + * [x] [`_mm512_mask_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_ps&expand=5236) + * [x] [`_mm512_mask_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi32&expand=5236) + * [x] [`_mm512_mask_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi64&expand=5236) + * [x] [`_mm512_mask_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_pd&expand=5236) + * [x] [`_mm512_mask_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_ps&expand=5236) + * [x] [`_mm512_mask_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi32&expand=5236) + * [x] [`_mm512_mask_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi64&expand=5236) * [x] [`_mm512_mask_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rol_epi32&expand=5236) * [x] [`_mm512_mask_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rol_epi64&expand=5236) * [x] [`_mm512_mask_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rolv_epi32&expand=5236) @@ -605,16 +607,16 @@ * [x] [`_mm512_mask_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ror_epi64&expand=5236) * [x] [`_mm512_mask_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rorv_epi32&expand=5236) * [x] [`_mm512_mask_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rorv_epi64&expand=5236) - * [ ] [`_mm512_mask_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_pd&expand=5236) - * [ ] [`_mm512_mask_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_ps&expand=5236) - * [ ] [`_mm512_mask_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_pd&expand=5236) - * [ ] [`_mm512_mask_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_ps&expand=5236) + * [x] [`_mm512_mask_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_pd&expand=5236) + * [x] [`_mm512_mask_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_ps&expand=5236) + * [x] [`_mm512_mask_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_pd&expand=5236) + * [x] [`_mm512_mask_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_ps&expand=5236) * [x] [`_mm512_mask_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rsqrt14_pd&expand=5236) * [x] [`_mm512_mask_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rsqrt14_ps&expand=5236) - * [ ] [`_mm512_mask_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_pd&expand=5236) - * [ ] [`_mm512_mask_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_ps&expand=5236) - * [ ] [`_mm512_mask_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_pd&expand=5236) - * [ ] [`_mm512_mask_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_ps&expand=5236) + * [x] [`_mm512_mask_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_pd&expand=5236) + * [x] [`_mm512_mask_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_ps&expand=5236) + * [x] [`_mm512_mask_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_pd&expand=5236) + * [x] [`_mm512_mask_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_ps&expand=5236) * [x] [`_mm512_mask_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi32&expand=5236) * [x] [`_mm512_mask_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi64&expand=5236) * [x] [`_mm512_mask_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_epi32&expand=5236) @@ -660,12 +662,12 @@ * [x] [`_mm512_mask_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_ps&expand=5236) * [x] [`_mm512_mask_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_round_pd&expand=5236) * [x] [`_mm512_mask_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_round_ps&expand=5236) - * [ ] [`_mm512_mask_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi32&expand=5236) - * [ ] [`_mm512_mask_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi64&expand=5236) - * [ ] [`_mm512_mask_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi32_mask&expand=5236) - * [ ] [`_mm512_mask_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi64_mask&expand=5236) - * [ ] [`_mm512_mask_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi32_mask&expand=5236) - * [ ] [`_mm512_mask_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi64_mask&expand=5236) + * [x] [`_mm512_mask_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi32&expand=5236) + * [x] [`_mm512_mask_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi64&expand=5236) + * [x] [`_mm512_mask_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi32_mask&expand=5236) + * [x] [`_mm512_mask_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi64_mask&expand=5236) + * [x] [`_mm512_mask_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi32_mask&expand=5236) + * [x] [`_mm512_mask_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi64_mask&expand=5236) * [x] [`_mm512_mask_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi32&expand=5236) * [x] [`_mm512_mask_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi64&expand=5236) * [x] [`_mm512_mask_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_pd&expand=5236) @@ -684,8 +686,8 @@ * [x] [`_mm512_maskz_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_ps&expand=5236) * [x] [`_mm512_maskz_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_round_pd&expand=5236) * [x] [`_mm512_maskz_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_round_ps&expand=5236) - * [ ] [`_mm512_maskz_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi32&expand=5236) - * [ ] [`_mm512_maskz_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi64&expand=5236) + * [x] [`_mm512_maskz_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi32&expand=5236) + * [x] [`_mm512_maskz_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi64&expand=5236) * [x] [`_mm512_maskz_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_and_epi32&expand=5236) * [x] [`_mm512_maskz_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_and_epi64&expand=5236) * [x] [`_mm512_maskz_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_andnot_epi32&expand=5236) @@ -698,52 +700,52 @@ * [x] [`_mm512_maskz_broadcastq_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastq_epi64&expand=5236) * [x] [`_mm512_maskz_broadcastsd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastsd_pd&expand=5236) * [x] [`_mm512_maskz_broadcastss_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastss_ps&expand=5236) - * [ ] [`_mm512_maskz_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi32&expand=5236) - * [ ] [`_mm512_maskz_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi64&expand=5236) - * [ ] [`_mm512_maskz_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_pd&expand=5236) - * [ ] [`_mm512_maskz_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_ps&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepi32_ps&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepu32_ps&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epu32&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_ps&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_maskz_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi32&expand=5236) + * [x] [`_mm512_maskz_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi64&expand=5236) + * [x] [`_mm512_maskz_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_pd&expand=5236) + * [x] [`_mm512_maskz_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_ps&expand=5236) + * [x] [`_mm512_maskz_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepi32_ps&expand=5236) + * [x] [`_mm512_maskz_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepu32_ps&expand=5236) + * [x] [`_mm512_maskz_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epi32&expand=5236) + * [x] [`_mm512_maskz_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epu32&expand=5236) + * [x] [`_mm512_maskz_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_ps&expand=5236) + * [x] [`_mm512_maskz_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundph_ps&expand=5236) * [x] [`_mm512_maskz_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_epi32&expand=5236) * [x] [`_mm512_maskz_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_epu32&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_pd&expand=5236) - * [ ] [`_mm512_maskz_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_ph&expand=5236) - * [ ] [`_mm512_maskz_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi64&expand=5236) - * [ ] [`_mm512_maskz_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi16&expand=5236) - * [ ] [`_mm512_maskz_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi64&expand=5236) - * [ ] [`_mm512_maskz_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi8&expand=5236) - * [ ] [`_mm512_maskz_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_pd&expand=5236) - * [ ] [`_mm512_maskz_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_ps&expand=5236) - * [ ] [`_mm512_maskz_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi16&expand=5236) - * [ ] [`_mm512_maskz_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi8&expand=5236) - * [ ] [`_mm512_maskz_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi64&expand=5236) - * [ ] [`_mm512_maskz_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi64&expand=5236) - * [ ] [`_mm512_maskz_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_epi64&expand=5236) - * [ ] [`_mm512_maskz_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_pd&expand=5236) - * [ ] [`_mm512_maskz_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_ps&expand=5236) - * [ ] [`_mm512_maskz_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_maskz_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_pd&expand=5236) + * [x] [`_mm512_maskz_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_ph&expand=5236) + * [x] [`_mm512_maskz_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi64&expand=5236) + * [x] [`_mm512_maskz_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi16&expand=5236) + * [x] [`_mm512_maskz_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi64&expand=5236) + * [x] [`_mm512_maskz_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_pd&expand=5236) + * [x] [`_mm512_maskz_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_ps&expand=5236) + * [x] [`_mm512_maskz_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi16&expand=5236) + * [x] [`_mm512_maskz_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi64&expand=5236) + * [x] [`_mm512_maskz_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi64&expand=5236) + * [x] [`_mm512_maskz_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_epi64&expand=5236) + * [x] [`_mm512_maskz_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_pd&expand=5236) + * [x] [`_mm512_maskz_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_ps&expand=5236) + * [x] [`_mm512_maskz_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi64&expand=5236) * [x] [`_mm512_maskz_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_epi32&expand=5236) * [x] [`_mm512_maskz_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_epu32&expand=5236) - * [ ] [`_mm512_maskz_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_ps&expand=5236) - * [ ] [`_mm512_maskz_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtph_ps&expand=5236) + * [x] [`_mm512_maskz_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_ps&expand=5236) + * [x] [`_mm512_maskz_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtph_ps&expand=5236) * [x] [`_mm512_maskz_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_epi32&expand=5236) * [x] [`_mm512_maskz_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_epu32&expand=5236) - * [ ] [`_mm512_maskz_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_pd&expand=5236) - * [ ] [`_mm512_maskz_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_ph&expand=5236) - * [ ] [`_mm512_maskz_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi16&expand=5236) - * [ ] [`_mm512_maskz_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi8&expand=5236) - * [ ] [`_mm512_maskz_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi16&expand=5236) - * [ ] [`_mm512_maskz_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_pd&expand=5236) + * [x] [`_mm512_maskz_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_ph&expand=5236) + * [x] [`_mm512_maskz_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi16&expand=5236) + * [x] [`_mm512_maskz_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi16&expand=5236) + * [x] [`_mm512_maskz_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi8&expand=5236) * [x] [`_mm512_maskz_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundpd_epi32&expand=5236) * [x] [`_mm512_maskz_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundpd_epu32&expand=5236) * [x] [`_mm512_maskz_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundps_epi32&expand=5236) @@ -752,31 +754,31 @@ * [x] [`_mm512_maskz_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttpd_epu32&expand=5236) * [x] [`_mm512_maskz_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttps_epi32&expand=5236) * [x] [`_mm512_maskz_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttps_epu32&expand=5236) - * [ ] [`_mm512_maskz_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi16&expand=5236) - * [ ] [`_mm512_maskz_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi8&expand=5236) - * [ ] [`_mm512_maskz_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi16&expand=5236) - * [ ] [`_mm512_maskz_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi32&expand=5236) - * [ ] [`_mm512_maskz_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi16&expand=5236) + * [x] [`_mm512_maskz_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi16&expand=5236) + * [x] [`_mm512_maskz_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi8&expand=5236) * [x] [`_mm512_maskz_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_pd&expand=5236) * [x] [`_mm512_maskz_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_ps&expand=5236) * [x] [`_mm512_maskz_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_round_pd&expand=5236) * [x] [`_mm512_maskz_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_round_ps&expand=5236) - * [ ] [`_mm512_maskz_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi32&expand=5236) - * [ ] [`_mm512_maskz_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi64&expand=5236) - * [ ] [`_mm512_maskz_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_pd&expand=5236) - * [ ] [`_mm512_maskz_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_ps&expand=5236) + * [x] [`_mm512_maskz_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi32&expand=5236) + * [x] [`_mm512_maskz_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi64&expand=5236) + * [x] [`_mm512_maskz_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_pd&expand=5236) + * [x] [`_mm512_maskz_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_ps&expand=5236) * [ ] [`_mm512_maskz_expandloadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi32&expand=5236) * [ ] [`_mm512_maskz_expandloadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi64&expand=5236) * [ ] [`_mm512_maskz_expandloadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_pd&expand=5236) * [ ] [`_mm512_maskz_expandloadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_ps&expand=5236) - * [ ] [`_mm512_maskz_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf32x4_ps&expand=5236) - * [ ] [`_mm512_maskz_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf64x4_pd&expand=5236) - * [ ] [`_mm512_maskz_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti32x4_epi32&expand=5236) - * [ ] [`_mm512_maskz_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti64x4_epi64&expand=5236) - * [ ] [`_mm512_maskz_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_pd&expand=5236) - * [ ] [`_mm512_maskz_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_ps&expand=5236) - * [ ] [`_mm512_maskz_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_pd&expand=5236) - * [ ] [`_mm512_maskz_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_maskz_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf32x4_ps&expand=5236) + * [x] [`_mm512_maskz_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf64x4_pd&expand=5236) + * [x] [`_mm512_maskz_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti32x4_epi32&expand=5236) + * [x] [`_mm512_maskz_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti64x4_epi64&expand=5236) + * [x] [`_mm512_maskz_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_pd&expand=5236) + * [x] [`_mm512_maskz_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_ps&expand=5236) + * [x] [`_mm512_maskz_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_pd&expand=5236) + * [x] [`_mm512_maskz_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_ps&expand=5236) * [x] [`_mm512_maskz_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_pd&expand=5236) * [x] [`_mm512_maskz_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_ps&expand=5236) * [x] [`_mm512_maskz_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_round_pd&expand=5236) @@ -837,10 +839,10 @@ * [x] [`_mm512_maskz_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_ps&expand=5236) * [x] [`_mm512_maskz_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_round_pd&expand=5236) * [x] [`_mm512_maskz_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_round_ps&expand=5236) - * [ ] [`_mm512_maskz_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi32&expand=5236) - * [ ] [`_mm512_maskz_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi64&expand=5236) - * [ ] [`_mm512_maskz_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_pd&expand=5236) - * [ ] [`_mm512_maskz_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_ps&expand=5236) + * [x] [`_mm512_maskz_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi32&expand=5236) + * [x] [`_mm512_maskz_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi64&expand=5236) + * [x] [`_mm512_maskz_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_pd&expand=5236) + * [x] [`_mm512_maskz_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_ps&expand=5236) * [x] [`_mm512_maskz_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_movedup_pd&expand=5236) * [x] [`_mm512_maskz_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_movehdup_ps&expand=5236) * [x] [`_mm512_maskz_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_moveldup_ps&expand=5236) @@ -877,18 +879,18 @@ * [x] [`_mm512_maskz_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ror_epi64&expand=5236) * [x] [`_mm512_maskz_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rorv_epi32&expand=5236) * [x] [`_mm512_maskz_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rorv_epi64&expand=5236) - * [ ] [`_mm512_maskz_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_pd&expand=5236) - * [ ] [`_mm512_maskz_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_ps&expand=5236) - * [ ] [`_mm512_maskz_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_pd&expand=5236) - * [ ] [`_mm512_maskz_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_ps&expand=5236) + * [x] [`_mm512_maskz_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_pd&expand=5236) + * [x] [`_mm512_maskz_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_ps&expand=5236) + * [x] [`_mm512_maskz_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_pd&expand=5236) + * [x] [`_mm512_maskz_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_ps&expand=5236) * [x] [`_mm512_maskz_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rsqrt14_pd&expand=5236) * [x] [`_mm512_maskz_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rsqrt14_ps&expand=5236) - * [ ] [`_mm512_maskz_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_pd&expand=5236) - * [ ] [`_mm512_maskz_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_ps&expand=5236) - * [ ] [`_mm512_maskz_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_pd&expand=5236) - * [ ] [`_mm512_maskz_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_ps&expand=5236) - * [ ] [`_mm512_maskz_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi32&expand=5236) - * [ ] [`_mm512_maskz_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi64&expand=5236) + * [x] [`_mm512_maskz_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_pd&expand=5236) + * [x] [`_mm512_maskz_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_ps&expand=5236) + * [x] [`_mm512_maskz_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_pd&expand=5236) + * [x] [`_mm512_maskz_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_ps&expand=5236) + * [x] [`_mm512_maskz_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi32&expand=5236) + * [x] [`_mm512_maskz_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi64&expand=5236) * [x] [`_mm512_maskz_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_epi32&expand=5236) * [x] [`_mm512_maskz_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_f32x4&expand=5236) * [x] [`_mm512_maskz_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_f64x2&expand=5236) @@ -924,8 +926,8 @@ * [x] [`_mm512_maskz_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_ps&expand=5236) * [x] [`_mm512_maskz_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_round_pd&expand=5236) * [x] [`_mm512_maskz_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_round_ps&expand=5236) - * [ ] [`_mm512_maskz_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi32&expand=5236) - * [ ] [`_mm512_maskz_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi64&expand=5236) + * [x] [`_mm512_maskz_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi32&expand=5236) + * [x] [`_mm512_maskz_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi64&expand=5236) * [x] [`_mm512_maskz_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi32&expand=5236) * [x] [`_mm512_maskz_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi64&expand=5236) * [x] [`_mm512_maskz_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_pd&expand=5236) @@ -983,30 +985,30 @@ * [x] [`_mm512_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_ps&expand=5236) * [x] [`_mm512_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rcp14_pd&expand=5236) * [x] [`_mm512_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rcp14_ps&expand=5236) - * [ ] [`_mm512_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi32&expand=5236) - * [ ] [`_mm512_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi64&expand=5236) - * [ ] [`_mm512_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_pd&expand=5236) - * [ ] [`_mm512_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_ps&expand=5236) - * [ ] [`_mm512_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi32&expand=5236) - * [ ] [`_mm512_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi64&expand=5236) - * [ ] [`_mm512_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi32&expand=5236) - * [ ] [`_mm512_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi64&expand=5236) - * [ ] [`_mm512_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu32&expand=5236) - * [ ] [`_mm512_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu64&expand=5236) - * [ ] [`_mm512_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_pd&expand=5236) - * [ ] [`_mm512_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_ps&expand=5236) - * [ ] [`_mm512_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi32&expand=5236) - * [ ] [`_mm512_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi64&expand=5236) - * [ ] [`_mm512_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu32&expand=5236) - * [ ] [`_mm512_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu64&expand=5236) - * [ ] [`_mm512_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_pd&expand=5236) - * [ ] [`_mm512_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_ps&expand=5236) - * [ ] [`_mm512_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi32&expand=5236) - * [ ] [`_mm512_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi64&expand=5236) - * [ ] [`_mm512_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_pd&expand=5236) - * [ ] [`_mm512_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_ps&expand=5236) - * [ ] [`_mm512_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi32&expand=5236) - * [ ] [`_mm512_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi64&expand=5236) + * [x] [`_mm512_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi32&expand=5236) + * [x] [`_mm512_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi64&expand=5236) + * [x] [`_mm512_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_pd&expand=5236) + * [x] [`_mm512_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_ps&expand=5236) + * [x] [`_mm512_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi32&expand=5236) + * [x] [`_mm512_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi64&expand=5236) + * [x] [`_mm512_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi32&expand=5236) + * [x] [`_mm512_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi64&expand=5236) + * [x] [`_mm512_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu32&expand=5236) + * [x] [`_mm512_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu64&expand=5236) + * [x] [`_mm512_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_pd&expand=5236) + * [x] [`_mm512_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_ps&expand=5236) + * [x] [`_mm512_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi32&expand=5236) + * [x] [`_mm512_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi64&expand=5236) + * [x] [`_mm512_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu32&expand=5236) + * [x] [`_mm512_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu64&expand=5236) + * [x] [`_mm512_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_pd&expand=5236) + * [x] [`_mm512_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_ps&expand=5236) + * [x] [`_mm512_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi32&expand=5236) + * [x] [`_mm512_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi64&expand=5236) + * [x] [`_mm512_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_pd&expand=5236) + * [x] [`_mm512_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_ps&expand=5236) + * [x] [`_mm512_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi32&expand=5236) + * [x] [`_mm512_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi64&expand=5236) * [x] [`_mm512_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rol_epi32&expand=5236) * [x] [`_mm512_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rol_epi64&expand=5236) * [x] [`_mm512_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rolv_epi32&expand=5236) @@ -1015,45 +1017,45 @@ * [x] [`_mm512_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ror_epi64&expand=5236) * [x] [`_mm512_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rorv_epi32&expand=5236) * [x] [`_mm512_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rorv_epi64&expand=5236) - * [ ] [`_mm512_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_pd&expand=5236) - * [ ] [`_mm512_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_ps&expand=5236) - * [ ] [`_mm512_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_pd&expand=5236) - * [ ] [`_mm512_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_ps&expand=5236) + * [x] [`_mm512_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_pd&expand=5236) + * [x] [`_mm512_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_ps&expand=5236) + * [x] [`_mm512_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_pd&expand=5236) + * [x] [`_mm512_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_ps&expand=5236) * [x] [`_mm512_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rsqrt14_pd&expand=5236) * [x] [`_mm512_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rsqrt14_ps&expand=5236) - * [ ] [`_mm512_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_pd&expand=5236) - * [ ] [`_mm512_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_ps&expand=5236) - * [ ] [`_mm512_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_pd&expand=5236) - * [ ] [`_mm512_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_ps&expand=5236) - * [ ] [`_mm512_set1_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi16&expand=5236) - * [ ] [`_mm512_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi32&expand=5236) - * [ ] [`_mm512_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi64&expand=5236) - * [ ] [`_mm512_set1_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi8&expand=5236) - * [ ] [`_mm512_set1_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_pd&expand=5236) - * [ ] [`_mm512_set1_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_ps&expand=5236) - * [ ] [`_mm512_set4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi32&expand=5236) - * [ ] [`_mm512_set4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi64&expand=5236) - * [ ] [`_mm512_set4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_pd&expand=5236) - * [ ] [`_mm512_set4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_ps&expand=5236) - * [ ] [`_mm512_set_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi16&expand=5236) - * [ ] [`_mm512_set_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi32&expand=5236) + * [x] [`_mm512_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_pd&expand=5236) + * [x] [`_mm512_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_ps&expand=5236) + * [x] [`_mm512_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_pd&expand=5236) + * [x] [`_mm512_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_ps&expand=5236) + * [x] [`_mm512_set1_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi16&expand=5236) + * [x] [`_mm512_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi32&expand=5236) + * [x] [`_mm512_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi64&expand=5236) + * [x] [`_mm512_set1_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi8&expand=5236) + * [x] [`_mm512_set1_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_pd&expand=5236) + * [x] [`_mm512_set1_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_ps&expand=5236) + * [x] [`_mm512_set4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi32&expand=5236) + * [x] [`_mm512_set4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi64&expand=5236) + * [x] [`_mm512_set4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_pd&expand=5236) + * [x] [`_mm512_set4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_ps&expand=5236) + * [x] [`_mm512_set_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi16&expand=5236) + * [x] [`_mm512_set_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi32&expand=5236) * [x] [`_mm512_set_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi64&expand=5236) - * [ ] [`_mm512_set_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi8&expand=5236) + * [x] [`_mm512_set_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi8&expand=5236) * [x] [`_mm512_set_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_pd&expand=5236) * [x] [`_mm512_set_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_ps&expand=5236) - * [ ] [`_mm512_setr4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi32&expand=5236) - * [ ] [`_mm512_setr4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi64&expand=5236) - * [ ] [`_mm512_setr4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_pd&expand=5236) - * [ ] [`_mm512_setr4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_ps&expand=5236) + * [x] [`_mm512_setr4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi32&expand=5236) + * [x] [`_mm512_setr4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi64&expand=5236) + * [x] [`_mm512_setr4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_pd&expand=5236) + * [x] [`_mm512_setr4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_ps&expand=5236) * [x] [`_mm512_setr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_epi32&expand=5236) * [x] [`_mm512_setr_epi64`](https:/software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_epi64&expand=5236) * [x] [`_mm512_setr_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_pd&expand=5236) * [x] [`_mm512_setr_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_ps&expand=5236) - * [ ] [`_mm512_setzero_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_epi32&expand=5236) + * [x] [`_mm512_setzero_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_epi32&expand=5236) * [x] [`_mm512_setzero_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_pd&expand=5236) * [x] [`_mm512_setzero_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_ps&expand=5236) * [x] [`_mm512_setzero_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_si512&expand=5236) - * [ ] [`_mm512_setzero`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero&expand=5236) + * [x] [`_mm512_setzero`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero&expand=5236) * [x] [`_mm512_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_epi32&expand=5236) * [x] [`_mm512_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_f32x4&expand=5236) * [x] [`_mm512_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_f64x2&expand=5236) @@ -1083,18 +1085,20 @@ * [x] [`_mm512_srli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srli_epi64&expand=5236) * [x] [`_mm512_srlv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srlv_epi32&expand=5236) * [x] [`_mm512_srlv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srlv_epi64&expand=5236) - * [ ] [`_mm512_store_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi32&expand=5236) - * [ ] [`_mm512_store_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi64&expand=5236) - * [ ] [`_mm512_store_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_pd&expand=5236) - * [ ] [`_mm512_store_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_ps&expand=5236) - * [ ] [`_mm512_store_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_si512&expand=5236) + * [x] [`_mm512_store_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi32&expand=5236) + * [x] [`_mm512_store_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi64&expand=5236) + * [x] [`_mm512_store_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_pd&expand=5236) + * [x] [`_mm512_store_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_ps&expand=5236) + * [x] [`_mm512_store_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_si512&expand=5236) * [x] [`_mm512_storeu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_pd&expand=5236) * [x] [`_mm512_storeu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_ps&expand=5236) - * [ ] [`_mm512_storeu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_si512&expand=5236) + * [x] [`_mm512_storeu_epi32`] + * [x] [`_mm512_storeu_epi64`] + * [x] [`_mm512_storeu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_si512&expand=5236) * [ ] [`_mm512_stream_load_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_load_si512&expand=5236) - * [ ] [`_mm512_stream_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_pd&expand=5236) - * [ ] [`_mm512_stream_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_ps&expand=5236) - * [ ] [`_mm512_stream_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_si512&expand=5236) + * [x] [`_mm512_stream_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_pd&expand=5236) + * [x] [`_mm512_stream_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_ps&expand=5236) + * [x] [`_mm512_stream_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_si512&expand=5236) * [x] [`_mm512_sub_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi32&expand=5236) * [x] [`_mm512_sub_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi64&expand=5236) * [x] [`_mm512_sub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_pd&expand=5236) @@ -1102,16 +1106,16 @@ * [x] [`_mm512_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_round_pd&expand=5236) * [x] [`_mm512_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_round_ps&expand=5236) * [ ] [`_mm512_svml_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_svml_round_pd&expand=5236) - * [ ] [`_mm512_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi32&expand=5236) - * [ ] [`_mm512_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi64&expand=5236) - * [ ] [`_mm512_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi32_mask&expand=5236) - * [ ] [`_mm512_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi64_mask&expand=5236) - * [ ] [`_mm512_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi32_mask&expand=5236) - * [ ] [`_mm512_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi64_mask&expand=5236) - * [ ] [`_mm512_undefined_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_epi32&expand=5236) + * [x] [`_mm512_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi32&expand=5236) + * [x] [`_mm512_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi64&expand=5236) + * [x] [`_mm512_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi32_mask&expand=5236) + * [x] [`_mm512_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi64_mask&expand=5236) + * [x] [`_mm512_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi32_mask&expand=5236) + * [x] [`_mm512_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi64_mask&expand=5236) + * [x] [`_mm512_undefined_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_epi32&expand=5236) * [x] [`_mm512_undefined_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_pd&expand=5236) * [x] [`_mm512_undefined_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_ps&expand=5236) - * [ ] [`_mm512_undefined`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined&expand=5236) + * [x] [`_mm512_undefined`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined&expand=5236) * [x] [`_mm512_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi32&expand=5236) * [x] [`_mm512_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi64&expand=5236) * [x] [`_mm512_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_pd&expand=5236) @@ -1123,296 +1127,296 @@ * [x] [`_mm512_xor_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_epi32&expand=5236) * [x] [`_mm512_xor_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_epi64&expand=5236) * [x] [`_mm512_xor_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_si512&expand=5236) - * [ ] [`_mm512_zextpd128_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd128_pd512&expand=5236) - * [ ] [`_mm512_zextpd256_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd256_pd512&expand=5236) - * [ ] [`_mm512_zextps128_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps128_ps512&expand=5236) - * [ ] [`_mm512_zextps256_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps256_ps512&expand=5236) - * [ ] [`_mm512_zextsi128_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi128_si512&expand=5236) - * [ ] [`_mm512_zextsi256_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi256_si512&expand=5236) - * [ ] [`_mm_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_sd&expand=5236) - * [ ] [`_mm_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_ss&expand=5236) + * [x] [`_mm512_zextpd128_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd128_pd512&expand=5236) + * [x] [`_mm512_zextpd256_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd256_pd512&expand=5236) + * [x] [`_mm512_zextps128_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps128_ps512&expand=5236) + * [x] [`_mm512_zextps256_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps256_ps512&expand=5236) + * [x] [`_mm512_zextsi128_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi128_si512&expand=5236) + * [x] [`_mm512_zextsi256_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi256_si512&expand=5236) + * [x] [`_mm_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_sd&expand=5236) + * [x] [`_mm_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_ss&expand=5236) * [x] [`_mm_cmp_round_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_sd_mask&expand=5236) * [x] [`_mm_cmp_round_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_ss_mask&expand=5236) * [x] [`_mm_cmp_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_sd_mask&expand=5236) * [x] [`_mm_cmp_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_ss_mask&expand=5236) - * [ ] [`_mm_comi_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_sd&expand=5236) - * [ ] [`_mm_comi_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_ss&expand=5236) - * [ ] [`_mm_cvt_roundi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi32_ss&expand=5236) + * [x] [`_mm_comi_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_sd&expand=5236) + * [x] [`_mm_comi_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_ss&expand=5236) + * [x] [`_mm_cvt_roundi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi32_ss&expand=5236) * [ ] [`_mm_cvt_roundi64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi64_sd&expand=5236) * [ ] [`_mm_cvt_roundi64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi64_ss&expand=5236) - * [ ] [`_mm_cvt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_i32&expand=5236) + * [x] [`_mm_cvt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_i32&expand=5236) * [ ] [`_mm_cvt_roundsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_i64&expand=5236) - * [ ] [`_mm_cvt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_si32&expand=5236) + * [x] [`_mm_cvt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_si32&expand=5236) * [ ] [`_mm_cvt_roundsd_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_si64&expand=5236) - * [ ] [`_mm_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_ss&expand=5236) - * [ ] [`_mm_cvt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_u32&expand=5236) + * [x] [`_mm_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_ss&expand=5236) + * [x] [`_mm_cvt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_u32&expand=5236) * [ ] [`_mm_cvt_roundsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_u64&expand=5236) - * [ ] [`_mm_cvt_roundsi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi32_ss&expand=5236) + * [x] [`_mm_cvt_roundsi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi32_ss&expand=5236) * [ ] [`_mm_cvt_roundsi64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi64_sd&expand=5236) * [ ] [`_mm_cvt_roundsi64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi64_ss&expand=5236) - * [ ] [`_mm_cvt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_i32&expand=5236) + * [x] [`_mm_cvt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_i32&expand=5236) * [ ] [`_mm_cvt_roundss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_i64&expand=5236) - * [ ] [`_mm_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_sd&expand=5236) - * [ ] [`_mm_cvt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_si32&expand=5236) + * [x] [`_mm_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_sd&expand=5236) + * [x] [`_mm_cvt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_si32&expand=5236) * [ ] [`_mm_cvt_roundss_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_si64&expand=5236) - * [ ] [`_mm_cvt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_u32&expand=5236) + * [x] [`_mm_cvt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_u32&expand=5236) * [ ] [`_mm_cvt_roundss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_u64&expand=5236) - * [ ] [`_mm_cvt_roundu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu32_ss&expand=5236) + * [x] [`_mm_cvt_roundu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu32_ss&expand=5236) * [ ] [`_mm_cvt_roundu64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu64_sd&expand=5236) * [ ] [`_mm_cvt_roundu64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu64_ss&expand=5236) - * [ ] [`_mm_cvti32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_sd&expand=5236) - * [ ] [`_mm_cvti32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_ss&expand=5236) + * [x] [`_mm_cvti32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_sd&expand=5236) + * [x] [`_mm_cvti32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_ss&expand=5236) * [ ] [`_mm_cvti64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti64_sd&expand=5236) * [ ] [`_mm_cvti64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti64_ss&expand=5236) - * [ ] [`_mm_cvtsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_i32&expand=5236) + * [x] [`_mm_cvtsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_i32&expand=5236) * [ ] [`_mm_cvtsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_i64&expand=5236) - * [ ] [`_mm_cvtsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_u32&expand=5236) + * [x] [`_mm_cvtsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_u32&expand=5236) * [ ] [`_mm_cvtsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_u64&expand=5236) - * [ ] [`_mm_cvtss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_i32&expand=5236) + * [x] [`_mm_cvtss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_i32&expand=5236) * [ ] [`_mm_cvtss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_i64&expand=5236) - * [ ] [`_mm_cvtss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_u32&expand=5236) + * [x] [`_mm_cvtss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_u32&expand=5236) * [ ] [`_mm_cvtss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_u64&expand=5236) - * [ ] [`_mm_cvtt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i32&expand=5236) - * [ ] [`_mm_cvtt_roundsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i64&expand=5236) - * [ ] [`_mm_cvtt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_si32&expand=5236) + * [x] [`_mm_cvtt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i32&expand=5236) + * [x] [`_mm_cvtt_roundsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i64&expand=5236) + * [x] [`_mm_cvtt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_si32&expand=5236) * [ ] [`_mm_cvtt_roundsd_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_si64&expand=5236) - * [ ] [`_mm_cvtt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_u32&expand=5236) + * [x] [`_mm_cvtt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_u32&expand=5236) * [ ] [`_mm_cvtt_roundsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_u64&expand=5236) - * [ ] [`_mm_cvtt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_i32&expand=5236) + * [x] [`_mm_cvtt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_i32&expand=5236) * [ ] [`_mm_cvtt_roundss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_i64&expand=5236) - * [ ] [`_mm_cvtt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_si32&expand=5236) + * [x] [`_mm_cvtt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_si32&expand=5236) * [ ] [`_mm_cvtt_roundss_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_si64&expand=5236) - * [ ] [`_mm_cvtt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_u32&expand=5236) + * [x] [`_mm_cvtt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_u32&expand=5236) * [ ] [`_mm_cvtt_roundss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_u64&expand=5236) - * [ ] [`_mm_cvttsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_i32&expand=5236) + * [x] [`_mm_cvttsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_i32&expand=5236) * [ ] [`_mm_cvttsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_i64&expand=5236) - * [ ] [`_mm_cvttsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_u32&expand=5236) + * [x] [`_mm_cvttsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_u32&expand=5236) * [ ] [`_mm_cvttsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_u64&expand=5236) - * [ ] [`_mm_cvttss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_i32&expand=5236) + * [x] [`_mm_cvttss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_i32&expand=5236) * [ ] [`_mm_cvttss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_i64&expand=5236) - * [ ] [`_mm_cvttss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_u32&expand=5236) + * [x] [`_mm_cvttss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_u32&expand=5236) * [ ] [`_mm_cvttss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_u64&expand=5236) - * [ ] [`_mm_cvtu32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_sd&expand=5236) - * [ ] [`_mm_cvtu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_ss&expand=5236) - * [ ] [`_mm_cvtu64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_sd&expand=5236) - * [ ] [`_mm_cvtu64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_ss&expand=5236) - * [ ] [`_mm_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_sd&expand=5236) - * [ ] [`_mm_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_ss&expand=5236) - * [ ] [`_mm_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_sd&expand=5236) - * [ ] [`_mm_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_ss&expand=5236) - * [ ] [`_mm_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_sd&expand=5236) - * [ ] [`_mm_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_ss&expand=5236) - * [ ] [`_mm_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_sd&expand=5236) - * [ ] [`_mm_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_ss&expand=5236) - * [ ] [`_mm_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_sd&expand=5236) - * [ ] [`_mm_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_ss&expand=5236) - * [ ] [`_mm_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_sd&expand=5236) - * [ ] [`_mm_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_ss&expand=5236) - * [ ] [`_mm_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_sd&expand=5236) - * [ ] [`_mm_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_ss&expand=5236) - * [ ] [`_mm_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_sd&expand=5236) - * [ ] [`_mm_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_ss&expand=5236) - * [ ] [`_mm_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_sd&expand=5236) - * [ ] [`_mm_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_ss&expand=5236) - * [ ] [`_mm_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_sd&expand=5236) - * [ ] [`_mm_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_ss&expand=5236) - * [ ] [`_mm_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_sd&expand=5236) - * [ ] [`_mm_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_ss&expand=5236) - * [ ] [`_mm_mask3_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_sd&expand=5236) - * [ ] [`_mm_mask3_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_ss&expand=5236) - * [ ] [`_mm_mask3_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_sd&expand=5236) - * [ ] [`_mm_mask3_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_ss&expand=5236) - * [ ] [`_mm_mask3_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_sd&expand=5236) - * [ ] [`_mm_mask3_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_ss&expand=5236) - * [ ] [`_mm_mask3_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_sd&expand=5236) - * [ ] [`_mm_mask3_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_ss&expand=5236) - * [ ] [`_mm_mask3_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_sd&expand=5236) - * [ ] [`_mm_mask3_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_ss&expand=5236) - * [ ] [`_mm_mask3_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_sd&expand=5236) - * [ ] [`_mm_mask3_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_ss&expand=5236) - * [ ] [`_mm_mask3_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_sd&expand=5236) - * [ ] [`_mm_mask3_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_ss&expand=5236) - * [ ] [`_mm_mask3_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_sd&expand=5236) - * [ ] [`_mm_mask3_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_ss&expand=5236) - * [ ] [`_mm_mask_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_sd&expand=5236) - * [ ] [`_mm_mask_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_ss&expand=5236) - * [ ] [`_mm_mask_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_sd&expand=5236) - * [ ] [`_mm_mask_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_ss&expand=5236) + * [x] [`_mm_cvtu32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_sd&expand=5236) + * [x] [`_mm_cvtu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_ss&expand=5236) + * [x] [`_mm_cvtu64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_sd&expand=5236) + * [x] [`_mm_cvtu64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_ss&expand=5236) + * [x] [`_mm_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_sd&expand=5236) + * [x] [`_mm_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_ss&expand=5236) + * [x] [`_mm_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_sd&expand=5236) + * [x] [`_mm_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_ss&expand=5236) + * [x] [`_mm_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_sd&expand=5236) + * [x] [`_mm_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_ss&expand=5236) + * [x] [`_mm_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_sd&expand=5236) + * [x] [`_mm_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_ss&expand=5236) + * [x] [`_mm_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_sd&expand=5236) + * [x] [`_mm_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_ss&expand=5236) + * [x] [`_mm_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_sd&expand=5236) + * [x] [`_mm_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_ss&expand=5236) + * [x] [`_mm_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_sd&expand=5236) + * [x] [`_mm_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_ss&expand=5236) + * [x] [`_mm_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_sd&expand=5236) + * [x] [`_mm_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_ss&expand=5236) + * [x] [`_mm_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_sd&expand=5236) + * [x] [`_mm_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_ss&expand=5236) + * [x] [`_mm_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_sd&expand=5236) + * [x] [`_mm_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_ss&expand=5236) + * [x] [`_mm_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_sd&expand=5236) + * [x] [`_mm_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_ss&expand=5236) + * [x] [`_mm_mask3_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_sd&expand=5236) + * [x] [`_mm_mask3_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_ss&expand=5236) + * [x] [`_mm_mask3_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_sd&expand=5236) + * [x] [`_mm_mask3_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_ss&expand=5236) + * [x] [`_mm_mask3_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_sd&expand=5236) + * [x] [`_mm_mask3_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_ss&expand=5236) + * [x] [`_mm_mask3_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_sd&expand=5236) + * [x] [`_mm_mask3_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_ss&expand=5236) + * [x] [`_mm_mask3_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_sd&expand=5236) + * [x] [`_mm_mask3_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_ss&expand=5236) + * [x] [`_mm_mask3_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_sd&expand=5236) + * [x] [`_mm_mask3_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_ss&expand=5236) + * [x] [`_mm_mask3_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_sd&expand=5236) + * [x] [`_mm_mask3_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_ss&expand=5236) + * [x] [`_mm_mask3_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_sd&expand=5236) + * [x] [`_mm_mask3_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_ss&expand=5236) + * [x] [`_mm_mask_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_sd&expand=5236) + * [x] [`_mm_mask_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_ss&expand=5236) + * [x] [`_mm_mask_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_sd&expand=5236) + * [x] [`_mm_mask_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_ss&expand=5236) * [x] [`_mm_mask_cmp_round_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_sd_mask&expand=5236) * [x] [`_mm_mask_cmp_round_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_ss_mask&expand=5236) * [x] [`_mm_mask_cmp_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_sd_mask&expand=5236) * [x] [`_mm_mask_cmp_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_ss_mask&expand=5236) - * [ ] [`_mm_mask_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundsd_ss&expand=5236) - * [ ] [`_mm_mask_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundss_sd&expand=5236) - * [ ] [`_mm_mask_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtsd_ss&expand=5236) - * [ ] [`_mm_mask_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtss_sd&expand=5236) - * [ ] [`_mm_mask_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_sd&expand=5236) - * [ ] [`_mm_mask_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_ss&expand=5236) - * [ ] [`_mm_mask_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_sd&expand=5236) - * [ ] [`_mm_mask_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_ss&expand=5236) - * [ ] [`_mm_mask_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_sd&expand=5236) - * [ ] [`_mm_mask_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_ss&expand=5236) - * [ ] [`_mm_mask_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_sd&expand=5236) - * [ ] [`_mm_mask_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_ss&expand=5236) - * [ ] [`_mm_mask_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_sd&expand=5236) - * [ ] [`_mm_mask_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_ss&expand=5236) - * [ ] [`_mm_mask_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_sd&expand=5236) - * [ ] [`_mm_mask_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_ss&expand=5236) - * [ ] [`_mm_mask_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_sd&expand=5236) - * [ ] [`_mm_mask_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_ss&expand=5236) - * [ ] [`_mm_mask_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_sd&expand=5236) - * [ ] [`_mm_mask_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_ss&expand=5236) - * [ ] [`_mm_mask_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_sd&expand=5236) - * [ ] [`_mm_mask_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_ss&expand=5236) - * [ ] [`_mm_mask_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_sd&expand=5236) - * [ ] [`_mm_mask_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_ss&expand=5236) - * [ ] [`_mm_mask_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_sd&expand=5236) - * [ ] [`_mm_mask_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_ss&expand=5236) - * [ ] [`_mm_mask_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_sd&expand=5236) - * [ ] [`_mm_mask_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_ss&expand=5236) - * [ ] [`_mm_mask_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_sd&expand=5236) - * [ ] [`_mm_mask_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_ss&expand=5236) - * [ ] [`_mm_mask_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_sd&expand=5236) - * [ ] [`_mm_mask_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_ss&expand=5236) - * [ ] [`_mm_mask_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_sd&expand=5236) - * [ ] [`_mm_mask_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_ss&expand=5236) - * [ ] [`_mm_mask_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_sd&expand=5236) - * [ ] [`_mm_mask_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_ss&expand=5236) + * [x] [`_mm_mask_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundsd_ss&expand=5236) + * [x] [`_mm_mask_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundss_sd&expand=5236) + * [x] [`_mm_mask_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtsd_ss&expand=5236) + * [x] [`_mm_mask_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtss_sd&expand=5236) + * [x] [`_mm_mask_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_sd&expand=5236) + * [x] [`_mm_mask_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_ss&expand=5236) + * [x] [`_mm_mask_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_sd&expand=5236) + * [x] [`_mm_mask_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_ss&expand=5236) + * [x] [`_mm_mask_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_sd&expand=5236) + * [x] [`_mm_mask_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_ss&expand=5236) + * [x] [`_mm_mask_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_sd&expand=5236) + * [x] [`_mm_mask_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_ss&expand=5236) + * [x] [`_mm_mask_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_sd&expand=5236) + * [x] [`_mm_mask_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_ss&expand=5236) + * [x] [`_mm_mask_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_sd&expand=5236) + * [x] [`_mm_mask_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_ss&expand=5236) + * [x] [`_mm_mask_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_sd&expand=5236) + * [x] [`_mm_mask_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_ss&expand=5236) + * [x] [`_mm_mask_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_sd&expand=5236) + * [x] [`_mm_mask_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_ss&expand=5236) + * [x] [`_mm_mask_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_sd&expand=5236) + * [x] [`_mm_mask_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_ss&expand=5236) + * [x] [`_mm_mask_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_sd&expand=5236) + * [x] [`_mm_mask_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_ss&expand=5236) + * [x] [`_mm_mask_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_sd&expand=5236) + * [x] [`_mm_mask_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_ss&expand=5236) + * [x] [`_mm_mask_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_sd&expand=5236) + * [x] [`_mm_mask_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_ss&expand=5236) + * [x] [`_mm_mask_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_sd&expand=5236) + * [x] [`_mm_mask_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_ss&expand=5236) + * [x] [`_mm_mask_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_sd&expand=5236) + * [x] [`_mm_mask_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_ss&expand=5236) + * [x] [`_mm_mask_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_sd&expand=5236) + * [x] [`_mm_mask_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_ss&expand=5236) + * [x] [`_mm_mask_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_sd&expand=5236) + * [x] [`_mm_mask_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_ss&expand=5236) * [ ] [`_mm_mask_load_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_load_sd&expand=5236) * [ ] [`_mm_mask_load_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_load_ss&expand=5236) - * [ ] [`_mm_mask_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_sd&expand=5236) - * [ ] [`_mm_mask_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_ss&expand=5236) - * [ ] [`_mm_mask_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_sd&expand=5236) - * [ ] [`_mm_mask_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_ss&expand=5236) - * [ ] [`_mm_mask_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_sd&expand=5236) - * [ ] [`_mm_mask_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_ss&expand=5236) - * [ ] [`_mm_mask_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_sd&expand=5236) - * [ ] [`_mm_mask_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_ss&expand=5236) - * [ ] [`_mm_mask_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_sd&expand=5236) - * [ ] [`_mm_mask_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_ss&expand=5236) - * [ ] [`_mm_mask_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_sd&expand=5236) - * [ ] [`_mm_mask_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_ss&expand=5236) - * [ ] [`_mm_mask_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_sd&expand=5236) - * [ ] [`_mm_mask_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_ss&expand=5236) - * [ ] [`_mm_mask_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_sd&expand=5236) - * [ ] [`_mm_mask_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_ss&expand=5236) - * [ ] [`_mm_mask_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_sd&expand=5236) - * [ ] [`_mm_mask_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_ss&expand=5236) - * [ ] [`_mm_mask_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_sd&expand=5236) - * [ ] [`_mm_mask_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_ss&expand=5236) - * [ ] [`_mm_mask_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_sd&expand=5236) - * [ ] [`_mm_mask_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_ss&expand=5236) - * [ ] [`_mm_mask_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_sd&expand=5236) - * [ ] [`_mm_mask_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_ss&expand=5236) - * [ ] [`_mm_mask_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_sd&expand=5236) - * [ ] [`_mm_mask_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_ss&expand=5236) - * [ ] [`_mm_mask_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_sd&expand=5236) - * [ ] [`_mm_mask_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_ss&expand=5236) - * [ ] [`_mm_mask_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_sd&expand=5236) - * [ ] [`_mm_mask_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_ss&expand=5236) + * [x] [`_mm_mask_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_sd&expand=5236) + * [x] [`_mm_mask_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_ss&expand=5236) + * [x] [`_mm_mask_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_sd&expand=5236) + * [x] [`_mm_mask_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_ss&expand=5236) + * [x] [`_mm_mask_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_sd&expand=5236) + * [x] [`_mm_mask_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_ss&expand=5236) + * [x] [`_mm_mask_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_sd&expand=5236) + * [x] [`_mm_mask_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_ss&expand=5236) + * [x] [`_mm_mask_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_sd&expand=5236) + * [x] [`_mm_mask_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_ss&expand=5236) + * [x] [`_mm_mask_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_sd&expand=5236) + * [x] [`_mm_mask_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_ss&expand=5236) + * [x] [`_mm_mask_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_sd&expand=5236) + * [x] [`_mm_mask_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_ss&expand=5236) + * [x] [`_mm_mask_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_sd&expand=5236) + * [x] [`_mm_mask_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_ss&expand=5236) + * [x] [`_mm_mask_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_sd&expand=5236) + * [x] [`_mm_mask_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_ss&expand=5236) + * [x] [`_mm_mask_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_sd&expand=5236) + * [x] [`_mm_mask_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_ss&expand=5236) + * [x] [`_mm_mask_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_sd&expand=5236) + * [x] [`_mm_mask_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_ss&expand=5236) + * [x] [`_mm_mask_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_sd&expand=5236) + * [x] [`_mm_mask_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_ss&expand=5236) + * [x] [`_mm_mask_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_sd&expand=5236) + * [x] [`_mm_mask_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_ss&expand=5236) + * [x] [`_mm_mask_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_sd&expand=5236) + * [x] [`_mm_mask_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_ss&expand=5236) + * [x] [`_mm_mask_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_sd&expand=5236) + * [x] [`_mm_mask_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_ss&expand=5236) * [ ] [`_mm_mask_store_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_store_sd&expand=5236) * [ ] [`_mm_mask_store_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_store_ss&expand=5236) - * [ ] [`_mm_mask_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_sd&expand=5236) - * [ ] [`_mm_mask_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_ss&expand=5236) - * [ ] [`_mm_mask_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_sd&expand=5236) - * [ ] [`_mm_mask_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_ss&expand=5236) - * [ ] [`_mm_maskz_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_sd&expand=5236) - * [ ] [`_mm_maskz_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_ss&expand=5236) - * [ ] [`_mm_maskz_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_sd&expand=5236) - * [ ] [`_mm_maskz_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_ss&expand=5236) - * [ ] [`_mm_maskz_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundsd_ss&expand=5236) - * [ ] [`_mm_maskz_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundss_sd&expand=5236) - * [ ] [`_mm_maskz_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtsd_ss&expand=5236) - * [ ] [`_mm_maskz_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtss_sd&expand=5236) - * [ ] [`_mm_maskz_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_sd&expand=5236) - * [ ] [`_mm_maskz_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_ss&expand=5236) - * [ ] [`_mm_maskz_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_sd&expand=5236) - * [ ] [`_mm_maskz_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_ss&expand=5236) - * [ ] [`_mm_maskz_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_sd&expand=5236) - * [ ] [`_mm_maskz_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_ss&expand=5236) - * [ ] [`_mm_maskz_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_sd&expand=5236) - * [ ] [`_mm_maskz_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_ss&expand=5236) - * [ ] [`_mm_maskz_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_sd&expand=5236) - * [ ] [`_mm_maskz_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_ss&expand=5236) - * [ ] [`_mm_maskz_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_sd&expand=5236) - * [ ] [`_mm_maskz_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_ss&expand=5236) - * [ ] [`_mm_maskz_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_sd&expand=5236) - * [ ] [`_mm_maskz_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_ss&expand=5236) - * [ ] [`_mm_maskz_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_sd&expand=5236) - * [ ] [`_mm_maskz_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_ss&expand=5236) - * [ ] [`_mm_maskz_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_sd&expand=5236) - * [ ] [`_mm_maskz_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_ss&expand=5236) - * [ ] [`_mm_maskz_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_sd&expand=5236) - * [ ] [`_mm_maskz_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_ss&expand=5236) - * [ ] [`_mm_maskz_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_sd&expand=5236) - * [ ] [`_mm_maskz_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_ss&expand=5236) - * [ ] [`_mm_maskz_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_sd&expand=5236) - * [ ] [`_mm_maskz_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_ss&expand=5236) - * [ ] [`_mm_maskz_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_sd&expand=5236) - * [ ] [`_mm_maskz_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_ss&expand=5236) - * [ ] [`_mm_maskz_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_sd&expand=5236) - * [ ] [`_mm_maskz_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_ss&expand=5236) - * [ ] [`_mm_maskz_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_sd&expand=5236) - * [ ] [`_mm_maskz_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_ss&expand=5236) - * [ ] [`_mm_maskz_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_sd&expand=5236) - * [ ] [`_mm_maskz_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_ss&expand=5236) + * [x] [`_mm_mask_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_sd&expand=5236) + * [x] [`_mm_mask_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_ss&expand=5236) + * [x] [`_mm_mask_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_sd&expand=5236) + * [x] [`_mm_mask_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_ss&expand=5236) + * [x] [`_mm_maskz_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_sd&expand=5236) + * [x] [`_mm_maskz_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_ss&expand=5236) + * [x] [`_mm_maskz_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_sd&expand=5236) + * [x] [`_mm_maskz_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_ss&expand=5236) + * [x] [`_mm_maskz_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundsd_ss&expand=5236) + * [x] [`_mm_maskz_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundss_sd&expand=5236) + * [x] [`_mm_maskz_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtsd_ss&expand=5236) + * [x] [`_mm_maskz_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtss_sd&expand=5236) + * [x] [`_mm_maskz_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_sd&expand=5236) + * [x] [`_mm_maskz_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_ss&expand=5236) + * [x] [`_mm_maskz_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_sd&expand=5236) + * [x] [`_mm_maskz_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_ss&expand=5236) + * [x] [`_mm_maskz_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_sd&expand=5236) + * [x] [`_mm_maskz_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_ss&expand=5236) + * [x] [`_mm_maskz_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_sd&expand=5236) + * [x] [`_mm_maskz_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_ss&expand=5236) + * [x] [`_mm_maskz_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_sd&expand=5236) + * [x] [`_mm_maskz_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_ss&expand=5236) + * [x] [`_mm_maskz_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_sd&expand=5236) + * [x] [`_mm_maskz_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_ss&expand=5236) + * [x] [`_mm_maskz_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_sd&expand=5236) + * [x] [`_mm_maskz_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_ss&expand=5236) + * [x] [`_mm_maskz_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_sd&expand=5236) + * [x] [`_mm_maskz_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_ss&expand=5236) + * [x] [`_mm_maskz_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_sd&expand=5236) + * [x] [`_mm_maskz_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_ss&expand=5236) + * [x] [`_mm_maskz_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_sd&expand=5236) + * [x] [`_mm_maskz_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_ss&expand=5236) + * [x] [`_mm_maskz_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_sd&expand=5236) + * [x] [`_mm_maskz_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_ss&expand=5236) + * [x] [`_mm_maskz_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_sd&expand=5236) + * [x] [`_mm_maskz_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_ss&expand=5236) + * [x] [`_mm_maskz_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_sd&expand=5236) + * [x] [`_mm_maskz_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_ss&expand=5236) + * [x] [`_mm_maskz_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_sd&expand=5236) + * [x] [`_mm_maskz_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_ss&expand=5236) + * [x] [`_mm_maskz_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_sd&expand=5236) + * [x] [`_mm_maskz_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_ss&expand=5236) + * [x] [`_mm_maskz_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_sd&expand=5236) + * [x] [`_mm_maskz_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_ss&expand=5236) * [ ] [`_mm_maskz_load_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_load_sd&expand=5236) * [ ] [`_mm_maskz_load_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_load_ss&expand=5236) - * [ ] [`_mm_maskz_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_sd&expand=5236) - * [ ] [`_mm_maskz_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_ss&expand=5236) - * [ ] [`_mm_maskz_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_sd&expand=5236) - * [ ] [`_mm_maskz_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_ss&expand=5236) - * [ ] [`_mm_maskz_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_sd&expand=5236) - * [ ] [`_mm_maskz_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_ss&expand=5236) - * [ ] [`_mm_maskz_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_sd&expand=5236) - * [ ] [`_mm_maskz_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_ss&expand=5236) - * [ ] [`_mm_maskz_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_sd&expand=5236) - * [ ] [`_mm_maskz_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_ss&expand=5236) - * [ ] [`_mm_maskz_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_sd&expand=5236) - * [ ] [`_mm_maskz_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_ss&expand=5236) - * [ ] [`_mm_maskz_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_sd&expand=5236) - * [ ] [`_mm_maskz_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_ss&expand=5236) - * [ ] [`_mm_maskz_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_sd&expand=5236) - * [ ] [`_mm_maskz_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_ss&expand=5236) - * [ ] [`_mm_maskz_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_sd&expand=5236) - * [ ] [`_mm_maskz_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_ss&expand=5236) - * [ ] [`_mm_maskz_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_sd&expand=5236) - * [ ] [`_mm_maskz_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_ss&expand=5236) - * [ ] [`_mm_maskz_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_sd&expand=5236) - * [ ] [`_mm_maskz_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_ss&expand=5236) - * [ ] [`_mm_maskz_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_sd&expand=5236) - * [ ] [`_mm_maskz_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_ss&expand=5236) - * [ ] [`_mm_maskz_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_sd&expand=5236) - * [ ] [`_mm_maskz_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_ss&expand=5236) - * [ ] [`_mm_maskz_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_sd&expand=5236) - * [ ] [`_mm_maskz_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_ss&expand=5236) - * [ ] [`_mm_maskz_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_sd&expand=5236) - * [ ] [`_mm_maskz_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_ss&expand=5236) - * [ ] [`_mm_maskz_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_sd&expand=5236) - * [ ] [`_mm_maskz_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_ss&expand=5236) - * [ ] [`_mm_maskz_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_sd&expand=5236) - * [ ] [`_mm_maskz_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_ss&expand=5236) - * [ ] [`_mm_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_sd&expand=5236) - * [ ] [`_mm_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_ss&expand=5236) - * [ ] [`_mm_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_sd&expand=5236) - * [ ] [`_mm_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_ss&expand=5236) - * [ ] [`_mm_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_sd&expand=5236) - * [ ] [`_mm_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_ss&expand=5236) - * [ ] [`_mm_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_sd&expand=5236) - * [ ] [`_mm_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_ss&expand=5236) - * [ ] [`_mm_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_sd&expand=5236) - * [ ] [`_mm_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_ss&expand=5236) - * [ ] [`_mm_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_sd&expand=5236) - * [ ] [`_mm_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_ss&expand=5236) - * [ ] [`_mm_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_sd&expand=5236) - * [ ] [`_mm_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_ss&expand=5236) - * [ ] [`_mm_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_sd&expand=5236) - * [ ] [`_mm_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_ss&expand=5236) - * [ ] [`_mm_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_sd&expand=5236) - * [ ] [`_mm_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_ss&expand=5236) - * [ ] [`_mm_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_sd&expand=5236) - * [ ] [`_mm_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_ss&expand=5236) - * [ ] [`_mm_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_sd&expand=5236) - * [ ] [`_mm_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_ss&expand=5236) + * [x] [`_mm_maskz_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_sd&expand=5236) + * [x] [`_mm_maskz_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_ss&expand=5236) + * [x] [`_mm_maskz_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_sd&expand=5236) + * [x] [`_mm_maskz_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_ss&expand=5236) + * [x] [`_mm_maskz_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_sd&expand=5236) + * [x] [`_mm_maskz_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_ss&expand=5236) + * [x] [`_mm_maskz_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_sd&expand=5236) + * [x] [`_mm_maskz_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_ss&expand=5236) + * [x] [`_mm_maskz_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_sd&expand=5236) + * [x] [`_mm_maskz_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_ss&expand=5236) + * [x] [`_mm_maskz_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_sd&expand=5236) + * [x] [`_mm_maskz_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_ss&expand=5236) + * [x] [`_mm_maskz_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_sd&expand=5236) + * [x] [`_mm_maskz_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_ss&expand=5236) + * [x] [`_mm_maskz_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_sd&expand=5236) + * [x] [`_mm_maskz_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_ss&expand=5236) + * [x] [`_mm_maskz_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_sd&expand=5236) + * [x] [`_mm_maskz_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_ss&expand=5236) + * [x] [`_mm_maskz_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_sd&expand=5236) + * [x] [`_mm_maskz_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_ss&expand=5236) + * [x] [`_mm_maskz_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_sd&expand=5236) + * [x] [`_mm_maskz_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_ss&expand=5236) + * [x] [`_mm_maskz_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_sd&expand=5236) + * [x] [`_mm_maskz_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_ss&expand=5236) + * [x] [`_mm_maskz_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_sd&expand=5236) + * [x] [`_mm_maskz_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_ss&expand=5236) + * [x] [`_mm_maskz_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_sd&expand=5236) + * [x] [`_mm_maskz_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_ss&expand=5236) + * [x] [`_mm_maskz_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_sd&expand=5236) + * [x] [`_mm_maskz_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_ss&expand=5236) + * [x] [`_mm_maskz_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_sd&expand=5236) + * [x] [`_mm_maskz_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_ss&expand=5236) + * [x] [`_mm_maskz_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_sd&expand=5236) + * [x] [`_mm_maskz_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_ss&expand=5236) + * [x] [`_mm_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_sd&expand=5236) + * [x] [`_mm_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_ss&expand=5236) + * [x] [`_mm_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_sd&expand=5236) + * [x] [`_mm_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_ss&expand=5236) + * [x] [`_mm_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_sd&expand=5236) + * [x] [`_mm_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_ss&expand=5236) + * [x] [`_mm_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_sd&expand=5236) + * [x] [`_mm_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_ss&expand=5236) + * [x] [`_mm_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_sd&expand=5236) + * [x] [`_mm_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_ss&expand=5236) + * [x] [`_mm_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_sd&expand=5236) + * [x] [`_mm_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_ss&expand=5236) + * [x] [`_mm_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_sd&expand=5236) + * [x] [`_mm_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_ss&expand=5236) + * [x] [`_mm_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_sd&expand=5236) + * [x] [`_mm_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_ss&expand=5236) + * [x] [`_mm_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_sd&expand=5236) + * [x] [`_mm_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_ss&expand=5236) + * [x] [`_mm_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_sd&expand=5236) + * [x] [`_mm_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_ss&expand=5236) + * [x] [`_mm_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_sd&expand=5236) + * [x] [`_mm_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_ss&expand=5236)

diff --git a/library/stdarch/crates/core_arch/src/aarch64/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/mod.rs index ec2c6924b9..f6d0fc9dbd 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/mod.rs @@ -12,9 +12,6 @@ pub use self::v8::*; mod neon; pub use self::neon::*; -mod crypto; -pub use self::crypto::*; - mod tme; pub use self::tme::*; diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs index fcb3986350..db76c8721d 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs @@ -297,6 +297,58 @@ pub unsafe fn vsubq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { simd_sub(a, b) } +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fmax))] +pub unsafe fn vmax_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v1f64")] + fn vmax_f64_(a: float64x1_t, a: float64x1_t) -> float64x1_t; + } + vmax_f64_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fmax))] +pub unsafe fn vmaxq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v2f64")] + fn vmaxq_f64_(a: float64x2_t, a: float64x2_t) -> float64x2_t; + } + vmaxq_f64_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fmin))] +pub unsafe fn vmin_f64(a: float64x1_t, b: float64x1_t) -> float64x1_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v1f64")] + fn vmin_f64_(a: float64x1_t, a: float64x1_t) -> float64x1_t; + } + vmin_f64_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fmin))] +pub unsafe fn vminq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v2f64")] + fn vminq_f64_(a: float64x2_t, a: float64x2_t) -> float64x2_t; + } + vminq_f64_(a, b) +} + #[cfg(test)] mod test { use super::*; @@ -663,4 +715,40 @@ mod test { let r: f64x2 = transmute(vsubq_f64(transmute(a), transmute(b))); assert_eq!(r, e); } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_f64() { + let a: f64 = 1.0; + let b: f64 = 0.0; + let e: f64 = 1.0; + let r: f64 = transmute(vmax_f64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_f64() { + let a: f64x2 = f64x2::new(1.0, -2.0); + let b: f64x2 = f64x2::new(0.0, 3.0); + let e: f64x2 = f64x2::new(1.0, 3.0); + let r: f64x2 = transmute(vmaxq_f64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_f64() { + let a: f64 = 1.0; + let b: f64 = 0.0; + let e: f64 = 0.0; + let r: f64 = transmute(vmin_f64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_f64() { + let a: f64x2 = f64x2::new(1.0, -2.0); + let b: f64x2 = f64x2::new(0.0, 3.0); + let e: f64x2 = f64x2::new(0.0, -2.0); + let r: f64x2 = transmute(vminq_f64(transmute(a), transmute(b))); + assert_eq!(r, e); + } } diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs index 438b1ac771..227d227f4e 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs @@ -8,7 +8,7 @@ pub use self::generated::*; // FIXME: replace neon with asimd use crate::{ - core_arch::{arm::*, simd_llvm::*}, + core_arch::{arm::*, simd::*, simd_llvm::*}, mem::{transmute, zeroed}, }; #[cfg(test)] @@ -19,14 +19,6 @@ types! { pub struct float64x1_t(f64); // FIXME: check this! /// ARM-specific 128-bit wide vector of two packed `f64`. pub struct float64x2_t(f64, f64); - /// ARM-specific 64-bit wide vector of one packed `p64`. - pub struct poly64x1_t(i64); // FIXME: check this! - /// ARM-specific 64-bit wide vector of one packed `p64`. - pub struct poly64_t(i64); // FIXME: check this! - /// ARM-specific 64-bit wide vector of two packed `p64`. - pub struct poly64x2_t(i64, i64); // FIXME: check this! - /// ARM-specific 128-bit wide vector of one packed `p64`. - pub struct poly128_t(i128); // FIXME: check this! } /// ARM-specific type containing two `int8x16_t` vectors. @@ -79,6 +71,40 @@ extern "C" { #[link_name = "llvm.aarch64.neon.abs.v2i64"] fn vabsq_s64_(a: int64x2_t) -> int64x2_t; + #[link_name = "llvm.aarch64.neon.suqadd.v8i8"] + fn vuqadd_s8_(a: int8x8_t, b: uint8x8_t) -> int8x8_t; + #[link_name = "llvm.aarch64.neon.suqadd.v16i8"] + fn vuqaddq_s8_(a: int8x16_t, b: uint8x16_t) -> int8x16_t; + #[link_name = "llvm.aarch64.neon.suqadd.v4i16"] + fn vuqadd_s16_(a: int16x4_t, b: uint16x4_t) -> int16x4_t; + #[link_name = "llvm.aarch64.neon.suqadd.v8i16"] + fn vuqaddq_s16_(a: int16x8_t, b: uint16x8_t) -> int16x8_t; + #[link_name = "llvm.aarch64.neon.suqadd.v2i32"] + fn vuqadd_s32_(a: int32x2_t, b: uint32x2_t) -> int32x2_t; + #[link_name = "llvm.aarch64.neon.suqadd.v4i32"] + fn vuqaddq_s32_(a: int32x4_t, b: uint32x4_t) -> int32x4_t; + #[link_name = "llvm.aarch64.neon.suqadd.v1i64"] + fn vuqadd_s64_(a: int64x1_t, b: uint64x1_t) -> int64x1_t; + #[link_name = "llvm.aarch64.neon.suqadd.v2i64"] + fn vuqaddq_s64_(a: int64x2_t, b: uint64x2_t) -> int64x2_t; + + #[link_name = "llvm.aarch64.neon.usqadd.v8i8"] + fn vsqadd_u8_(a: uint8x8_t, b: int8x8_t) -> uint8x8_t; + #[link_name = "llvm.aarch64.neon.usqadd.v16i8"] + fn vsqaddq_u8_(a: uint8x16_t, b: int8x16_t) -> uint8x16_t; + #[link_name = "llvm.aarch64.neon.usqadd.v4i16"] + fn vsqadd_u16_(a: uint16x4_t, b: int16x4_t) -> uint16x4_t; + #[link_name = "llvm.aarch64.neon.usqadd.v8i16"] + fn vsqaddq_u16_(a: uint16x8_t, b: int16x8_t) -> uint16x8_t; + #[link_name = "llvm.aarch64.neon.usqadd.v2i32"] + fn vsqadd_u32_(a: uint32x2_t, b: int32x2_t) -> uint32x2_t; + #[link_name = "llvm.aarch64.neon.usqadd.v4i32"] + fn vsqaddq_u32_(a: uint32x4_t, b: int32x4_t) -> uint32x4_t; + #[link_name = "llvm.aarch64.neon.usqadd.v1i64"] + fn vsqadd_u64_(a: uint64x1_t, b: int64x1_t) -> uint64x1_t; + #[link_name = "llvm.aarch64.neon.usqadd.v2i64"] + fn vsqaddq_u64_(a: uint64x2_t, b: int64x2_t) -> uint64x2_t; + #[link_name = "llvm.aarch64.neon.pmull64"] fn vmull_p64_(a: i64, b: i64) -> int8x16_t; @@ -290,6 +316,367 @@ extern "C" { fn vcvtq_u32_f32_(a: float32x4_t) -> uint32x4_t; #[link_name = "llvm.aarch64.neon.fcvtzs.v4i32.v4f32"] fn vcvtq_s32_f32_(a: float32x4_t) -> int32x4_t; + + #[link_name = "llvm.aarch64.neon.vsli.v8i8"] + fn vsli_n_s8_(a: int8x8_t, b: int8x8_t, n: i32) -> int8x8_t; + #[link_name = "llvm.aarch64.neon.vsli.v16i8"] + fn vsliq_n_s8_(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t; + #[link_name = "llvm.aarch64.neon.vsli.v4i16"] + fn vsli_n_s16_(a: int16x4_t, b: int16x4_t, n: i32) -> int16x4_t; + #[link_name = "llvm.aarch64.neon.vsli.v8i16"] + fn vsliq_n_s16_(a: int16x8_t, b: int16x8_t, n: i32) -> int16x8_t; + #[link_name = "llvm.aarch64.neon.vsli.v2i32"] + fn vsli_n_s32_(a: int32x2_t, b: int32x2_t, n: i32) -> int32x2_t; + #[link_name = "llvm.aarch64.neon.vsli.v4i32"] + fn vsliq_n_s32_(a: int32x4_t, b: int32x4_t, n: i32) -> int32x4_t; + #[link_name = "llvm.aarch64.neon.vsli.v1i64"] + fn vsli_n_s64_(a: int64x1_t, b: int64x1_t, n: i32) -> int64x1_t; + #[link_name = "llvm.aarch64.neon.vsli.v2i64"] + fn vsliq_n_s64_(a: int64x2_t, b: int64x2_t, n: i32) -> int64x2_t; + + #[link_name = "llvm.aarch64.neon.vsri.v8i8"] + fn vsri_n_s8_(a: int8x8_t, b: int8x8_t, n: i32) -> int8x8_t; + #[link_name = "llvm.aarch64.neon.vsri.v16i8"] + fn vsriq_n_s8_(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t; + #[link_name = "llvm.aarch64.neon.vsri.v4i16"] + fn vsri_n_s16_(a: int16x4_t, b: int16x4_t, n: i32) -> int16x4_t; + #[link_name = "llvm.aarch64.neon.vsri.v8i16"] + fn vsriq_n_s16_(a: int16x8_t, b: int16x8_t, n: i32) -> int16x8_t; + #[link_name = "llvm.aarch64.neon.vsri.v2i32"] + fn vsri_n_s32_(a: int32x2_t, b: int32x2_t, n: i32) -> int32x2_t; + #[link_name = "llvm.aarch64.neon.vsri.v4i32"] + fn vsriq_n_s32_(a: int32x4_t, b: int32x4_t, n: i32) -> int32x4_t; + #[link_name = "llvm.aarch64.neon.vsri.v1i64"] + fn vsri_n_s64_(a: int64x1_t, b: int64x1_t, n: i32) -> int64x1_t; + #[link_name = "llvm.aarch64.neon.vsri.v2i64"] + fn vsriq_n_s64_(a: int64x2_t, b: int64x2_t, n: i32) -> int64x2_t; +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_s8(ptr: *const i8) -> int8x8_t { + transmute(i8x8::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_s8(ptr: *const i8) -> int8x16_t { + transmute(i8x16::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + *ptr.offset(8), + *ptr.offset(9), + *ptr.offset(10), + *ptr.offset(11), + *ptr.offset(12), + *ptr.offset(13), + *ptr.offset(14), + *ptr.offset(15), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_s16(ptr: *const i16) -> int16x4_t { + transmute(i16x4::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_s16(ptr: *const i16) -> int16x8_t { + transmute(i16x8::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_s32(ptr: *const i32) -> int32x2_t { + transmute(i32x2::new(*ptr, *ptr.offset(1))) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_s32(ptr: *const i32) -> int32x4_t { + transmute(i32x4::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_s64(ptr: *const i64) -> int64x1_t { + transmute(i64x1::new(*ptr)) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_s64(ptr: *const i64) -> int64x2_t { + transmute(i64x2::new(*ptr, *ptr.offset(1))) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_u8(ptr: *const u8) -> uint8x8_t { + transmute(u8x8::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_u8(ptr: *const u8) -> uint8x16_t { + transmute(u8x16::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + *ptr.offset(8), + *ptr.offset(9), + *ptr.offset(10), + *ptr.offset(11), + *ptr.offset(12), + *ptr.offset(13), + *ptr.offset(14), + *ptr.offset(15), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_u16(ptr: *const u16) -> uint16x4_t { + transmute(u16x4::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_u16(ptr: *const u16) -> uint16x8_t { + transmute(u16x8::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_u32(ptr: *const u32) -> uint32x2_t { + transmute(u32x2::new(*ptr, *ptr.offset(1))) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_u32(ptr: *const u32) -> uint32x4_t { + transmute(u32x4::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_u64(ptr: *const u64) -> uint64x1_t { + transmute(u64x1::new(*ptr)) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_u64(ptr: *const u64) -> uint64x2_t { + transmute(u64x2::new(*ptr, *ptr.offset(1))) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_p8(ptr: *const p8) -> poly8x8_t { + transmute(u8x8::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_p8(ptr: *const p8) -> poly8x16_t { + transmute(u8x16::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + *ptr.offset(8), + *ptr.offset(9), + *ptr.offset(10), + *ptr.offset(11), + *ptr.offset(12), + *ptr.offset(13), + *ptr.offset(14), + *ptr.offset(15), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_p16(ptr: *const p16) -> poly16x4_t { + transmute(u16x4::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_p16(ptr: *const p16) -> poly16x8_t { + transmute(u16x8::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + *ptr.offset(4), + *ptr.offset(5), + *ptr.offset(6), + *ptr.offset(7), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_f32(ptr: *const f32) -> float32x2_t { + transmute(f32x2::new(*ptr, *ptr.offset(1))) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_f32(ptr: *const f32) -> float32x4_t { + transmute(f32x4::new( + *ptr, + *ptr.offset(1), + *ptr.offset(2), + *ptr.offset(3), + )) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1_f64(ptr: *const f64) -> float64x1_t { + transmute(f64x1::new(*ptr)) +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_f64(ptr: *const f64) -> float64x2_t { + transmute(f64x2::new(*ptr, *ptr.offset(1))) } /// Absolute Value (wrapping). @@ -314,6 +701,120 @@ pub unsafe fn vabsq_s64(a: int64x2_t) -> int64x2_t { vabsq_s64_(a) } +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqadd_s8(a: int8x8_t, b: uint8x8_t) -> int8x8_t { + vuqadd_s8_(a, b) +} +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqaddq_s8(a: int8x16_t, b: uint8x16_t) -> int8x16_t { + vuqaddq_s8_(a, b) +} +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqadd_s16(a: int16x4_t, b: uint16x4_t) -> int16x4_t { + vuqadd_s16_(a, b) +} +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqaddq_s16(a: int16x8_t, b: uint16x8_t) -> int16x8_t { + vuqaddq_s16_(a, b) +} +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqadd_s32(a: int32x2_t, b: uint32x2_t) -> int32x2_t { + vuqadd_s32_(a, b) +} +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqaddq_s32(a: int32x4_t, b: uint32x4_t) -> int32x4_t { + vuqaddq_s32_(a, b) +} +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqadd_s64(a: int64x1_t, b: uint64x1_t) -> int64x1_t { + vuqadd_s64_(a, b) +} +/// Signed saturating Accumulate of Unsigned value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(suqadd))] +pub unsafe fn vuqaddq_s64(a: int64x2_t, b: uint64x2_t) -> int64x2_t { + vuqaddq_s64_(a, b) +} + +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqadd_u8(a: uint8x8_t, b: int8x8_t) -> uint8x8_t { + vsqadd_u8_(a, b) +} +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqaddq_u8(a: uint8x16_t, b: int8x16_t) -> uint8x16_t { + vsqaddq_u8_(a, b) +} +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqadd_u16(a: uint16x4_t, b: int16x4_t) -> uint16x4_t { + vsqadd_u16_(a, b) +} +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqaddq_u16(a: uint16x8_t, b: int16x8_t) -> uint16x8_t { + vsqaddq_u16_(a, b) +} +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqadd_u32(a: uint32x2_t, b: int32x2_t) -> uint32x2_t { + vsqadd_u32_(a, b) +} +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqaddq_u32(a: uint32x4_t, b: int32x4_t) -> uint32x4_t { + vsqaddq_u32_(a, b) +} +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqadd_u64(a: uint64x1_t, b: int64x1_t) -> uint64x1_t { + vsqadd_u64_(a, b) +} +/// Unsigned saturating Accumulate of Signed value. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(usqadd))] +pub unsafe fn vsqaddq_u64(a: uint64x2_t, b: int64x2_t) -> uint64x2_t { + vsqaddq_u64_(a, b) +} + /// Add pairwise #[inline] #[target_feature(enable = "neon")] @@ -474,7 +975,7 @@ pub unsafe fn vaddvq_u64(a: uint64x2_t) -> u64 { #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(pmull))] -pub unsafe fn vmull_p64(a: poly64_t, b: poly64_t) -> poly128_t { +pub unsafe fn vmull_p64(a: p64, b: p64) -> p128 { transmute(vmull_p64_(transmute(a), transmute(b))) } @@ -1156,7 +1657,6 @@ pub unsafe fn vtbl4_p8(a: poly8x8x4_t, b: uint8x8_t) -> poly8x8_t { #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tbx))] pub unsafe fn vtbx1_s8(a: int8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { - use crate::core_arch::simd::i8x8; let r = vqtbx1_s8(a, vcombine_s8(b, zeroed()), transmute(c)); let m: int8x8_t = simd_lt(c, transmute(i8x8::splat(8))); simd_select(m, r, a) @@ -1168,7 +1668,6 @@ pub unsafe fn vtbx1_s8(a: int8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tbx))] pub unsafe fn vtbx1_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { - use crate::core_arch::simd::u8x8; let r = vqtbx1_u8(a, vcombine_u8(b, zeroed()), c); let m: int8x8_t = simd_lt(c, transmute(u8x8::splat(8))); simd_select(m, r, a) @@ -1180,7 +1679,6 @@ pub unsafe fn vtbx1_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tbx))] pub unsafe fn vtbx1_p8(a: poly8x8_t, b: poly8x8_t, c: uint8x8_t) -> poly8x8_t { - use crate::core_arch::simd::u8x8; let r = vqtbx1_p8(a, vcombine_p8(b, zeroed()), c); let m: int8x8_t = simd_lt(c, transmute(u8x8::splat(8))); simd_select(m, r, a) @@ -1219,7 +1717,6 @@ pub unsafe fn vtbx2_p8(a: poly8x8_t, b: poly8x8x2_t, c: uint8x8_t) -> poly8x8_t #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tbx))] pub unsafe fn vtbx3_s8(a: int8x8_t, b: int8x8x3_t, c: int8x8_t) -> int8x8_t { - use crate::core_arch::simd::i8x8; let r = vqtbx2_s8( a, int8x16x2_t(vcombine_s8(b.0, b.1), vcombine_s8(b.2, zeroed())), @@ -1235,7 +1732,6 @@ pub unsafe fn vtbx3_s8(a: int8x8_t, b: int8x8x3_t, c: int8x8_t) -> int8x8_t { #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tbx))] pub unsafe fn vtbx3_u8(a: uint8x8_t, b: uint8x8x3_t, c: uint8x8_t) -> uint8x8_t { - use crate::core_arch::simd::u8x8; let r = vqtbx2_u8( a, uint8x16x2_t(vcombine_u8(b.0, b.1), vcombine_u8(b.2, zeroed())), @@ -1251,7 +1747,6 @@ pub unsafe fn vtbx3_u8(a: uint8x8_t, b: uint8x8x3_t, c: uint8x8_t) -> uint8x8_t #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(tbx))] pub unsafe fn vtbx3_p8(a: poly8x8_t, b: poly8x8x3_t, c: uint8x8_t) -> poly8x8_t { - use crate::core_arch::simd::u8x8; let r = vqtbx2_p8( a, poly8x16x2_t(vcombine_p8(b.0, b.1), vcombine_p8(b.2, zeroed())), @@ -1806,56 +2301,379 @@ pub unsafe fn vqtbx4q_p8(a: poly8x16_t, t: poly8x16x4_t, idx: uint8x16_t) -> pol #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] -pub unsafe fn vld1q_f32(addr: *const f32) -> float32x4_t { - use crate::core_arch::simd::f32x4; - transmute(f32x4::new( - *addr, - *addr.offset(1), - *addr.offset(2), - *addr.offset(3), - )) +#[cfg_attr(test, assert_instr(fcvtzs))] +pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { + vcvtq_s32_f32_(a) } +/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] -pub unsafe fn vld1q_s32(addr: *const i32) -> int32x4_t { - use crate::core_arch::simd::i32x4; - transmute(i32x4::new( - *addr, - *addr.offset(1), - *addr.offset(2), - *addr.offset(3), - )) +#[cfg_attr(test, assert_instr(fcvtzu))] +pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { + vcvtq_u32_f32_(a) } +/// Shift Left and Insert (immediate) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(ldr))] -pub unsafe fn vld1q_u32(addr: *const u32) -> uint32x4_t { - use crate::core_arch::simd::u32x4; - transmute(u32x4::new( - *addr, - *addr.offset(1), - *addr.offset(2), - *addr.offset(3), - )) +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s8(a: int8x8_t, b: int8x8_t, n: i32) -> int8x8_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + vsli_n_s8_(a, b, n) } - +/// Shift Left and Insert (immediate) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(fcvtzs))] -pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { - vcvtq_s32_f32_(a) +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s8(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + vsliq_n_s8_(a, b, n) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s16(a: int16x4_t, b: int16x4_t, n: i32) -> int16x4_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + vsli_n_s16_(a, b, n) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s16(a: int16x8_t, b: int16x8_t, n: i32) -> int16x8_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + vsliq_n_s16_(a, b, n) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s32(a: int32x2_t, b: int32x2_t, n: i32) -> int32x2_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + vsli_n_s32_(a, b, n) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s32(a: int32x4_t, b: int32x4_t, n: i32) -> int32x4_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + vsliq_n_s32_(a, b, n) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s64(a: int64x1_t, b: int64x1_t, n: i32) -> int64x1_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + vsli_n_s64_(a, b, n) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s64(a: int64x2_t, b: int64x2_t, n: i32) -> int64x2_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + vsliq_n_s64_(a, b, n) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u8(a: uint8x8_t, b: uint8x8_t, n: i32) -> uint8x8_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + transmute(vsli_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u8(a: uint8x16_t, b: uint8x16_t, n: i32) -> uint8x16_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + transmute(vsliq_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u16(a: uint16x4_t, b: uint16x4_t, n: i32) -> uint16x4_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + transmute(vsli_n_s16_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u16(a: uint16x8_t, b: uint16x8_t, n: i32) -> uint16x8_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + transmute(vsliq_n_s16_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u32(a: uint32x2_t, b: uint32x2_t, n: i32) -> uint32x2_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + transmute(vsli_n_s32_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u32(a: uint32x4_t, b: uint32x4_t, n: i32) -> uint32x4_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + transmute(vsliq_n_s32_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u64(a: uint64x1_t, b: uint64x1_t, n: i32) -> uint64x1_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + transmute(vsli_n_s64_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u64(a: uint64x2_t, b: uint64x2_t, n: i32) -> uint64x2_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + transmute(vsliq_n_s64_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_p8(a: poly8x8_t, b: poly8x8_t, n: i32) -> poly8x8_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + transmute(vsli_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_p8(a: poly8x16_t, b: poly8x16_t, n: i32) -> poly8x16_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + transmute(vsliq_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_p16(a: poly16x4_t, b: poly16x4_t, n: i32) -> poly16x4_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + transmute(vsli_n_s16_(transmute(a), transmute(b), n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sli, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_p16(a: poly16x8_t, b: poly16x8_t, n: i32) -> poly16x8_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + transmute(vsliq_n_s16_(transmute(a), transmute(b), n)) } -/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) +/// Shift Right and Insert (immediate) #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(test, assert_instr(fcvtzu))] -pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { - vcvtq_u32_f32_(a) +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s8(a: int8x8_t, b: int8x8_t, n: i32) -> int8x8_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + vsri_n_s8_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s8(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + vsriq_n_s8_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s16(a: int16x4_t, b: int16x4_t, n: i32) -> int16x4_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + vsri_n_s16_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s16(a: int16x8_t, b: int16x8_t, n: i32) -> int16x8_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + vsriq_n_s16_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s32(a: int32x2_t, b: int32x2_t, n: i32) -> int32x2_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + vsri_n_s32_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s32(a: int32x4_t, b: int32x4_t, n: i32) -> int32x4_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + vsriq_n_s32_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s64(a: int64x1_t, b: int64x1_t, n: i32) -> int64x1_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + vsri_n_s64_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s64(a: int64x2_t, b: int64x2_t, n: i32) -> int64x2_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + vsriq_n_s64_(a, b, n) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u8(a: uint8x8_t, b: uint8x8_t, n: i32) -> uint8x8_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + transmute(vsri_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u8(a: uint8x16_t, b: uint8x16_t, n: i32) -> uint8x16_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + transmute(vsriq_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u16(a: uint16x4_t, b: uint16x4_t, n: i32) -> uint16x4_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + transmute(vsri_n_s16_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u16(a: uint16x8_t, b: uint16x8_t, n: i32) -> uint16x8_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + transmute(vsriq_n_s16_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u32(a: uint32x2_t, b: uint32x2_t, n: i32) -> uint32x2_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + transmute(vsri_n_s32_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u32(a: uint32x4_t, b: uint32x4_t, n: i32) -> uint32x4_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + transmute(vsriq_n_s32_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u64(a: uint64x1_t, b: uint64x1_t, n: i32) -> uint64x1_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + transmute(vsri_n_s64_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u64(a: uint64x2_t, b: uint64x2_t, n: i32) -> uint64x2_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + transmute(vsriq_n_s64_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_p8(a: poly8x8_t, b: poly8x8_t, n: i32) -> poly8x8_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + transmute(vsri_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_p8(a: poly8x16_t, b: poly8x16_t, n: i32) -> poly8x16_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + transmute(vsriq_n_s8_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_p16(a: poly16x4_t, b: poly16x4_t, n: i32) -> poly16x4_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + transmute(vsri_n_s16_(transmute(a), transmute(b), n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(sri, n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_p16(a: poly16x8_t, b: poly16x8_t, n: i32) -> poly16x8_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + transmute(vsriq_n_s16_(transmute(a), transmute(b), n)) } #[cfg(test)] @@ -1903,32 +2721,166 @@ mod tests { } #[simd_test(enable = "neon")] - unsafe fn test_vld1q_f32() { - let e = f32x4::new(1., 2., 3., 4.); - let f = [0., 1., 2., 3., 4.]; - // do a load that has 4 byte alignment to make sure we're not - // over aligning it - let r: f32x4 = transmute(vld1q_f32(f[1..].as_ptr())); + unsafe fn test_vuqadd_s8() { + let a = i8x8::new(i8::MIN, -3, -2, -1, 0, 1, 2, i8::MAX); + let b = u8x8::new(u8::MAX, 1, 2, 3, 4, 5, 6, 7); + let e = i8x8::new(i8::MAX, -2, 0, 2, 4, 6, 8, i8::MAX); + let r: i8x8 = transmute(vuqadd_s8(transmute(a), transmute(b))); assert_eq!(r, e); } - #[simd_test(enable = "neon")] - unsafe fn test_vld1q_s32() { - let e = i32x4::new(1, 2, 3, 4); - let f = [0, 1, 2, 3, 4]; - // do a load that has 4 byte alignment to make sure we're not - // over aligning it - let r: i32x4 = transmute(vld1q_s32(f[1..].as_ptr())); + unsafe fn test_vuqaddq_s8() { + let a = i8x16::new( + i8::MIN, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + i8::MAX, + ); + let b = u8x16::new(u8::MAX, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e = i8x16::new( + i8::MAX, + -6, + -4, + -2, + 0, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18, + 20, + i8::MAX, + ); + let r: i8x16 = transmute(vuqaddq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vuqadd_s16() { + let a = i16x4::new(i16::MIN, -1, 0, i16::MAX); + let b = u16x4::new(u16::MAX, 1, 2, 3); + let e = i16x4::new(i16::MAX, 0, 2, i16::MAX); + let r: i16x4 = transmute(vuqadd_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vuqaddq_s16() { + let a = i16x8::new(i16::MIN, -3, -2, -1, 0, 1, 2, i16::MAX); + let b = u16x8::new(u16::MAX, 1, 2, 3, 4, 5, 6, 7); + let e = i16x8::new(i16::MAX, -2, 0, 2, 4, 6, 8, i16::MAX); + let r: i16x8 = transmute(vuqaddq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vuqadd_s32() { + let a = i32x2::new(i32::MIN, i32::MAX); + let b = u32x2::new(u32::MAX, 1); + let e = i32x2::new(i32::MAX, i32::MAX); + let r: i32x2 = transmute(vuqadd_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vuqaddq_s32() { + let a = i32x4::new(i32::MIN, -1, 0, i32::MAX); + let b = u32x4::new(u32::MAX, 1, 2, 3); + let e = i32x4::new(i32::MAX, 0, 2, i32::MAX); + let r: i32x4 = transmute(vuqaddq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vuqadd_s64() { + let a = i64x1::new(i64::MIN); + let b = u64x1::new(u64::MAX); + let e = i64x1::new(i64::MAX); + let r: i64x1 = transmute(vuqadd_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vuqaddq_s64() { + let a = i64x2::new(i64::MIN, i64::MAX); + let b = u64x2::new(u64::MAX, 1); + let e = i64x2::new(i64::MAX, i64::MAX); + let r: i64x2 = transmute(vuqaddq_s64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vld1q_u32() { - let e = u32x4::new(1, 2, 3, 4); - let f = [0, 1, 2, 3, 4]; - // do a load that has 4 byte alignment to make sure we're not - // over aligning it - let r: u32x4 = transmute(vld1q_u32(f[1..].as_ptr())); + unsafe fn test_vsqadd_u8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, u8::MAX); + let b = i8x8::new(i8::MIN, -3, -2, -1, 0, 1, 2, 3); + let e = u8x8::new(0, 0, 0, 2, 4, 6, 8, u8::MAX); + let r: u8x8 = transmute(vsqadd_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vsqaddq_u8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, u8::MAX); + let b = i8x16::new(i8::MIN, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7); + let e = u8x16::new(0, 0, 0, 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, u8::MAX); + let r: u8x16 = transmute(vsqaddq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vsqadd_u16() { + let a = u16x4::new(0, 1, 2, u16::MAX); + let b = i16x4::new(i16::MIN, -1, 0, 1); + let e = u16x4::new(0, 0, 2, u16::MAX); + let r: u16x4 = transmute(vsqadd_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vsqaddq_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, u16::MAX); + let b = i16x8::new(i16::MIN, -3, -2, -1, 0, 1, 2, 3); + let e = u16x8::new(0, 0, 0, 2, 4, 6, 8, u16::MAX); + let r: u16x8 = transmute(vsqaddq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vsqadd_u32() { + let a = u32x2::new(0, u32::MAX); + let b = i32x2::new(i32::MIN, 1); + let e = u32x2::new(0, u32::MAX); + let r: u32x2 = transmute(vsqadd_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vsqaddq_u32() { + let a = u32x4::new(0, 1, 2, u32::MAX); + let b = i32x4::new(i32::MIN, -1, 0, 1); + let e = u32x4::new(0, 0, 2, u32::MAX); + let r: u32x4 = transmute(vsqaddq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vsqadd_u64() { + let a = u64x1::new(0); + let b = i64x1::new(i64::MIN); + let e = u64x1::new(0); + let r: u64x1 = transmute(vsqadd_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vsqaddq_u64() { + let a = u64x2::new(0, u64::MAX); + let b = i64x2::new(i64::MIN, 1); + let e = u64x2::new(0, u64::MAX); + let r: u64x2 = transmute(vsqaddq_u64(transmute(a), transmute(b))); assert_eq!(r, e); } @@ -3063,3 +4015,11 @@ mod tests { #[cfg(target_endian = "little")] #[path = "../../arm/neon/table_lookup_tests.rs"] mod table_lookup_tests; + +#[cfg(test)] +#[path = "../../arm/neon/shift_and_insert_tests.rs"] +mod shift_and_insert_tests; + +#[cfg(test)] +#[path = "../../arm/neon/load_tests.rs"] +mod load_tests; diff --git a/library/stdarch/crates/core_arch/src/aarch64/crypto.rs b/library/stdarch/crates/core_arch/src/arm/crypto.rs similarity index 77% rename from library/stdarch/crates/core_arch/src/aarch64/crypto.rs rename to library/stdarch/crates/core_arch/src/arm/crypto.rs index 91269d8052..8361e39646 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/crypto.rs +++ b/library/stdarch/crates/core_arch/src/arm/crypto.rs @@ -2,35 +2,49 @@ use crate::core_arch::arm::{uint32x4_t, uint8x16_t}; #[allow(improper_ctypes)] extern "C" { - #[link_name = "llvm.aarch64.crypto.aese"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.aese")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.aese")] fn vaeseq_u8_(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t; - #[link_name = "llvm.aarch64.crypto.aesd"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.aesd")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.aesd")] fn vaesdq_u8_(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t; - #[link_name = "llvm.aarch64.crypto.aesmc"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.aesmc")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.aesmc")] fn vaesmcq_u8_(data: uint8x16_t) -> uint8x16_t; - #[link_name = "llvm.aarch64.crypto.aesimc"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.aesimc")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.aesimc")] fn vaesimcq_u8_(data: uint8x16_t) -> uint8x16_t; - #[link_name = "llvm.aarch64.crypto.sha1h"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha1h")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha1h")] fn vsha1h_u32_(hash_e: u32) -> u32; - #[link_name = "llvm.aarch64.crypto.sha1su0"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha1su0")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha1su0")] fn vsha1su0q_u32_(w0_3: uint32x4_t, w4_7: uint32x4_t, w8_11: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha1su1"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha1su1")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha1su1")] fn vsha1su1q_u32_(tw0_3: uint32x4_t, w12_15: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha1c"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha1c")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha1c")] fn vsha1cq_u32_(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha1p"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha1p")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha1p")] fn vsha1pq_u32_(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha1m"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha1m")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha1m")] fn vsha1mq_u32_(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha256h"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha256h")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha256h")] fn vsha256hq_u32_(hash_abcd: uint32x4_t, hash_efgh: uint32x4_t, wk: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha256h2"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha256h2")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha256h2")] fn vsha256h2q_u32_(hash_efgh: uint32x4_t, hash_abcd: uint32x4_t, wk: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha256su0"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha256su0")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha256su0")] fn vsha256su0q_u32_(w0_3: uint32x4_t, w4_7: uint32x4_t) -> uint32x4_t; - #[link_name = "llvm.aarch64.crypto.sha256su1"] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.crypto.sha256su1")] + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.sha256su1")] fn vsha256su1q_u32_(tw0_3: uint32x4_t, w8_11: uint32x4_t, w12_15: uint32x4_t) -> uint32x4_t; } @@ -40,6 +54,7 @@ use stdarch_test::assert_instr; /// AES single round encryption. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(aese))] pub unsafe fn vaeseq_u8(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { vaeseq_u8_(data, key) @@ -48,6 +63,7 @@ pub unsafe fn vaeseq_u8(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { /// AES single round decryption. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(aesd))] pub unsafe fn vaesdq_u8(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { vaesdq_u8_(data, key) @@ -56,6 +72,7 @@ pub unsafe fn vaesdq_u8(data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { /// AES mix columns. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(aesmc))] pub unsafe fn vaesmcq_u8(data: uint8x16_t) -> uint8x16_t { vaesmcq_u8_(data) @@ -64,6 +81,7 @@ pub unsafe fn vaesmcq_u8(data: uint8x16_t) -> uint8x16_t { /// AES inverse mix columns. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(aesimc))] pub unsafe fn vaesimcq_u8(data: uint8x16_t) -> uint8x16_t { vaesimcq_u8_(data) @@ -72,6 +90,7 @@ pub unsafe fn vaesimcq_u8(data: uint8x16_t) -> uint8x16_t { /// SHA1 fixed rotate. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha1h))] pub unsafe fn vsha1h_u32(hash_e: u32) -> u32 { vsha1h_u32_(hash_e) @@ -80,6 +99,7 @@ pub unsafe fn vsha1h_u32(hash_e: u32) -> u32 { /// SHA1 hash update accelerator, choose. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha1c))] pub unsafe fn vsha1cq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> uint32x4_t { vsha1cq_u32_(hash_abcd, hash_e, wk) @@ -88,6 +108,7 @@ pub unsafe fn vsha1cq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> /// SHA1 hash update accelerator, majority. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha1m))] pub unsafe fn vsha1mq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> uint32x4_t { vsha1mq_u32_(hash_abcd, hash_e, wk) @@ -96,6 +117,7 @@ pub unsafe fn vsha1mq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> /// SHA1 hash update accelerator, parity. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha1p))] pub unsafe fn vsha1pq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> uint32x4_t { vsha1pq_u32_(hash_abcd, hash_e, wk) @@ -104,6 +126,7 @@ pub unsafe fn vsha1pq_u32(hash_abcd: uint32x4_t, hash_e: u32, wk: uint32x4_t) -> /// SHA1 schedule update accelerator, first part. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha1su0))] pub unsafe fn vsha1su0q_u32(w0_3: uint32x4_t, w4_7: uint32x4_t, w8_11: uint32x4_t) -> uint32x4_t { vsha1su0q_u32_(w0_3, w4_7, w8_11) @@ -112,6 +135,7 @@ pub unsafe fn vsha1su0q_u32(w0_3: uint32x4_t, w4_7: uint32x4_t, w8_11: uint32x4_ /// SHA1 schedule update accelerator, second part. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha1su1))] pub unsafe fn vsha1su1q_u32(tw0_3: uint32x4_t, w12_15: uint32x4_t) -> uint32x4_t { vsha1su1q_u32_(tw0_3, w12_15) @@ -120,6 +144,7 @@ pub unsafe fn vsha1su1q_u32(tw0_3: uint32x4_t, w12_15: uint32x4_t) -> uint32x4_t /// SHA256 hash update accelerator. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha256h))] pub unsafe fn vsha256hq_u32( hash_abcd: uint32x4_t, @@ -132,6 +157,7 @@ pub unsafe fn vsha256hq_u32( /// SHA256 hash update accelerator, upper part. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha256h2))] pub unsafe fn vsha256h2q_u32( hash_efgh: uint32x4_t, @@ -144,6 +170,7 @@ pub unsafe fn vsha256h2q_u32( /// SHA256 schedule update accelerator, first part. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha256su0))] pub unsafe fn vsha256su0q_u32(w0_3: uint32x4_t, w4_7: uint32x4_t) -> uint32x4_t { vsha256su0q_u32_(w0_3, w4_7) @@ -152,6 +179,7 @@ pub unsafe fn vsha256su0q_u32(w0_3: uint32x4_t, w4_7: uint32x4_t) -> uint32x4_t /// SHA256 schedule update accelerator, second part. #[inline] #[target_feature(enable = "crypto")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(test, assert_instr(sha256su1))] pub unsafe fn vsha256su1q_u32( tw0_3: uint32x4_t, @@ -163,7 +191,7 @@ pub unsafe fn vsha256su1q_u32( #[cfg(test)] mod tests { - use crate::core_arch::{aarch64::*, simd::*}; + use crate::core_arch::{arm::*, simd::*}; use std::mem; use stdarch_test::simd_test; diff --git a/library/stdarch/crates/core_arch/src/arm/mod.rs b/library/stdarch/crates/core_arch/src/arm/mod.rs index 5a66ff5f9b..fd0cb2cf8d 100644 --- a/library/stdarch/crates/core_arch/src/arm/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm/mod.rs @@ -29,6 +29,11 @@ mod crc; #[cfg(any(target_arch = "aarch64", target_feature = "v7"))] pub use self::crc::*; +#[cfg(any(target_arch = "aarch64", target_feature = "v7"))] +mod crypto; +#[cfg(any(target_arch = "aarch64", target_feature = "v7"))] +pub use self::crypto::*; + pub use crate::core_arch::acle::*; #[cfg(test)] diff --git a/library/stdarch/crates/core_arch/src/arm/neon/generated.rs b/library/stdarch/crates/core_arch/src/arm/neon/generated.rs index fcf73e71d2..c60ad9cc50 100644 --- a/library/stdarch/crates/core_arch/src/arm/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/arm/neon/generated.rs @@ -2469,6 +2469,454 @@ pub unsafe fn vhsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { vhsubq_s32_(a, b) } +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmax_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v8i8")] + fn vmax_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + } +vmax_s8_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmaxq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v16i8")] + fn vmaxq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + } +vmaxq_s8_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmax_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v4i16")] + fn vmax_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vmax_s16_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmaxq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v8i16")] + fn vmaxq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vmaxq_s16_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmax_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v2i32")] + fn vmax_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vmax_s32_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smax))] +pub unsafe fn vmaxq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smax.v4i32")] + fn vmaxq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vmaxq_s32_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmax_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v8i8")] + fn vmax_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; + } +vmax_u8_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmaxq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v16i8")] + fn vmaxq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; + } +vmaxq_u8_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmax_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v4i16")] + fn vmax_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; + } +vmax_u16_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmaxq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v8i16")] + fn vmaxq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; + } +vmaxq_u16_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmax_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v2i32")] + fn vmax_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; + } +vmax_u32_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umax))] +pub unsafe fn vmaxq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umax.v4i32")] + fn vmaxq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; + } +vmaxq_u32_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] +pub unsafe fn vmax_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v2f32")] + fn vmax_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; + } +vmax_f32_(a, b) +} + +/// Maximum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] +pub unsafe fn vmaxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v4f32")] + fn vmaxq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + } +vmaxq_f32_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vmin_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v8i8")] + fn vmin_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + } +vmin_s8_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vminq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v16i8")] + fn vminq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + } +vminq_s8_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vmin_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v4i16")] + fn vmin_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + } +vmin_s16_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vminq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v8i16")] + fn vminq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + } +vminq_s16_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vmin_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v2i32")] + fn vmin_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + } +vmin_s32_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smin))] +pub unsafe fn vminq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.smin.v4i32")] + fn vminq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; + } +vminq_s32_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vmin_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v8i8")] + fn vmin_u8_(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; + } +vmin_u8_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vminq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v16i8")] + fn vminq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; + } +vminq_u8_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vmin_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v4i16")] + fn vmin_u16_(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; + } +vmin_u16_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vminq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v8i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v8i16")] + fn vminq_u16_(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; + } +vminq_u16_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vmin_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v2i32")] + fn vmin_u32_(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; + } +vmin_u32_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umin))] +pub unsafe fn vminq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vminu.v4i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.umin.v4i32")] + fn vminq_u32_(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; + } +vminq_u32_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] +pub unsafe fn vmin_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v2f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v2f32")] + fn vmin_f32_(a: float32x2_t, b: float32x2_t) -> float32x2_t; + } +vmin_f32_(a, b) +} + +/// Minimum (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] +pub unsafe fn vminq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + #[allow(improper_ctypes)] + extern "C" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4f32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v4f32")] + fn vminq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + } +vminq_f32_(a, b) +} + #[cfg(test)] #[allow(overflowing_literals)] mod test { @@ -4534,4 +4982,256 @@ mod test { let r: i32x4 = transmute(vhsubq_s32(transmute(a), transmute(b))); assert_eq!(r, e); } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_s8() { + let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i8x8 = i8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: i8x8 = i8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let r: i8x8 = transmute(vmax_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_s8() { + let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: i8x16 = i8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let e: i8x16 = i8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 9, 10, 11, 12, 13, 14, 15, 16); + let r: i8x16 = transmute(vmaxq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_s16() { + let a: i16x4 = i16x4::new(1, 2, 3, 4); + let b: i16x4 = i16x4::new(16, 15, 14, 13); + let e: i16x4 = i16x4::new(16, 15, 14, 13); + let r: i16x4 = transmute(vmax_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_s16() { + let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i16x8 = i16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: i16x8 = i16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let r: i16x8 = transmute(vmaxq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_s32() { + let a: i32x2 = i32x2::new(1, 2); + let b: i32x2 = i32x2::new(16, 15); + let e: i32x2 = i32x2::new(16, 15); + let r: i32x2 = transmute(vmax_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_s32() { + let a: i32x4 = i32x4::new(1, 2, 3, 4); + let b: i32x4 = i32x4::new(16, 15, 14, 13); + let e: i32x4 = i32x4::new(16, 15, 14, 13); + let r: i32x4 = transmute(vmaxq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_u8() { + let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u8x8 = u8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: u8x8 = u8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let r: u8x8 = transmute(vmax_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_u8() { + let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: u8x16 = u8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let e: u8x16 = u8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 9, 10, 11, 12, 13, 14, 15, 16); + let r: u8x16 = transmute(vmaxq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_u16() { + let a: u16x4 = u16x4::new(1, 2, 3, 4); + let b: u16x4 = u16x4::new(16, 15, 14, 13); + let e: u16x4 = u16x4::new(16, 15, 14, 13); + let r: u16x4 = transmute(vmax_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_u16() { + let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u16x8 = u16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: u16x8 = u16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let r: u16x8 = transmute(vmaxq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_u32() { + let a: u32x2 = u32x2::new(1, 2); + let b: u32x2 = u32x2::new(16, 15); + let e: u32x2 = u32x2::new(16, 15); + let r: u32x2 = transmute(vmax_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_u32() { + let a: u32x4 = u32x4::new(1, 2, 3, 4); + let b: u32x4 = u32x4::new(16, 15, 14, 13); + let e: u32x4 = u32x4::new(16, 15, 14, 13); + let r: u32x4 = transmute(vmaxq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmax_f32() { + let a: f32x2 = f32x2::new(1.0, -2.0); + let b: f32x2 = f32x2::new(0.0, 3.0); + let e: f32x2 = f32x2::new(1.0, 3.0); + let r: f32x2 = transmute(vmax_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_f32() { + let a: f32x4 = f32x4::new(1.0, -2.0, 3.0, -4.0); + let b: f32x4 = f32x4::new(0.0, 3.0, 2.0, 8.0); + let e: f32x4 = f32x4::new(1.0, 3.0, 3.0, 8.0); + let r: f32x4 = transmute(vmaxq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_s8() { + let a: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i8x8 = i8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: i8x8 = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: i8x8 = transmute(vmin_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_s8() { + let a: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: i8x16 = i8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let e: i8x16 = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1); + let r: i8x16 = transmute(vminq_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_s16() { + let a: i16x4 = i16x4::new(1, 2, 3, 4); + let b: i16x4 = i16x4::new(16, 15, 14, 13); + let e: i16x4 = i16x4::new(1, 2, 3, 4); + let r: i16x4 = transmute(vmin_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_s16() { + let a: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: i16x8 = i16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: i16x8 = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: i16x8 = transmute(vminq_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_s32() { + let a: i32x2 = i32x2::new(1, 2); + let b: i32x2 = i32x2::new(16, 15); + let e: i32x2 = i32x2::new(1, 2); + let r: i32x2 = transmute(vmin_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_s32() { + let a: i32x4 = i32x4::new(1, 2, 3, 4); + let b: i32x4 = i32x4::new(16, 15, 14, 13); + let e: i32x4 = i32x4::new(1, 2, 3, 4); + let r: i32x4 = transmute(vminq_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_u8() { + let a: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u8x8 = u8x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: u8x8 = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u8x8 = transmute(vmin_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_u8() { + let a: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b: u8x16 = u8x16::new(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let e: u8x16 = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1); + let r: u8x16 = transmute(vminq_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_u16() { + let a: u16x4 = u16x4::new(1, 2, 3, 4); + let b: u16x4 = u16x4::new(16, 15, 14, 13); + let e: u16x4 = u16x4::new(1, 2, 3, 4); + let r: u16x4 = transmute(vmin_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_u16() { + let a: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b: u16x8 = u16x8::new(16, 15, 14, 13, 12, 11, 10, 9); + let e: u16x8 = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u16x8 = transmute(vminq_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_u32() { + let a: u32x2 = u32x2::new(1, 2); + let b: u32x2 = u32x2::new(16, 15); + let e: u32x2 = u32x2::new(1, 2); + let r: u32x2 = transmute(vmin_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_u32() { + let a: u32x4 = u32x4::new(1, 2, 3, 4); + let b: u32x4 = u32x4::new(16, 15, 14, 13); + let e: u32x4 = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vminq_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmin_f32() { + let a: f32x2 = f32x2::new(1.0, -2.0); + let b: f32x2 = f32x2::new(0.0, 3.0); + let e: f32x2 = f32x2::new(0.0, -2.0); + let r: f32x2 = transmute(vmin_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vminq_f32() { + let a: f32x4 = f32x4::new(1.0, -2.0, 3.0, -4.0); + let b: f32x4 = f32x4::new(0.0, 3.0, 2.0, 8.0); + let e: f32x4 = f32x4::new(0.0, -2.0, 2.0, -4.0); + let r: f32x4 = transmute(vminq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } } diff --git a/library/stdarch/crates/core_arch/src/arm/neon/load_tests.rs b/library/stdarch/crates/core_arch/src/arm/neon/load_tests.rs new file mode 100644 index 0000000000..82e2f74955 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/arm/neon/load_tests.rs @@ -0,0 +1,208 @@ +//! Tests for ARM+v7+neon load (vld1) intrinsics. +//! +//! These are included in `{arm, aarch64}::neon`. + +use super::*; + +#[cfg(target_arch = "arm")] +use crate::core_arch::arm::*; + +#[cfg(target_arch = "aarch64")] +use crate::core_arch::aarch64::*; + +use crate::core_arch::simd::*; +use std::mem; +use stdarch_test::simd_test; +#[simd_test(enable = "neon")] +unsafe fn test_vld1_s8() { + let a: [i8; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: i8x8 = transmute(vld1_s8(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_s8() { + let a: [i8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r: i8x16 = transmute(vld1q_s8(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_s16() { + let a: [i16; 5] = [0, 1, 2, 3, 4]; + let e = i16x4::new(1, 2, 3, 4); + let r: i16x4 = transmute(vld1_s16(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_s16() { + let a: [i16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: i16x8 = transmute(vld1q_s16(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_s32() { + let a: [i32; 3] = [0, 1, 2]; + let e = i32x2::new(1, 2); + let r: i32x2 = transmute(vld1_s32(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_s32() { + let a: [i32; 5] = [0, 1, 2, 3, 4]; + let e = i32x4::new(1, 2, 3, 4); + let r: i32x4 = transmute(vld1q_s32(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_s64() { + let a: [i64; 2] = [0, 1]; + let e = i64x1::new(1); + let r: i64x1 = transmute(vld1_s64(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_s64() { + let a: [i64; 3] = [0, 1, 2]; + let e = i64x2::new(1, 2); + let r: i64x2 = transmute(vld1q_s64(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_u8() { + let a: [u8; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u8x8 = transmute(vld1_u8(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_u8() { + let a: [u8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r: u8x16 = transmute(vld1q_u8(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_u16() { + let a: [u16; 5] = [0, 1, 2, 3, 4]; + let e = u16x4::new(1, 2, 3, 4); + let r: u16x4 = transmute(vld1_u16(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_u16() { + let a: [u16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u16x8 = transmute(vld1q_u16(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_u32() { + let a: [u32; 3] = [0, 1, 2]; + let e = u32x2::new(1, 2); + let r: u32x2 = transmute(vld1_u32(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_u32() { + let a: [u32; 5] = [0, 1, 2, 3, 4]; + let e = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vld1q_u32(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_u64() { + let a: [u64; 2] = [0, 1]; + let e = u64x1::new(1); + let r: u64x1 = transmute(vld1_u64(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_u64() { + let a: [u64; 3] = [0, 1, 2]; + let e = u64x2::new(1, 2); + let r: u64x2 = transmute(vld1q_u64(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_p8() { + let a: [p8; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u8x8 = transmute(vld1_p8(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_p8() { + let a: [p8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let e = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r: u8x16 = transmute(vld1q_p8(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_p16() { + let a: [p16; 5] = [0, 1, 2, 3, 4]; + let e = u16x4::new(1, 2, 3, 4); + let r: u16x4 = transmute(vld1_p16(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_p16() { + let a: [p16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let e = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u16x8 = transmute(vld1q_p16(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1_f32() { + let a: [f32; 3] = [0., 1., 2.]; + let e = f32x2::new(1., 2.); + let r: f32x2 = transmute(vld1_f32(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_f32() { + let a: [f32; 5] = [0., 1., 2., 3., 4.]; + let e = f32x4::new(1., 2., 3., 4.); + let r: f32x4 = transmute(vld1q_f32(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[cfg(target_arch = "aarch64")] +#[simd_test(enable = "neon")] +unsafe fn test_vld1_f64() { + let a: [f64; 2] = [0., 1.]; + let e = f64x1::new(1.); + let r: f64x1 = transmute(vld1_f64(a[1..].as_ptr())); + assert_eq!(r, e) +} + +#[cfg(target_arch = "aarch64")] +#[simd_test(enable = "neon")] +unsafe fn test_vld1q_f64() { + let a: [f64; 3] = [0., 1., 2.]; + let e = f64x2::new(1., 2.); + let r: f64x2 = transmute(vld1q_f64(a[1..].as_ptr())); + assert_eq!(r, e) +} diff --git a/library/stdarch/crates/core_arch/src/arm/neon/mod.rs b/library/stdarch/crates/core_arch/src/arm/neon/mod.rs index 03fa069c11..4f6ab5aef1 100644 --- a/library/stdarch/crates/core_arch/src/arm/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm/neon/mod.rs @@ -5,25 +5,34 @@ mod generated; #[rustfmt::skip] pub use self::generated::*; -use crate::{core_arch::simd_llvm::*, hint::unreachable_unchecked, mem::transmute, ptr}; +#[cfg(target_arch = "arm")] +use crate::mem::align_of; +use crate::{ + core_arch::simd::*, core_arch::simd_llvm::*, hint::unreachable_unchecked, mem::transmute, +}; #[cfg(test)] use stdarch_test::assert_instr; +pub(crate) type p8 = u8; +pub(crate) type p16 = u16; +pub(crate) type p64 = u64; +pub(crate) type p128 = u128; + types! { /// ARM-specific 64-bit wide vector of eight packed `i8`. pub struct int8x8_t(i8, i8, i8, i8, i8, i8, i8, i8); /// ARM-specific 64-bit wide vector of eight packed `u8`. pub struct uint8x8_t(u8, u8, u8, u8, u8, u8, u8, u8); - /// ARM-specific 64-bit wide polynomial vector of eight packed `u8`. - pub struct poly8x8_t(u8, u8, u8, u8, u8, u8, u8, u8); + /// ARM-specific 64-bit wide polynomial vector of eight packed `p8`. + pub struct poly8x8_t(p8, p8, p8, p8, p8, p8, p8, p8); /// ARM-specific 64-bit wide vector of four packed `i16`. pub struct int16x4_t(i16, i16, i16, i16); /// ARM-specific 64-bit wide vector of four packed `u16`. pub struct uint16x4_t(u16, u16, u16, u16); // FIXME: ARM-specific 64-bit wide vector of four packed `f16`. // pub struct float16x4_t(f16, f16, f16, f16); - /// ARM-specific 64-bit wide vector of four packed `u16`. - pub struct poly16x4_t(u16, u16, u16, u16); + /// ARM-specific 64-bit wide vector of four packed `p16`. + pub struct poly16x4_t(p16, p16, p16, p16); /// ARM-specific 64-bit wide vector of two packed `i32`. pub struct int32x2_t(i32, i32); /// ARM-specific 64-bit wide vector of two packed `u32`. @@ -34,21 +43,23 @@ types! { pub struct int64x1_t(i64); /// ARM-specific 64-bit wide vector of one packed `u64`. pub struct uint64x1_t(u64); + /// ARM-specific 64-bit wide vector of one packed `p64`. + pub struct poly64x1_t(p64); /// ARM-specific 128-bit wide vector of sixteen packed `i8`. pub struct int8x16_t( - i8, i8 ,i8, i8, i8, i8 ,i8, i8, - i8, i8 ,i8, i8, i8, i8 ,i8, i8, + i8, i8, i8, i8, i8, i8 ,i8, i8, + i8, i8, i8, i8, i8, i8 ,i8, i8, ); /// ARM-specific 128-bit wide vector of sixteen packed `u8`. pub struct uint8x16_t( u8, u8 ,u8, u8, u8, u8 ,u8, u8, u8, u8 ,u8, u8, u8, u8 ,u8, u8, ); - /// ARM-specific 128-bit wide vector of sixteen packed `u8`. + /// ARM-specific 128-bit wide vector of sixteen packed `p8`. pub struct poly8x16_t( - u8, u8, u8, u8, u8, u8, u8, u8, - u8, u8, u8, u8, u8, u8, u8, u8 + p8, p8, p8, p8, p8, p8, p8, p8, + p8, p8, p8, p8, p8, p8, p8, p8, ); /// ARM-specific 128-bit wide vector of eight packed `i16`. pub struct int16x8_t(i16, i16, i16, i16, i16, i16, i16, i16); @@ -56,8 +67,8 @@ types! { pub struct uint16x8_t(u16, u16, u16, u16, u16, u16, u16, u16); // FIXME: ARM-specific 128-bit wide vector of eight packed `f16`. // pub struct float16x8_t(f16, f16, f16, f16, f16, f16, f16); - /// ARM-specific 128-bit wide vector of eight packed `u16`. - pub struct poly16x8_t(u16, u16, u16, u16, u16, u16, u16, u16); + /// ARM-specific 128-bit wide vector of eight packed `p16`. + pub struct poly16x8_t(p16, p16, p16, p16, p16, p16, p16, p16); /// ARM-specific 128-bit wide vector of four packed `i32`. pub struct int32x4_t(i32, i32, i32, i32); /// ARM-specific 128-bit wide vector of four packed `u32`. @@ -68,6 +79,8 @@ types! { pub struct int64x2_t(i64, i64); /// ARM-specific 128-bit wide vector of two packed `u64`. pub struct uint64x2_t(u64, u64); + /// ARM-specific 128-bit wide vector of two packed `p64`. + pub struct poly64x2_t(p64, p64); } /// ARM-specific type containing two `int8x8_t` vectors. @@ -176,6 +189,16 @@ extern "C" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxp.v2f32")] fn vpmaxf_v2f32(a: float32x2_t, b: float32x2_t) -> float32x2_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vraddhn.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.raddhn.v8i8")] + fn vraddhn_s16_(a: int16x8_t, b: int16x8_t) -> int8x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vraddhn.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.raddhn.v4i16")] + fn vraddhn_s32_(a: int32x4_t, b: int32x4_t) -> int16x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vraddhn.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.raddhn.v2i32")] + fn vraddhn_s64_(a: int64x2_t, b: int64x2_t) -> int32x2_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v4i16")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v4i16")] fn vpadd_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; @@ -189,17 +212,117 @@ extern "C" { #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v16i8")] fn vpaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmax.v4f32")] - fn vmaxq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4f32")] - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmin.v4f32")] - fn vminq_f32_(a: float32x4_t, b: float32x4_t) -> float32x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddls.v4i16.v8i8")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.saddlp.v4i16.v8i8" + )] + fn vpaddl_s8_(a: int8x8_t) -> int16x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddls.v2i32.v4i16")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.saddlp.v2i32.v4i16" + )] + fn vpaddl_s16_(a: int16x4_t) -> int32x2_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddls.v1i64.v2i32")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.saddlp.v1i64.v2i32" + )] + fn vpaddl_s32_(a: int32x2_t) -> int64x1_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddls.v8i16.v16i8")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.saddlp.v8i16.v16i8" + )] + fn vpaddlq_s8_(a: int8x16_t) -> int16x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddls.v4i32.v8i16")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.saddlp.v4i32.v8i16" + )] + fn vpaddlq_s16_(a: int16x8_t) -> int32x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddls.v2i64.v4i32")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.saddlp.v2i64.v4i32" + )] + fn vpaddlq_s32_(a: int32x4_t) -> int64x2_t; + + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddlu.v4i16.v8i8")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.uaddlp.v4i16.v8i8" + )] + fn vpaddl_u8_(a: uint8x8_t) -> uint16x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddlu.v2i32.v4i16")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.uaddlp.v2i32.v4i16" + )] + fn vpaddl_u16_(a: uint16x4_t) -> uint32x2_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddlu.v1i64.v2i32")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.uaddlp.v1i64.v2i32" + )] + fn vpaddl_u32_(a: uint32x2_t) -> uint64x1_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddlu.v8i16.v16i8")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.uaddlp.v8i16.v16i8" + )] + fn vpaddlq_u8_(a: uint8x16_t) -> uint16x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddlu.v4i32.v8i16")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.uaddlp.v4i32.v8i16" + )] + fn vpaddlq_u16_(a: uint16x8_t) -> uint32x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpaddlu.v2i64.v4i32")] + #[cfg_attr( + target_arch = "aarch64", + link_name = "llvm.aarch64.neon.uaddlp.v2i64.v4i32" + )] + fn vpaddlq_u32_(a: uint32x4_t) -> uint64x2_t; + + #[cfg_attr(target_arch = "arm", link_name = "llvm.ctpop.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.ctpop.v8i8")] + fn vcnt_s8_(a: int8x8_t) -> int8x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.ctpop.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.ctpop.v16i8")] + fn vcntq_s8_(a: int8x16_t) -> int8x16_t; } #[cfg(target_arch = "arm")] #[allow(improper_ctypes)] extern "C" { + #[link_name = "llvm.arm.neon.vpadals.v4i16.v8i8"] + fn vpadal_s8_(a: int16x4_t, b: int8x8_t) -> int16x4_t; + #[link_name = "llvm.arm.neon.vpadals.v2i32.v4i16"] + fn vpadal_s16_(a: int32x2_t, b: int16x4_t) -> int32x2_t; + #[link_name = "llvm.arm.neon.vpadals.v1i64.v2i32"] + fn vpadal_s32_(a: int64x1_t, b: int32x2_t) -> int64x1_t; + #[link_name = "llvm.arm.neon.vpadals.v8i16.v16i8"] + fn vpadalq_s8_(a: int16x8_t, b: int8x16_t) -> int16x8_t; + #[link_name = "llvm.arm.neon.vpadals.v4i32.v8i16"] + fn vpadalq_s16_(a: int32x4_t, b: int16x8_t) -> int32x4_t; + #[link_name = "llvm.arm.neon.vpadals.v2i64.v4i32"] + fn vpadalq_s32_(a: int64x2_t, b: int32x4_t) -> int64x2_t; + + #[link_name = "llvm.arm.neon.vpadalu.v4i16.v8i8"] + fn vpadal_u8_(a: uint16x4_t, b: uint8x8_t) -> uint16x4_t; + #[link_name = "llvm.arm.neon.vpadalu.v2i32.v4i16"] + fn vpadal_u16_(a: uint32x2_t, b: uint16x4_t) -> uint32x2_t; + #[link_name = "llvm.arm.neon.vpadalu.v1i64.v2i32"] + fn vpadal_u32_(a: uint64x1_t, b: uint32x2_t) -> uint64x1_t; + #[link_name = "llvm.arm.neon.vpadalu.v8i16.v16i8"] + fn vpadalq_u8_(a: uint16x8_t, b: uint8x16_t) -> uint16x8_t; + #[link_name = "llvm.arm.neon.vpadalu.v4i32.v8i16"] + fn vpadalq_u16_(a: uint32x4_t, b: uint16x8_t) -> uint32x4_t; + #[link_name = "llvm.arm.neon.vpadalu.v2i64.v4i32"] + fn vpadalq_u32_(a: uint64x2_t, b: uint32x4_t) -> uint64x2_t; + #[link_name = "llvm.arm.neon.vtbl1"] fn vtbl1(a: int8x8_t, b: int8x8_t) -> int8x8_t; #[link_name = "llvm.arm.neon.vtbl2"] @@ -224,2008 +347,5542 @@ extern "C" { d: int8x8_t, e: int8x8_t, ) -> int8x8_t; - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v4f32.p0i8")] - fn vld1q_v4f32(addr: *const u8, align: u32) -> float32x4_t; - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v4i32.p0i8")] - fn vld1q_v4i32(addr: *const u8, align: u32) -> int32x4_t; + + #[link_name = "llvm.arm.neon.vshiftins.v8i8"] + fn vshiftins_v8i8(a: int8x8_t, b: int8x8_t, shift: int8x8_t) -> int8x8_t; + #[link_name = "llvm.arm.neon.vshiftins.v16i8"] + fn vshiftins_v16i8(a: int8x16_t, b: int8x16_t, shift: int8x16_t) -> int8x16_t; + #[link_name = "llvm.arm.neon.vshiftins.v4i16"] + fn vshiftins_v4i16(a: int16x4_t, b: int16x4_t, shift: int16x4_t) -> int16x4_t; + #[link_name = "llvm.arm.neon.vshiftins.v8i16"] + fn vshiftins_v8i16(a: int16x8_t, b: int16x8_t, shift: int16x8_t) -> int16x8_t; + #[link_name = "llvm.arm.neon.vshiftins.v2i32"] + fn vshiftins_v2i32(a: int32x2_t, b: int32x2_t, shift: int32x2_t) -> int32x2_t; + #[link_name = "llvm.arm.neon.vshiftins.v4i32"] + fn vshiftins_v4i32(a: int32x4_t, b: int32x4_t, shift: int32x4_t) -> int32x4_t; + #[link_name = "llvm.arm.neon.vshiftins.v1i64"] + fn vshiftins_v1i64(a: int64x1_t, b: int64x1_t, shift: int64x1_t) -> int64x1_t; + #[link_name = "llvm.arm.neon.vshiftins.v2i64"] + fn vshiftins_v2i64(a: int64x2_t, b: int64x2_t, shift: int64x2_t) -> int64x2_t; + + #[link_name = "llvm.arm.neon.vld1.v8i8.p0i8"] + fn vld1_v8i8(addr: *const i8, align: i32) -> int8x8_t; + #[link_name = "llvm.arm.neon.vld1.v16i8.p0i8"] + fn vld1q_v16i8(addr: *const i8, align: i32) -> int8x16_t; + #[link_name = "llvm.arm.neon.vld1.v4i16.p0i8"] + fn vld1_v4i16(addr: *const i8, align: i32) -> int16x4_t; + #[link_name = "llvm.arm.neon.vld1.v8i16.p0i8"] + fn vld1q_v8i16(addr: *const i8, align: i32) -> int16x8_t; + #[link_name = "llvm.arm.neon.vld1.v2i32.p0i8"] + fn vld1_v2i32(addr: *const i8, align: i32) -> int32x2_t; + #[link_name = "llvm.arm.neon.vld1.v4i32.p0i8"] + fn vld1q_v4i32(addr: *const i8, align: i32) -> int32x4_t; + #[link_name = "llvm.arm.neon.vld1.v1i64.p0i8"] + fn vld1_v1i64(addr: *const i8, align: i32) -> int64x1_t; + #[link_name = "llvm.arm.neon.vld1.v2i64.p0i8"] + fn vld1q_v2i64(addr: *const i8, align: i32) -> int64x2_t; + #[link_name = "llvm.arm.neon.vld1.v2f32.p0i8"] + fn vld1_v2f32(addr: *const i8, align: i32) -> float32x2_t; + #[link_name = "llvm.arm.neon.vld1.v4f32.p0i8"] + fn vld1q_v4f32(addr: *const i8, align: i32) -> float32x4_t; +} + +/// Load multiple single-element structures to one, two, three, or four registers. +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.8"))] +pub unsafe fn vld1_s8(ptr: *const i8) -> int8x8_t { + vld1_v8i8(ptr as *const i8, align_of::() as i32) } -/// Absolute value (wrapping). +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] -pub unsafe fn vabs_s8(a: int8x8_t) -> int8x8_t { - vabs_s8_(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.8"))] +pub unsafe fn vld1q_s8(ptr: *const i8) -> int8x16_t { + vld1q_v16i8(ptr as *const i8, align_of::() as i32) } -/// Absolute value (wrapping). + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] -pub unsafe fn vabs_s16(a: int16x4_t) -> int16x4_t { - vabs_s16_(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.16"))] +pub unsafe fn vld1_s16(ptr: *const i16) -> int16x4_t { + vld1_v4i16(ptr as *const i8, align_of::() as i32) } -/// Absolute value (wrapping). + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] -pub unsafe fn vabs_s32(a: int32x2_t) -> int32x2_t { - vabs_s32_(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.16"))] +pub unsafe fn vld1q_s16(ptr: *const i16) -> int16x8_t { + vld1q_v8i16(ptr as *const i8, align_of::() as i32) } -/// Absolute value (wrapping). + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] -pub unsafe fn vabsq_s8(a: int8x16_t) -> int8x16_t { - vabsq_s8_(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vldr))] +pub unsafe fn vld1_s32(ptr: *const i32) -> int32x2_t { + vld1_v2i32(ptr as *const i8, align_of::() as i32) } -/// Absolute value (wrapping). + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] -pub unsafe fn vabsq_s16(a: int16x8_t) -> int16x8_t { - vabsq_s16_(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_s32(ptr: *const i32) -> int32x4_t { + vld1q_v4i32(ptr as *const i8, align_of::() as i32) } -/// Absolute value (wrapping). + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] -pub unsafe fn vabsq_s32(a: int32x4_t) -> int32x4_t { - vabsq_s32_(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vldr))] +pub unsafe fn vld1_s64(ptr: *const i64) -> int64x1_t { + vld1_v1i64(ptr as *const i8, align_of::() as i32) } -/// Add pairwise. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] -pub unsafe fn vpadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - vpadd_s16_(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.64"))] +pub unsafe fn vld1q_s64(ptr: *const i64) -> int64x2_t { + vld1q_v2i64(ptr as *const i8, align_of::() as i32) } -/// Add pairwise. + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] -pub unsafe fn vpadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - vpadd_s32_(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.8"))] +pub unsafe fn vld1_u8(ptr: *const u8) -> uint8x8_t { + transmute(vld1_v8i8(ptr as *const i8, align_of::() as i32)) } -/// Add pairwise. + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] -pub unsafe fn vpadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - vpadd_s8_(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.8"))] +pub unsafe fn vld1q_u8(ptr: *const u8) -> uint8x16_t { + transmute(vld1q_v16i8(ptr as *const i8, align_of::() as i32)) } -/// Add pairwise. + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] -pub unsafe fn vpadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - transmute(vpadd_s16_(transmute(a), transmute(b))) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.16"))] +pub unsafe fn vld1_u16(ptr: *const u16) -> uint16x4_t { + transmute(vld1_v4i16(ptr as *const i8, align_of::() as i32)) } -/// Add pairwise. + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] -pub unsafe fn vpadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - transmute(vpadd_s32_(transmute(a), transmute(b))) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.16"))] +pub unsafe fn vld1q_u16(ptr: *const u16) -> uint16x8_t { + transmute(vld1q_v8i16(ptr as *const i8, align_of::() as i32)) } -/// Add pairwise. + +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] -pub unsafe fn vpadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - transmute(vpadd_s8_(transmute(a), transmute(b))) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vldr))] +pub unsafe fn vld1_u32(ptr: *const u32) -> uint32x2_t { + transmute(vld1_v2i32(ptr as *const i8, align_of::() as i32)) } -/// Unsigned saturating extract narrow. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn.u64))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] -pub unsafe fn vqmovn_u64(a: uint64x2_t) -> uint32x2_t { - vqmovn_u64_(a) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_u32(ptr: *const u32) -> uint32x4_t { + transmute(vld1q_v4i32(ptr as *const i8, align_of::() as i32)) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vldr))] +pub unsafe fn vld1_u64(ptr: *const u64) -> uint64x1_t { + transmute(vld1_v1i64(ptr as *const i8, align_of::() as i32)) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.64"))] +pub unsafe fn vld1q_u64(ptr: *const u64) -> uint64x2_t { + transmute(vld1q_v2i64(ptr as *const i8, align_of::() as i32)) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.8"))] +pub unsafe fn vld1_p8(ptr: *const p8) -> poly8x8_t { + transmute(vld1_v8i8(ptr as *const i8, align_of::() as i32)) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.8"))] +pub unsafe fn vld1q_p8(ptr: *const p8) -> poly8x16_t { + transmute(vld1q_v16i8(ptr as *const i8, align_of::() as i32)) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.16"))] +pub unsafe fn vld1_p16(ptr: *const p16) -> poly16x4_t { + transmute(vld1_v4i16(ptr as *const i8, align_of::() as i32)) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.16"))] +pub unsafe fn vld1q_p16(ptr: *const p16) -> poly16x8_t { + transmute(vld1q_v8i16(ptr as *const i8, align_of::() as i32)) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vldr))] +pub unsafe fn vld1_f32(ptr: *const f32) -> float32x2_t { + vld1_v2f32(ptr as *const i8, align_of::() as i32) } -/// Vector add. +/// Load multiple single-element structures to one, two, three, or four registers. #[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - simd_add(a, b) +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_f32(ptr: *const f32) -> float32x4_t { + vld1q_v4f32(ptr as *const i8, align_of::() as i32) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8", lane = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 7))] +pub unsafe fn vld1_lane_s8(ptr: *const i8, src: int8x8_t, lane: i32) -> int8x8_t { + assert!( + 0 <= lane && lane <= 7, + "must have 0 ≤ lane ≤ 7, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8", lane = 15))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 15))] +pub unsafe fn vld1q_lane_s8(ptr: *const i8, src: int8x16_t, lane: i32) -> int8x16_t { + assert!( + 0 <= lane && lane <= 15, + "must have 0 ≤ lane ≤ 15, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16", lane = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 3))] +pub unsafe fn vld1_lane_s16(ptr: *const i16, src: int16x4_t, lane: i32) -> int16x4_t { + assert!( + 0 <= lane && lane <= 3, + "must have 0 ≤ lane ≤ 3, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16", lane = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 7))] +pub unsafe fn vld1q_lane_s16(ptr: *const i16, src: int16x8_t, lane: i32) -> int16x8_t { + assert!( + 0 <= lane && lane <= 7, + "must have 0 ≤ lane ≤ 7, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32", lane = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 1))] +pub unsafe fn vld1_lane_s32(ptr: *const i32, src: int32x2_t, lane: i32) -> int32x2_t { + assert!( + 0 <= lane && lane <= 1, + "must have 0 ≤ lane ≤ 1, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] -pub unsafe fn vaddq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32", lane = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 3))] +pub unsafe fn vld1q_lane_s32(ptr: *const i32, src: int32x4_t, lane: i32) -> int32x4_t { + assert!( + 0 <= lane && lane <= 3, + "must have 0 ≤ lane ≤ 3, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fadd))] -pub unsafe fn vadd_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr", lane = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr, lane = 0))] +pub unsafe fn vld1_lane_s64(ptr: *const i64, src: int64x1_t, lane: i32) -> int64x1_t { + assert!( + 0 <= lane && lane <= 0, + "must have 0 ≤ lane ≤ 0, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fadd))] -pub unsafe fn vaddq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr", lane = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 1))] +pub unsafe fn vld1q_lane_s64(ptr: *const i64, src: int64x2_t, lane: i32) -> int64x2_t { + assert!( + 0 <= lane && lane <= 1, + "must have 0 ≤ lane ≤ 1, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl))] -pub unsafe fn vaddl_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { - let a: int16x8_t = simd_cast(a); - let b: int16x8_t = simd_cast(b); - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8", lane = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 7))] +pub unsafe fn vld1_lane_u8(ptr: *const u8, src: uint8x8_t, lane: i32) -> uint8x8_t { + assert!( + 0 <= lane && lane <= 7, + "must have 0 ≤ lane ≤ 7, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl))] -pub unsafe fn vaddl_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { - let a: int32x4_t = simd_cast(a); - let b: int32x4_t = simd_cast(b); - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8", lane = 15))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 15))] +pub unsafe fn vld1q_lane_u8(ptr: *const u8, src: uint8x16_t, lane: i32) -> uint8x16_t { + assert!( + 0 <= lane && lane <= 15, + "must have 0 ≤ lane ≤ 15, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl))] -pub unsafe fn vaddl_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { - let a: int64x2_t = simd_cast(a); - let b: int64x2_t = simd_cast(b); - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16", lane = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 3))] +pub unsafe fn vld1_lane_u16(ptr: *const u16, src: uint16x4_t, lane: i32) -> uint16x4_t { + assert!( + 0 <= lane && lane <= 3, + "must have 0 ≤ lane ≤ 3, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl))] -pub unsafe fn vaddl_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { - let a: uint16x8_t = simd_cast(a); - let b: uint16x8_t = simd_cast(b); - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16", lane = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 7))] +pub unsafe fn vld1q_lane_u16(ptr: *const u16, src: uint16x8_t, lane: i32) -> uint16x8_t { + assert!( + 0 <= lane && lane <= 7, + "must have 0 ≤ lane ≤ 7, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl))] -pub unsafe fn vaddl_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { - let a: uint32x4_t = simd_cast(a); - let b: uint32x4_t = simd_cast(b); - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32", lane = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 1))] +pub unsafe fn vld1_lane_u32(ptr: *const u32, src: uint32x2_t, lane: i32) -> uint32x2_t { + assert!( + 0 <= lane && lane <= 1, + "must have 0 ≤ lane ≤ 1, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long add. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl))] -pub unsafe fn vaddl_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { - let a: uint64x2_t = simd_cast(a); - let b: uint64x2_t = simd_cast(b); - simd_add(a, b) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32", lane = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 3))] +pub unsafe fn vld1q_lane_u32(ptr: *const u32, src: uint32x4_t, lane: i32) -> uint32x4_t { + assert!( + 0 <= lane && lane <= 3, + "must have 0 ≤ lane ≤ 3, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector narrow integer. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] -pub unsafe fn vmovn_s16(a: int16x8_t) -> int8x8_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr", lane = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr, lane = 0))] +pub unsafe fn vld1_lane_u64(ptr: *const u64, src: uint64x1_t, lane: i32) -> uint64x1_t { + assert!( + 0 <= lane && lane <= 0, + "must have 0 ≤ lane ≤ 0, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector narrow integer. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] -pub unsafe fn vmovn_s32(a: int32x4_t) -> int16x4_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr", lane = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 1))] +pub unsafe fn vld1q_lane_u64(ptr: *const u64, src: uint64x2_t, lane: i32) -> uint64x2_t { + assert!( + 0 <= lane && lane <= 1, + "must have 0 ≤ lane ≤ 1, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector narrow integer. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] -pub unsafe fn vmovn_s64(a: int64x2_t) -> int32x2_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8", lane = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 7))] +pub unsafe fn vld1_lane_p8(ptr: *const p8, src: poly8x8_t, lane: i32) -> poly8x8_t { + assert!( + 0 <= lane && lane <= 7, + "must have 0 ≤ lane ≤ 7, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector narrow integer. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] -pub unsafe fn vmovn_u16(a: uint16x8_t) -> uint8x8_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8", lane = 15))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 15))] +pub unsafe fn vld1q_lane_p8(ptr: *const p8, src: poly8x16_t, lane: i32) -> poly8x16_t { + assert!( + 0 <= lane && lane <= 15, + "must have 0 ≤ lane ≤ 15, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector narrow integer. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] -pub unsafe fn vmovn_u32(a: uint32x4_t) -> uint16x4_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16", lane = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 3))] +pub unsafe fn vld1_lane_p16(ptr: *const p16, src: poly16x4_t, lane: i32) -> poly16x4_t { + assert!( + 0 <= lane && lane <= 3, + "must have 0 ≤ lane ≤ 3, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector narrow integer. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] -pub unsafe fn vmovn_u64(a: uint64x2_t) -> uint32x2_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16", lane = 7))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 7))] +pub unsafe fn vld1q_lane_p16(ptr: *const p16, src: poly16x8_t, lane: i32) -> poly16x8_t { + assert!( + 0 <= lane && lane <= 7, + "must have 0 ≤ lane ≤ 7, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long move. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sxtl))] -pub unsafe fn vmovl_s8(a: int8x8_t) -> int16x8_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32", lane = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 1))] +pub unsafe fn vld1_lane_f32(ptr: *const f32, src: float32x2_t, lane: i32) -> float32x2_t { + assert!( + 0 <= lane && lane <= 1, + "must have 0 ≤ lane ≤ 1, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long move. +/// Load one single-element structure to one lane of one register. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sxtl))] -pub unsafe fn vmovl_s16(a: int16x4_t) -> int32x4_t { - simd_cast(a) +#[rustc_args_required_const(2)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32", lane = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1, lane = 3))] +pub unsafe fn vld1q_lane_f32(ptr: *const f32, src: float32x4_t, lane: i32) -> float32x4_t { + assert!( + 0 <= lane && lane <= 3, + "must have 0 ≤ lane ≤ 3, but lane = {}", + lane + ); + simd_insert(src, lane as u32, *ptr) } -/// Vector long move. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sxtl))] -pub unsafe fn vmovl_s32(a: int32x2_t) -> int64x2_t { - simd_cast(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_s8(ptr: *const i8) -> int8x8_t { + let x = vld1_lane_s8(ptr, transmute(i8x8::splat(0)), 0); + simd_shuffle8(x, x, [0, 0, 0, 0, 0, 0, 0, 0]) } -/// Vector long move. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uxtl))] -pub unsafe fn vmovl_u8(a: uint8x8_t) -> uint16x8_t { - simd_cast(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_s8(ptr: *const i8) -> int8x16_t { + let x = vld1q_lane_s8(ptr, transmute(i8x16::splat(0)), 0); + simd_shuffle16(x, x, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) } -/// Vector long move. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uxtl))] -pub unsafe fn vmovl_u16(a: uint16x4_t) -> uint32x4_t { - simd_cast(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_s16(ptr: *const i16) -> int16x4_t { + let x = vld1_lane_s16(ptr, transmute(i16x4::splat(0)), 0); + simd_shuffle4(x, x, [0, 0, 0, 0]) } -/// Vector long move. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uxtl))] -pub unsafe fn vmovl_u32(a: uint32x2_t) -> uint64x2_t { - simd_cast(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_s16(ptr: *const i16) -> int16x8_t { + let x = vld1q_lane_s16(ptr, transmute(i16x8::splat(0)), 0); + simd_shuffle8(x, x, [0, 0, 0, 0, 0, 0, 0, 0]) } -/// Reciprocal square-root estimate. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frsqrte))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsqrte))] -pub unsafe fn vrsqrte_f32(a: float32x2_t) -> float32x2_t { - frsqrte_v2f32(a) +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_s32(ptr: *const i32) -> int32x2_t { + let x = vld1_lane_s32(ptr, transmute(i32x2::splat(0)), 0); + simd_shuffle2(x, x, [0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvn_s8(a: int8x8_t) -> int8x8_t { - let b = int8x8_t(-1, -1, -1, -1, -1, -1, -1, -1); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_s32(ptr: *const i32) -> int32x4_t { + let x = vld1q_lane_s32(ptr, transmute(i32x4::splat(0)), 0); + simd_shuffle4(x, x, [0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvnq_s8(a: int8x16_t) -> int8x16_t { - let b = int8x16_t( - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - ); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +pub unsafe fn vld1_dup_s64(ptr: *const i64) -> int64x1_t { + #[cfg(target_arch = "aarch64")] + use crate::core_arch::aarch64::vld1_s64; + vld1_s64(ptr) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvn_s16(a: int16x4_t) -> int16x4_t { - let b = int16x4_t(-1, -1, -1, -1); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_s64(ptr: *const i64) -> int64x2_t { + let x = vld1q_lane_s64(ptr, transmute(i64x2::splat(0)), 0); + simd_shuffle2(x, x, [0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvnq_s16(a: int16x8_t) -> int16x8_t { - let b = int16x8_t(-1, -1, -1, -1, -1, -1, -1, -1); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_u8(ptr: *const u8) -> uint8x8_t { + let x = vld1_lane_u8(ptr, transmute(u8x8::splat(0)), 0); + simd_shuffle8(x, x, [0, 0, 0, 0, 0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvn_s32(a: int32x2_t) -> int32x2_t { - let b = int32x2_t(-1, -1); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_u8(ptr: *const u8) -> uint8x16_t { + let x = vld1q_lane_u8(ptr, transmute(u8x16::splat(0)), 0); + simd_shuffle16(x, x, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvnq_s32(a: int32x4_t) -> int32x4_t { - let b = int32x4_t(-1, -1, -1, -1); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_u16(ptr: *const u16) -> uint16x4_t { + let x = vld1_lane_u16(ptr, transmute(u16x4::splat(0)), 0); + simd_shuffle4(x, x, [0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvn_u8(a: uint8x8_t) -> uint8x8_t { - let b = uint8x8_t(255, 255, 255, 255, 255, 255, 255, 255); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_u16(ptr: *const u16) -> uint16x8_t { + let x = vld1q_lane_u16(ptr, transmute(u16x8::splat(0)), 0); + simd_shuffle8(x, x, [0, 0, 0, 0, 0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvnq_u8(a: uint8x16_t) -> uint8x16_t { - let b = uint8x16_t( - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - ); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_u32(ptr: *const u32) -> uint32x2_t { + let x = vld1_lane_u32(ptr, transmute(u32x2::splat(0)), 0); + simd_shuffle2(x, x, [0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvn_u16(a: uint16x4_t) -> uint16x4_t { - let b = uint16x4_t(65_535, 65_535, 65_535, 65_535); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_u32(ptr: *const u32) -> uint32x4_t { + let x = vld1q_lane_u32(ptr, transmute(u32x4::splat(0)), 0); + simd_shuffle4(x, x, [0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvnq_u16(a: uint16x8_t) -> uint16x8_t { - let b = uint16x8_t( - 65_535, 65_535, 65_535, 65_535, 65_535, 65_535, 65_535, 65_535, - ); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ldr))] +pub unsafe fn vld1_dup_u64(ptr: *const u64) -> uint64x1_t { + #[cfg(target_arch = "aarch64")] + use crate::core_arch::aarch64::vld1_u64; + vld1_u64(ptr) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvn_u32(a: uint32x2_t) -> uint32x2_t { - let b = uint32x2_t(4_294_967_295, 4_294_967_295); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vldr"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_u64(ptr: *const u64) -> uint64x2_t { + let x = vld1q_lane_u64(ptr, transmute(u64x2::splat(0)), 0); + simd_shuffle2(x, x, [0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvnq_u32(a: uint32x4_t) -> uint32x4_t { - let b = uint32x4_t(4_294_967_295, 4_294_967_295, 4_294_967_295, 4_294_967_295); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_p8(ptr: *const p8) -> poly8x8_t { + let x = vld1_lane_p8(ptr, transmute(u8x8::splat(0)), 0); + simd_shuffle8(x, x, [0, 0, 0, 0, 0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvn_p8(a: poly8x8_t) -> poly8x8_t { - let b = poly8x8_t(255, 255, 255, 255, 255, 255, 255, 255); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_p8(ptr: *const p8) -> poly8x16_t { + let x = vld1q_lane_p8(ptr, transmute(u8x16::splat(0)), 0); + simd_shuffle16(x, x, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) } -/// Vector bitwise not. +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] -pub unsafe fn vmvnq_p8(a: poly8x16_t) -> poly8x16_t { - let b = poly8x16_t( - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - ); - simd_xor(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_p16(ptr: *const p16) -> poly16x4_t { + let x = vld1_lane_p16(ptr, transmute(u16x4::splat(0)), 0); + simd_shuffle4(x, x, [0, 0, 0, 0]) } -/// Folding minimum of adjacent pairs +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sminp))] -pub unsafe fn vpmin_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - vpmins_v8i8(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_p16(ptr: *const p16) -> poly16x8_t { + let x = vld1q_lane_p16(ptr, transmute(u16x8::splat(0)), 0); + simd_shuffle8(x, x, [0, 0, 0, 0, 0, 0, 0, 0]) } -/// Folding minimum of adjacent pairs +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sminp))] -pub unsafe fn vpmin_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - vpmins_v4i16(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1_dup_f32(ptr: *const f32) -> float32x2_t { + let x = vld1_lane_f32(ptr, transmute(f32x2::splat(0.)), 0); + simd_shuffle2(x, x, [0, 0]) } -/// Folding minimum of adjacent pairs +/// Load one single-element structure and Replicate to all lanes (of one register). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sminp))] -pub unsafe fn vpmin_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - vpmins_v2i32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_f32(ptr: *const f32) -> float32x4_t { + let x = vld1q_lane_f32(ptr, transmute(f32x4::splat(0.)), 0); + simd_shuffle4(x, x, [0, 0, 0, 0]) } -/// Folding minimum of adjacent pairs +/// Absolute value (wrapping). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uminp))] -pub unsafe fn vpmin_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - vpminu_v8i8(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] +pub unsafe fn vabs_s8(a: int8x8_t) -> int8x8_t { + vabs_s8_(a) } - -/// Folding minimum of adjacent pairs +/// Absolute value (wrapping). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uminp))] -pub unsafe fn vpmin_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - vpminu_v4i16(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] +pub unsafe fn vabs_s16(a: int16x4_t) -> int16x4_t { + vabs_s16_(a) } - -/// Folding minimum of adjacent pairs +/// Absolute value (wrapping). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uminp))] -pub unsafe fn vpmin_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - vpminu_v2i32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] +pub unsafe fn vabs_s32(a: int32x2_t) -> int32x2_t { + vabs_s32_(a) } - -/// Folding minimum of adjacent pairs +/// Absolute value (wrapping). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fminp))] -pub unsafe fn vpmin_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - vpminf_v2f32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] +pub unsafe fn vabsq_s8(a: int8x16_t) -> int8x16_t { + vabsq_s8_(a) } - -/// Folding maximum of adjacent pairs +/// Absolute value (wrapping). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smaxp))] -pub unsafe fn vpmax_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - vpmaxs_v8i8(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] +pub unsafe fn vabsq_s16(a: int16x8_t) -> int16x8_t { + vabsq_s16_(a) } - -/// Folding maximum of adjacent pairs +/// Absolute value (wrapping). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smaxp))] -pub unsafe fn vpmax_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - vpmaxs_v4i16(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vabs))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(abs))] +pub unsafe fn vabsq_s32(a: int32x4_t) -> int32x4_t { + vabsq_s32_(a) } -/// Folding maximum of adjacent pairs +/// Add pairwise. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smaxp))] -pub unsafe fn vpmax_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - vpmaxs_v2i32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + vpadd_s16_(a, b) } - -/// Folding maximum of adjacent pairs +/// Add pairwise. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umaxp))] -pub unsafe fn vpmax_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - vpmaxu_v8i8(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + vpadd_s32_(a, b) } - -/// Folding maximum of adjacent pairs +/// Add pairwise. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umaxp))] -pub unsafe fn vpmax_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - vpmaxu_v4i16(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + vpadd_s8_(a, b) } - -/// Folding maximum of adjacent pairs +/// Add pairwise. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umaxp))] -pub unsafe fn vpmax_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - vpmaxu_v2i32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + transmute(vpadd_s16_(transmute(a), transmute(b))) } - -/// Folding maximum of adjacent pairs +/// Add pairwise. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmaxp))] -pub unsafe fn vpmax_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { - vpmaxf_v2f32(a, b) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + transmute(vpadd_s32_(transmute(a), transmute(b))) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + transmute(vpadd_s8_(transmute(a), transmute(b))) } -/// Table look-up +/// Unsigned saturating extract narrow. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl1_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - vtbl1(a, b) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vqmovn.u64))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uqxtn))] +pub unsafe fn vqmovn_u64(a: uint64x2_t) -> uint32x2_t { + vqmovn_u64_(a) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl1_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - transmute(vtbl1(transmute(a), transmute(b))) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl1_p8(a: poly8x8_t, b: uint8x8_t) -> poly8x8_t { - transmute(vtbl1(transmute(a), transmute(b))) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl2_s8(a: int8x8x2_t, b: int8x8_t) -> int8x8_t { - vtbl2(a.0, a.1, b) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl2_u8(a: uint8x8x2_t, b: uint8x8_t) -> uint8x8_t { - transmute(vtbl2(transmute(a.0), transmute(a.1), transmute(b))) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl2_p8(a: poly8x8x2_t, b: uint8x8_t) -> poly8x8_t { - transmute(vtbl2(transmute(a.0), transmute(a.1), transmute(b))) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl3_s8(a: int8x8x3_t, b: int8x8_t) -> int8x8_t { - vtbl3(a.0, a.1, a.2, b) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl3_u8(a: uint8x8x3_t, b: uint8x8_t) -> uint8x8_t { - transmute(vtbl3( - transmute(a.0), - transmute(a.1), - transmute(a.2), - transmute(b), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl3_p8(a: poly8x8x3_t, b: uint8x8_t) -> poly8x8_t { - transmute(vtbl3( - transmute(a.0), - transmute(a.1), - transmute(a.2), - transmute(b), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl4_s8(a: int8x8x4_t, b: int8x8_t) -> int8x8_t { - vtbl4(a.0, a.1, a.2, a.3, b) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl4_u8(a: uint8x8x4_t, b: uint8x8_t) -> uint8x8_t { - transmute(vtbl4( - transmute(a.0), - transmute(a.1), - transmute(a.2), - transmute(a.3), - transmute(b), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + simd_add(a, b) } -/// Table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbl))] -pub unsafe fn vtbl4_p8(a: poly8x8x4_t, b: uint8x8_t) -> poly8x8_t { - transmute(vtbl4( - transmute(a.0), - transmute(a.1), - transmute(a.2), - transmute(a.3), - transmute(b), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + simd_add(a, b) } -/// Extended table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx1_s8(a: int8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { - vtbx1(a, b, c) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + simd_add(a, b) } -/// Extended table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx1_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { - transmute(vtbx1(transmute(a), transmute(b), transmute(c))) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + simd_add(a, b) } -/// Extended table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx1_p8(a: poly8x8_t, b: poly8x8_t, c: uint8x8_t) -> poly8x8_t { - transmute(vtbx1(transmute(a), transmute(b), transmute(c))) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(add))] +pub unsafe fn vaddq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { + simd_add(a, b) } -/// Extended table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx2_s8(a: int8x8_t, b: int8x8x2_t, c: int8x8_t) -> int8x8_t { - vtbx2(a, b.0, b.1, c) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fadd))] +pub unsafe fn vadd_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + simd_add(a, b) } -/// Extended table look-up +/// Vector add. #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx2_u8(a: uint8x8_t, b: uint8x8x2_t, c: uint8x8_t) -> uint8x8_t { - transmute(vtbx2( - transmute(a), - transmute(b.0), - transmute(b.1), - transmute(c), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fadd))] +pub unsafe fn vaddq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + simd_add(a, b) } -/// Extended table look-up +/// Signed Add Long (vector). #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx2_p8(a: poly8x8_t, b: poly8x8x2_t, c: uint8x8_t) -> poly8x8_t { - transmute(vtbx2( - transmute(a), - transmute(b.0), - transmute(b.1), - transmute(c), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl))] +pub unsafe fn vaddl_s8(a: int8x8_t, b: int8x8_t) -> int16x8_t { + let a: int16x8_t = simd_cast(a); + let b: int16x8_t = simd_cast(b); + simd_add(a, b) } -/// Extended table look-up +/// Signed Add Long (vector). #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx3_s8(a: int8x8_t, b: int8x8x3_t, c: int8x8_t) -> int8x8_t { - vtbx3(a, b.0, b.1, b.2, c) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl))] +pub unsafe fn vaddl_s16(a: int16x4_t, b: int16x4_t) -> int32x4_t { + let a: int32x4_t = simd_cast(a); + let b: int32x4_t = simd_cast(b); + simd_add(a, b) } -/// Extended table look-up +/// Signed Add Long (vector). #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx3_u8(a: uint8x8_t, b: uint8x8x3_t, c: uint8x8_t) -> uint8x8_t { - transmute(vtbx3( - transmute(a), - transmute(b.0), - transmute(b.1), - transmute(b.2), - transmute(c), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl))] +pub unsafe fn vaddl_s32(a: int32x2_t, b: int32x2_t) -> int64x2_t { + let a: int64x2_t = simd_cast(a); + let b: int64x2_t = simd_cast(b); + simd_add(a, b) } -/// Extended table look-up +/// Unsigned Add Long (vector). #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx3_p8(a: poly8x8_t, b: poly8x8x3_t, c: uint8x8_t) -> poly8x8_t { - transmute(vtbx3( - transmute(a), - transmute(b.0), - transmute(b.1), - transmute(b.2), - transmute(c), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl))] +pub unsafe fn vaddl_u8(a: uint8x8_t, b: uint8x8_t) -> uint16x8_t { + let a: uint16x8_t = simd_cast(a); + let b: uint16x8_t = simd_cast(b); + simd_add(a, b) } -/// Extended table look-up +/// Unsigned Add Long (vector). #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx4_s8(a: int8x8_t, b: int8x8x4_t, c: int8x8_t) -> int8x8_t { - vtbx4(a, b.0, b.1, b.2, b.3, c) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl))] +pub unsafe fn vaddl_u16(a: uint16x4_t, b: uint16x4_t) -> uint32x4_t { + let a: uint32x4_t = simd_cast(a); + let b: uint32x4_t = simd_cast(b); + simd_add(a, b) } -/// Extended table look-up +/// Unsigned Add Long (vector). #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx4_u8(a: uint8x8_t, b: uint8x8x4_t, c: uint8x8_t) -> uint8x8_t { - transmute(vtbx4( - transmute(a), - transmute(b.0), - transmute(b.1), - transmute(b.2), - transmute(b.3), - transmute(c), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl))] +pub unsafe fn vaddl_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { + let a: uint64x2_t = simd_cast(a); + let b: uint64x2_t = simd_cast(b); + simd_add(a, b) } -/// Extended table look-up +/// Signed Add Long (vector, high half). #[inline] -#[cfg(target_arch = "arm")] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,v7")] -#[cfg_attr(test, assert_instr(vtbx))] -pub unsafe fn vtbx4_p8(a: poly8x8_t, b: poly8x8x4_t, c: uint8x8_t) -> poly8x8_t { - transmute(vtbx4( - transmute(a), - transmute(b.0), - transmute(b.1), - transmute(b.2), - transmute(b.3), - transmute(c), - )) +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl2))] +pub unsafe fn vaddl_high_s8(a: int8x16_t, b: int8x16_t) -> int16x8_t { + let a: int8x8_t = simd_shuffle8(a, a, [8, 9, 10, 11, 12, 13, 14, 15]); + let b: int8x8_t = simd_shuffle8(b, b, [8, 9, 10, 11, 12, 13, 14, 15]); + let a: int16x8_t = simd_cast(a); + let b: int16x8_t = simd_cast(b); + simd_add(a, b) } -/// Move vector element to general-purpose register +/// Signed Add Long (vector, high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[rustc_args_required_const(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 1))] -// Based on the discussion in https://github.com/rust-lang/stdarch/pull/792 -// `mov` seems to be an acceptable intrinsic to compile to -// #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(vmov, imm5 = 1))] -pub unsafe fn vgetq_lane_u64(v: uint64x2_t, imm5: i32) -> u64 { - assert!(imm5 >= 0 && imm5 <= 1); - simd_extract(v, imm5 as u32) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl2))] +pub unsafe fn vaddl_high_s16(a: int16x8_t, b: int16x8_t) -> int32x4_t { + let a: int16x4_t = simd_shuffle4(a, a, [4, 5, 6, 7]); + let b: int16x4_t = simd_shuffle4(b, b, [4, 5, 6, 7]); + let a: int32x4_t = simd_cast(a); + let b: int32x4_t = simd_cast(b); + simd_add(a, b) } -/// Move vector element to general-purpose register +/// Signed Add Long (vector, high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[rustc_args_required_const(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 0))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmov, imm5 = 0))] -// FIXME: no 32bit this seems to be turned into two vmov.32 instructions -// validate correctness -pub unsafe fn vget_lane_u64(v: uint64x1_t, imm5: i32) -> u64 { - assert!(imm5 == 0); - simd_extract(v, 0) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddl2))] +pub unsafe fn vaddl_high_s32(a: int32x4_t, b: int32x4_t) -> int64x2_t { + let a: int32x2_t = simd_shuffle2(a, a, [2, 3]); + let b: int32x2_t = simd_shuffle2(b, b, [2, 3]); + let a: int64x2_t = simd_cast(a); + let b: int64x2_t = simd_cast(b); + simd_add(a, b) } -/// Move vector element to general-purpose register +/// Unsigned Add Long (vector, high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[rustc_args_required_const(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u16", imm5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, imm5 = 2))] -pub unsafe fn vgetq_lane_u16(v: uint16x8_t, imm5: i32) -> u16 { - assert!(imm5 >= 0 && imm5 <= 7); - simd_extract(v, imm5 as u32) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl2))] +pub unsafe fn vaddl_high_u8(a: uint8x16_t, b: uint8x16_t) -> uint16x8_t { + let a: uint8x8_t = simd_shuffle8(a, a, [8, 9, 10, 11, 12, 13, 14, 15]); + let b: uint8x8_t = simd_shuffle8(b, b, [8, 9, 10, 11, 12, 13, 14, 15]); + let a: uint16x8_t = simd_cast(a); + let b: uint16x8_t = simd_cast(b); + simd_add(a, b) } -/// Move vector element to general-purpose register +/// Unsigned Add Long (vector, high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[rustc_args_required_const(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 2))] -pub unsafe fn vgetq_lane_u32(v: uint32x4_t, imm5: i32) -> u32 { - assert!(imm5 >= 0 && imm5 <= 3); - simd_extract(v, imm5 as u32) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl2))] +pub unsafe fn vaddl_high_u16(a: uint16x8_t, b: uint16x8_t) -> uint32x4_t { + let a: uint16x4_t = simd_shuffle4(a, a, [4, 5, 6, 7]); + let b: uint16x4_t = simd_shuffle4(b, b, [4, 5, 6, 7]); + let a: uint32x4_t = simd_cast(a); + let b: uint32x4_t = simd_cast(b); + simd_add(a, b) } -/// Move vector element to general-purpose register +/// Unsigned Add Long (vector, high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[rustc_args_required_const(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 2))] -pub unsafe fn vgetq_lane_s32(v: int32x4_t, imm5: i32) -> i32 { - assert!(imm5 >= 0 && imm5 <= 3); - simd_extract(v, imm5 as u32) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddl2))] +pub unsafe fn vaddl_high_u32(a: uint32x4_t, b: uint32x4_t) -> uint64x2_t { + let a: uint32x2_t = simd_shuffle2(a, a, [2, 3]); + let b: uint32x2_t = simd_shuffle2(b, b, [2, 3]); + let a: uint64x2_t = simd_cast(a); + let b: uint64x2_t = simd_cast(b); + simd_add(a, b) } -/// Move vector element to general-purpose register +/// Signed Add Wide. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[rustc_args_required_const(1)] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u8", imm5 = 2))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, imm5 = 2))] -pub unsafe fn vget_lane_u8(v: uint8x8_t, imm5: i32) -> u8 { - assert!(imm5 >= 0 && imm5 <= 7); - simd_extract(v, imm5 as u32) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddw))] +pub unsafe fn vaddw_s8(a: int16x8_t, b: int8x8_t) -> int16x8_t { + let b: int16x8_t = simd_cast(b); + simd_add(a, b) } -/// Duplicate vector element to vector or scalar +/// Signed Add Wide. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] -pub unsafe fn vdupq_n_s8(value: i8) -> int8x16_t { - int8x16_t( - value, value, value, value, value, value, value, value, value, value, value, value, value, - value, value, value, - ) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddw))] +pub unsafe fn vaddw_s16(a: int32x4_t, b: int16x4_t) -> int32x4_t { + let b: int32x4_t = simd_cast(b); + simd_add(a, b) } -/// Duplicate vector element to vector or scalar +/// Signed Add Wide. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] -pub unsafe fn vdupq_n_u8(value: u8) -> uint8x16_t { - uint8x16_t( - value, value, value, value, value, value, value, value, value, value, value, value, value, - value, value, value, - ) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddw))] +pub unsafe fn vaddw_s32(a: int64x2_t, b: int32x2_t) -> int64x2_t { + let b: int64x2_t = simd_cast(b); + simd_add(a, b) } -/// Duplicate vector element to vector or scalar +/// Unsigned Add Wide. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.8"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] -pub unsafe fn vmovq_n_u8(value: u8) -> uint8x16_t { - vdupq_n_u8(value) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddw))] +pub unsafe fn vaddw_u8(a: uint16x8_t, b: uint8x8_t) -> uint16x8_t { + let b: uint16x8_t = simd_cast(b); + simd_add(a, b) } -/// Vector reinterpret cast operation +/// Unsigned Add Wide. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(nop))] -pub unsafe fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddw))] +pub unsafe fn vaddw_u16(a: uint32x4_t, b: uint16x4_t) -> uint32x4_t { + let b: uint32x4_t = simd_cast(b); + simd_add(a, b) } -/// Vector reinterpret cast operation +/// Unsigned Add Wide. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(nop))] -pub unsafe fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddw))] +pub unsafe fn vaddw_u32(a: uint64x2_t, b: uint32x2_t) -> uint64x2_t { + let b: uint64x2_t = simd_cast(b); + simd_add(a, b) } -/// Vector reinterpret cast operation +/// Signed Add Wide (high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(nop))] -pub unsafe fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddw2))] +pub unsafe fn vaddw_high_s8(a: int16x8_t, b: int8x16_t) -> int16x8_t { + let b: int8x8_t = simd_shuffle8(b, b, [8, 9, 10, 11, 12, 13, 14, 15]); + let b: int16x8_t = simd_cast(b); + simd_add(a, b) } -/// Vector reinterpret cast operation +/// Signed Add Wide (high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(nop))] -pub unsafe fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddw2))] +pub unsafe fn vaddw_high_s16(a: int32x4_t, b: int16x8_t) -> int32x4_t { + let b: int16x4_t = simd_shuffle4(b, b, [4, 5, 6, 7]); + let b: int32x4_t = simd_cast(b); + simd_add(a, b) } -/// Vector reinterpret cast operation +/// Signed Add Wide (high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(nop))] -pub unsafe fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddw2))] +pub unsafe fn vaddw_high_s32(a: int64x2_t, b: int32x4_t) -> int64x2_t { + let b: int32x2_t = simd_shuffle2(b, b, [2, 3]); + let b: int64x2_t = simd_cast(b); + simd_add(a, b) } -/// Vector reinterpret cast operation +/// Unsigned Add Wide (high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(nop))] -pub unsafe fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { - transmute(a) +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddw2))] +pub unsafe fn vaddw_high_u8(a: uint16x8_t, b: uint8x16_t) -> uint16x8_t { + let b: uint8x8_t = simd_shuffle8(b, b, [8, 9, 10, 11, 12, 13, 14, 15]); + let b: uint16x8_t = simd_cast(b); + simd_add(a, b) } -/// Unsigned shift right +/// Unsigned Add Wide (high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u8", imm3 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr("ushr", imm3 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn vshrq_n_u8(a: uint8x16_t, imm3: i32) -> uint8x16_t { - if imm3 < 0 || imm3 > 7 { - unreachable_unchecked(); - } else { - uint8x16_t( - a.0 >> imm3, - a.1 >> imm3, - a.2 >> imm3, - a.3 >> imm3, - a.4 >> imm3, - a.5 >> imm3, - a.6 >> imm3, - a.7 >> imm3, - a.8 >> imm3, - a.9 >> imm3, - a.10 >> imm3, - a.11 >> imm3, - a.12 >> imm3, - a.13 >> imm3, - a.14 >> imm3, - a.15 >> imm3, - ) - } +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddw2))] +pub unsafe fn vaddw_high_u16(a: uint32x4_t, b: uint16x8_t) -> uint32x4_t { + let b: uint16x4_t = simd_shuffle4(b, b, [4, 5, 6, 7]); + let b: uint32x4_t = simd_cast(b); + simd_add(a, b) } -/// Shift right +/// Unsigned Add Wide (high half). #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshl.s8", imm3 = 1))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, imm3 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn vshlq_n_u8(a: uint8x16_t, imm3: i32) -> uint8x16_t { - if imm3 < 0 || imm3 > 7 { - unreachable_unchecked(); - } else { - uint8x16_t( - a.0 << imm3, - a.1 << imm3, - a.2 << imm3, - a.3 << imm3, - a.4 << imm3, - a.5 << imm3, - a.6 << imm3, - a.7 << imm3, - a.8 << imm3, - a.9 << imm3, - a.10 << imm3, - a.11 << imm3, - a.12 << imm3, - a.13 << imm3, - a.14 << imm3, - a.15 << imm3, - ) - } +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddw))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddw2))] +pub unsafe fn vaddw_high_u32(a: uint64x2_t, b: uint32x4_t) -> uint64x2_t { + let b: uint32x2_t = simd_shuffle2(b, b, [2, 3]); + let b: uint64x2_t = simd_cast(b); + simd_add(a, b) } -/// Extract vector from pair of vectors +/// Add returning High Narrow. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", n = 3))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, n = 3))] -#[rustc_args_required_const(2)] -pub unsafe fn vextq_s8(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t { - if n < 0 || n > 15 { - unreachable_unchecked(); - }; - match n & 0b1111 { - 0 => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), - 1 => simd_shuffle16( - a, - b, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - ), - 2 => simd_shuffle16( - a, - b, - [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], - ), - 3 => simd_shuffle16( - a, - b, - [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], - ), - 4 => simd_shuffle16( - a, - b, - [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], - ), - 5 => simd_shuffle16( - a, - b, - [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], - ), - 6 => simd_shuffle16( - a, - b, - [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], - ), - 7 => simd_shuffle16( - a, - b, - [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22], - ), - 8 => simd_shuffle16( - a, - b, - [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], - ), - 9 => simd_shuffle16( - a, - b, - [ - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - ], - ), - 10 => simd_shuffle16( - a, - b, - [ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - ], - ), - 11 => simd_shuffle16( - a, - b, - [ - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - ], - ), - 12 => simd_shuffle16( - a, - b, - [ - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - ], - ), - 13 => simd_shuffle16( - a, - b, - [ - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - ], - ), - 14 => simd_shuffle16( - a, - b, - [ - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - ], - ), - 15 => simd_shuffle16( - a, - b, - [ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - ], - ), - _ => unreachable_unchecked(), - } +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn))] +pub unsafe fn vaddhn_s16(a: int16x8_t, b: int16x8_t) -> int8x8_t { + simd_cast(simd_shr(simd_add(a, b), int16x8_t(8, 8, 8, 8, 8, 8, 8, 8))) } -/// Extract vector from pair of vectors +/// Add returning High Narrow. #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", n = 3))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, n = 3))] -#[rustc_args_required_const(2)] -pub unsafe fn vextq_u8(a: uint8x16_t, b: uint8x16_t, n: i32) -> uint8x16_t { - if n < 0 || n > 15 { - unreachable_unchecked(); - }; - match n & 0b1111 { - 0 => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), - 1 => simd_shuffle16( - a, - b, - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - ), - 2 => simd_shuffle16( - a, - b, - [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], - ), - 3 => simd_shuffle16( - a, - b, - [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], - ), - 4 => simd_shuffle16( - a, - b, - [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], - ), - 5 => simd_shuffle16( - a, - b, - [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], - ), - 6 => simd_shuffle16( - a, - b, - [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], - ), - 7 => simd_shuffle16( - a, - b, - [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22], - ), - 8 => simd_shuffle16( - a, - b, - [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], - ), - 9 => simd_shuffle16( - a, - b, - [ - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - ], - ), - 10 => simd_shuffle16( - a, - b, - [ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - ], - ), - 11 => simd_shuffle16( - a, - b, - [ - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - ], - ), - 12 => simd_shuffle16( - a, - b, - [ - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - ], - ), - 13 => simd_shuffle16( - a, - b, - [ - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - ], - ), - 14 => simd_shuffle16( - a, - b, - [ - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - ], - ), - 15 => simd_shuffle16( - a, - b, - [ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - ], - ), - _ => unreachable_unchecked(), +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn))] +pub unsafe fn vaddhn_s32(a: int32x4_t, b: int32x4_t) -> int16x4_t { + simd_cast(simd_shr(simd_add(a, b), int32x4_t(16, 16, 16, 16))) +} + +/// Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn))] +pub unsafe fn vaddhn_s64(a: int64x2_t, b: int64x2_t) -> int32x2_t { + simd_cast(simd_shr(simd_add(a, b), int64x2_t(32, 32))) +} + +/// Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn))] +pub unsafe fn vaddhn_u16(a: uint16x8_t, b: uint16x8_t) -> uint8x8_t { + simd_cast(simd_shr(simd_add(a, b), uint16x8_t(8, 8, 8, 8, 8, 8, 8, 8))) +} + +/// Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn))] +pub unsafe fn vaddhn_u32(a: uint32x4_t, b: uint32x4_t) -> uint16x4_t { + simd_cast(simd_shr(simd_add(a, b), uint32x4_t(16, 16, 16, 16))) +} + +/// Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn))] +pub unsafe fn vaddhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { + simd_cast(simd_shr(simd_add(a, b), uint64x2_t(32, 32))) +} + +/// Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn2))] +pub unsafe fn vaddhn_high_s16(r: int8x8_t, a: int16x8_t, b: int16x8_t) -> int8x16_t { + let x = simd_cast(simd_shr(simd_add(a, b), int16x8_t(8, 8, 8, 8, 8, 8, 8, 8))); + simd_shuffle16(r, x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +} + +/// Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn2))] +pub unsafe fn vaddhn_high_s32(r: int16x4_t, a: int32x4_t, b: int32x4_t) -> int16x8_t { + let x = simd_cast(simd_shr(simd_add(a, b), int32x4_t(16, 16, 16, 16))); + simd_shuffle8(r, x, [0, 1, 2, 3, 4, 5, 6, 7]) +} + +/// Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn2))] +pub unsafe fn vaddhn_high_s64(r: int32x2_t, a: int64x2_t, b: int64x2_t) -> int32x4_t { + let x = simd_cast(simd_shr(simd_add(a, b), int64x2_t(32, 32))); + simd_shuffle4(r, x, [0, 1, 2, 3]) +} + +/// Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn2))] +pub unsafe fn vaddhn_high_u16(r: uint8x8_t, a: uint16x8_t, b: uint16x8_t) -> uint8x16_t { + let x = simd_cast(simd_shr(simd_add(a, b), uint16x8_t(8, 8, 8, 8, 8, 8, 8, 8))); + simd_shuffle16(r, x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +} + +/// Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn2))] +pub unsafe fn vaddhn_high_u32(r: uint16x4_t, a: uint32x4_t, b: uint32x4_t) -> uint16x8_t { + let x = simd_cast(simd_shr(simd_add(a, b), uint32x4_t(16, 16, 16, 16))); + simd_shuffle8(r, x, [0, 1, 2, 3, 4, 5, 6, 7]) +} + +/// Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vaddhn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addhn2))] +pub unsafe fn vaddhn_high_u64(r: uint32x2_t, a: uint64x2_t, b: uint64x2_t) -> uint32x4_t { + let x = simd_cast(simd_shr(simd_add(a, b), uint64x2_t(32, 32))); + simd_shuffle4(r, x, [0, 1, 2, 3]) +} + +/// Rounding Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn))] +pub unsafe fn vraddhn_s16(a: int16x8_t, b: int16x8_t) -> int8x8_t { + vraddhn_s16_(a, b) +} + +/// Rounding Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn))] +pub unsafe fn vraddhn_s32(a: int32x4_t, b: int32x4_t) -> int16x4_t { + vraddhn_s32_(a, b) +} + +/// Rounding Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i64))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn))] +pub unsafe fn vraddhn_s64(a: int64x2_t, b: int64x2_t) -> int32x2_t { + vraddhn_s64_(a, b) +} + +/// Rounding Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn))] +pub unsafe fn vraddhn_u16(a: uint16x8_t, b: uint16x8_t) -> uint8x8_t { + transmute(vraddhn_s16_(transmute(a), transmute(b))) +} + +/// Rounding Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn))] +pub unsafe fn vraddhn_u32(a: uint32x4_t, b: uint32x4_t) -> uint16x4_t { + transmute(vraddhn_s32_(transmute(a), transmute(b))) +} + +/// Rounding Add returning High Narrow. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i64))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn))] +pub unsafe fn vraddhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { + transmute(vraddhn_s64_(transmute(a), transmute(b))) +} + +/// Rounding Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn2))] +pub unsafe fn vraddhn_high_s16(r: int8x8_t, a: int16x8_t, b: int16x8_t) -> int8x16_t { + let x = vraddhn_s16_(a, b); + simd_shuffle16(r, x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +} + +/// Rounding Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn2))] +pub unsafe fn vraddhn_high_s32(r: int16x4_t, a: int32x4_t, b: int32x4_t) -> int16x8_t { + let x = vraddhn_s32_(a, b); + simd_shuffle8(r, x, [0, 1, 2, 3, 4, 5, 6, 7]) +} + +/// Rounding Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i64))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn2))] +pub unsafe fn vraddhn_high_s64(r: int32x2_t, a: int64x2_t, b: int64x2_t) -> int32x4_t { + let x = vraddhn_s64_(a, b); + simd_shuffle4(r, x, [0, 1, 2, 3]) +} + +/// Rounding Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn2))] +pub unsafe fn vraddhn_high_u16(r: uint8x8_t, a: uint16x8_t, b: uint16x8_t) -> uint8x16_t { + let x: uint8x8_t = transmute(vraddhn_s16_(transmute(a), transmute(b))); + simd_shuffle16(r, x, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +} + +/// Rounding Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn2))] +pub unsafe fn vraddhn_high_u32(r: uint16x4_t, a: uint32x4_t, b: uint32x4_t) -> uint16x8_t { + let x: uint16x4_t = transmute(vraddhn_s32_(transmute(a), transmute(b))); + simd_shuffle8(r, x, [0, 1, 2, 3, 4, 5, 6, 7]) +} + +/// Rounding Add returning High Narrow (high half). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vraddhn.i64))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(raddhn2))] +pub unsafe fn vraddhn_high_u64(r: uint32x2_t, a: uint64x2_t, b: uint64x2_t) -> uint32x4_t { + let x: uint32x2_t = transmute(vraddhn_s64_(transmute(a), transmute(b))); + simd_shuffle4(r, x, [0, 1, 2, 3]) +} + +/// Signed Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.s8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddlp))] +pub unsafe fn vpaddl_s8(a: int8x8_t) -> int16x4_t { + vpaddl_s8_(a) +} + +/// Signed Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.s16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddlp))] +pub unsafe fn vpaddl_s16(a: int16x4_t) -> int32x2_t { + vpaddl_s16_(a) +} + +/// Signed Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.s32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddlp))] +pub unsafe fn vpaddl_s32(a: int32x2_t) -> int64x1_t { + vpaddl_s32_(a) +} + +/// Signed Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.s8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddlp))] +pub unsafe fn vpaddlq_s8(a: int8x16_t) -> int16x8_t { + vpaddlq_s8_(a) +} + +/// Signed Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.s16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddlp))] +pub unsafe fn vpaddlq_s16(a: int16x8_t) -> int32x4_t { + vpaddlq_s16_(a) +} + +/// Signed Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.s32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(saddlp))] +pub unsafe fn vpaddlq_s32(a: int32x4_t) -> int64x2_t { + vpaddlq_s32_(a) +} + +/// Unsigned Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.u8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddlp))] +pub unsafe fn vpaddl_u8(a: uint8x8_t) -> uint16x4_t { + vpaddl_u8_(a) +} + +/// Unsigned Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.u16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddlp))] +pub unsafe fn vpaddl_u16(a: uint16x4_t) -> uint32x2_t { + vpaddl_u16_(a) +} + +/// Unsigned Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.u32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddlp))] +pub unsafe fn vpaddl_u32(a: uint32x2_t) -> uint64x1_t { + vpaddl_u32_(a) +} + +/// Unsigned Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.u8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddlp))] +pub unsafe fn vpaddlq_u8(a: uint8x16_t) -> uint16x8_t { + vpaddlq_u8_(a) +} + +/// Unsigned Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.u16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddlp))] +pub unsafe fn vpaddlq_u16(a: uint16x8_t) -> uint32x4_t { + vpaddlq_u16_(a) +} + +/// Unsigned Add Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpaddl.u32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uaddlp))] +pub unsafe fn vpaddlq_u32(a: uint32x4_t) -> uint64x2_t { + vpaddlq_u32_(a) +} + +/// Signed Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.s8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sadalp))] +pub unsafe fn vpadal_s8(a: int16x4_t, b: int8x8_t) -> int16x4_t { + #[cfg(target_arch = "arm")] + { + vpadal_s8_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddl_s8_(b), a) + } +} + +/// Signed Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.s16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sadalp))] +pub unsafe fn vpadal_s16(a: int32x2_t, b: int16x4_t) -> int32x2_t { + #[cfg(target_arch = "arm")] + { + vpadal_s16_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddl_s16_(b), a) + } +} + +/// Signed Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.s32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sadalp))] +pub unsafe fn vpadal_s32(a: int64x1_t, b: int32x2_t) -> int64x1_t { + #[cfg(target_arch = "arm")] + { + vpadal_s32_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddl_s32_(b), a) + } +} + +/// Signed Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.s8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sadalp))] +pub unsafe fn vpadalq_s8(a: int16x8_t, b: int8x16_t) -> int16x8_t { + #[cfg(target_arch = "arm")] + { + vpadalq_s8_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddlq_s8_(b), a) + } +} + +/// Signed Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.s16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sadalp))] +pub unsafe fn vpadalq_s16(a: int32x4_t, b: int16x8_t) -> int32x4_t { + #[cfg(target_arch = "arm")] + { + vpadalq_s16_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddlq_s16_(b), a) + } +} + +/// Signed Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.s32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sadalp))] +pub unsafe fn vpadalq_s32(a: int64x2_t, b: int32x4_t) -> int64x2_t { + #[cfg(target_arch = "arm")] + { + vpadalq_s32_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddlq_s32_(b), a) + } +} + +/// Unsigned Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.u8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uadalp))] +pub unsafe fn vpadal_u8(a: uint16x4_t, b: uint8x8_t) -> uint16x4_t { + #[cfg(target_arch = "arm")] + { + vpadal_u8_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddl_u8_(b), a) + } +} + +/// Unsigned Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.u16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uadalp))] +pub unsafe fn vpadal_u16(a: uint32x2_t, b: uint16x4_t) -> uint32x2_t { + #[cfg(target_arch = "arm")] + { + vpadal_u16_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddl_u16_(b), a) + } +} + +/// Unsigned Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.u32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uadalp))] +pub unsafe fn vpadal_u32(a: uint64x1_t, b: uint32x2_t) -> uint64x1_t { + #[cfg(target_arch = "arm")] + { + vpadal_u32_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddl_u32_(b), a) + } +} + +/// Unsigned Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.u8))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uadalp))] +pub unsafe fn vpadalq_u8(a: uint16x8_t, b: uint8x16_t) -> uint16x8_t { + #[cfg(target_arch = "arm")] + { + vpadalq_u8_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddlq_u8_(b), a) + } +} + +/// Unsigned Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.u16))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uadalp))] +pub unsafe fn vpadalq_u16(a: uint32x4_t, b: uint16x8_t) -> uint32x4_t { + #[cfg(target_arch = "arm")] + { + vpadalq_u16_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddlq_u16_(b), a) + } +} + +/// Unsigned Add and Accumulate Long Pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadal.u32))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uadalp))] +pub unsafe fn vpadalq_u32(a: uint64x2_t, b: uint32x4_t) -> uint64x2_t { + #[cfg(target_arch = "arm")] + { + vpadalq_u32_(a, b) + } + #[cfg(target_arch = "aarch64")] + { + simd_add(vpaddlq_u32_(b), a) + } +} + +/// Vector narrow integer. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] +pub unsafe fn vmovn_s16(a: int16x8_t) -> int8x8_t { + simd_cast(a) +} + +/// Vector narrow integer. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] +pub unsafe fn vmovn_s32(a: int32x4_t) -> int16x4_t { + simd_cast(a) +} + +/// Vector narrow integer. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] +pub unsafe fn vmovn_s64(a: int64x2_t) -> int32x2_t { + simd_cast(a) +} + +/// Vector narrow integer. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] +pub unsafe fn vmovn_u16(a: uint16x8_t) -> uint8x8_t { + simd_cast(a) +} + +/// Vector narrow integer. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] +pub unsafe fn vmovn_u32(a: uint32x4_t) -> uint16x4_t { + simd_cast(a) +} + +/// Vector narrow integer. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(xtn))] +pub unsafe fn vmovn_u64(a: uint64x2_t) -> uint32x2_t { + simd_cast(a) +} + +/// Vector long move. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sxtl))] +pub unsafe fn vmovl_s8(a: int8x8_t) -> int16x8_t { + simd_cast(a) +} + +/// Vector long move. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sxtl))] +pub unsafe fn vmovl_s16(a: int16x4_t) -> int32x4_t { + simd_cast(a) +} + +/// Vector long move. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sxtl))] +pub unsafe fn vmovl_s32(a: int32x2_t) -> int64x2_t { + simd_cast(a) +} + +/// Vector long move. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uxtl))] +pub unsafe fn vmovl_u8(a: uint8x8_t) -> uint16x8_t { + simd_cast(a) +} + +/// Vector long move. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uxtl))] +pub unsafe fn vmovl_u16(a: uint16x4_t) -> uint32x4_t { + simd_cast(a) +} + +/// Vector long move. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmovl))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uxtl))] +pub unsafe fn vmovl_u32(a: uint32x2_t) -> uint64x2_t { + simd_cast(a) +} + +/// Reciprocal square-root estimate. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(frsqrte))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vrsqrte))] +pub unsafe fn vrsqrte_f32(a: float32x2_t) -> float32x2_t { + frsqrte_v2f32(a) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvn_s8(a: int8x8_t) -> int8x8_t { + let b = int8x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvnq_s8(a: int8x16_t) -> int8x16_t { + let b = int8x16_t( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + ); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvn_s16(a: int16x4_t) -> int16x4_t { + let b = int16x4_t(-1, -1, -1, -1); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvnq_s16(a: int16x8_t) -> int16x8_t { + let b = int16x8_t(-1, -1, -1, -1, -1, -1, -1, -1); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvn_s32(a: int32x2_t) -> int32x2_t { + let b = int32x2_t(-1, -1); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvnq_s32(a: int32x4_t) -> int32x4_t { + let b = int32x4_t(-1, -1, -1, -1); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvn_u8(a: uint8x8_t) -> uint8x8_t { + let b = uint8x8_t(255, 255, 255, 255, 255, 255, 255, 255); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvnq_u8(a: uint8x16_t) -> uint8x16_t { + let b = uint8x16_t( + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + ); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvn_u16(a: uint16x4_t) -> uint16x4_t { + let b = uint16x4_t(65_535, 65_535, 65_535, 65_535); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvnq_u16(a: uint16x8_t) -> uint16x8_t { + let b = uint16x8_t( + 65_535, 65_535, 65_535, 65_535, 65_535, 65_535, 65_535, 65_535, + ); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvn_u32(a: uint32x2_t) -> uint32x2_t { + let b = uint32x2_t(4_294_967_295, 4_294_967_295); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvnq_u32(a: uint32x4_t) -> uint32x4_t { + let b = uint32x4_t(4_294_967_295, 4_294_967_295, 4_294_967_295, 4_294_967_295); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvn_p8(a: poly8x8_t) -> poly8x8_t { + let b = poly8x8_t(255, 255, 255, 255, 255, 255, 255, 255); + simd_xor(a, b) +} + +/// Vector bitwise not. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmvn))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mvn))] +pub unsafe fn vmvnq_p8(a: poly8x16_t) -> poly8x16_t { + let b = poly8x16_t( + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + ); + simd_xor(a, b) +} + +/// Folding minimum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sminp))] +pub unsafe fn vpmin_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + vpmins_v8i8(a, b) +} + +/// Folding minimum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sminp))] +pub unsafe fn vpmin_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + vpmins_v4i16(a, b) +} + +/// Folding minimum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(sminp))] +pub unsafe fn vpmin_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + vpmins_v2i32(a, b) +} + +/// Folding minimum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uminp))] +pub unsafe fn vpmin_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + vpminu_v8i8(a, b) +} + +/// Folding minimum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uminp))] +pub unsafe fn vpmin_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + vpminu_v4i16(a, b) +} + +/// Folding minimum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(uminp))] +pub unsafe fn vpmin_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + vpminu_v2i32(a, b) +} + +/// Folding minimum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmin))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fminp))] +pub unsafe fn vpmin_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + vpminf_v2f32(a, b) +} + +/// Folding maximum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smaxp))] +pub unsafe fn vpmax_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + vpmaxs_v8i8(a, b) +} + +/// Folding maximum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smaxp))] +pub unsafe fn vpmax_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + vpmaxs_v4i16(a, b) +} + +/// Folding maximum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(smaxp))] +pub unsafe fn vpmax_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + vpmaxs_v2i32(a, b) +} + +/// Folding maximum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umaxp))] +pub unsafe fn vpmax_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + vpmaxu_v8i8(a, b) +} + +/// Folding maximum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umaxp))] +pub unsafe fn vpmax_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + vpmaxu_v4i16(a, b) +} + +/// Folding maximum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umaxp))] +pub unsafe fn vpmax_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + vpmaxu_v2i32(a, b) +} + +/// Folding maximum of adjacent pairs +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpmax))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmaxp))] +pub unsafe fn vpmax_f32(a: float32x2_t, b: float32x2_t) -> float32x2_t { + vpmaxf_v2f32(a, b) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl1_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + vtbl1(a, b) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl1_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + transmute(vtbl1(transmute(a), transmute(b))) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl1_p8(a: poly8x8_t, b: uint8x8_t) -> poly8x8_t { + transmute(vtbl1(transmute(a), transmute(b))) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl2_s8(a: int8x8x2_t, b: int8x8_t) -> int8x8_t { + vtbl2(a.0, a.1, b) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl2_u8(a: uint8x8x2_t, b: uint8x8_t) -> uint8x8_t { + transmute(vtbl2(transmute(a.0), transmute(a.1), transmute(b))) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl2_p8(a: poly8x8x2_t, b: uint8x8_t) -> poly8x8_t { + transmute(vtbl2(transmute(a.0), transmute(a.1), transmute(b))) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl3_s8(a: int8x8x3_t, b: int8x8_t) -> int8x8_t { + vtbl3(a.0, a.1, a.2, b) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl3_u8(a: uint8x8x3_t, b: uint8x8_t) -> uint8x8_t { + transmute(vtbl3( + transmute(a.0), + transmute(a.1), + transmute(a.2), + transmute(b), + )) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl3_p8(a: poly8x8x3_t, b: uint8x8_t) -> poly8x8_t { + transmute(vtbl3( + transmute(a.0), + transmute(a.1), + transmute(a.2), + transmute(b), + )) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl4_s8(a: int8x8x4_t, b: int8x8_t) -> int8x8_t { + vtbl4(a.0, a.1, a.2, a.3, b) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl4_u8(a: uint8x8x4_t, b: uint8x8_t) -> uint8x8_t { + transmute(vtbl4( + transmute(a.0), + transmute(a.1), + transmute(a.2), + transmute(a.3), + transmute(b), + )) +} + +/// Table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbl))] +pub unsafe fn vtbl4_p8(a: poly8x8x4_t, b: uint8x8_t) -> poly8x8_t { + transmute(vtbl4( + transmute(a.0), + transmute(a.1), + transmute(a.2), + transmute(a.3), + transmute(b), + )) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx1_s8(a: int8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t { + vtbx1(a, b, c) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx1_u8(a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t { + transmute(vtbx1(transmute(a), transmute(b), transmute(c))) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx1_p8(a: poly8x8_t, b: poly8x8_t, c: uint8x8_t) -> poly8x8_t { + transmute(vtbx1(transmute(a), transmute(b), transmute(c))) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx2_s8(a: int8x8_t, b: int8x8x2_t, c: int8x8_t) -> int8x8_t { + vtbx2(a, b.0, b.1, c) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx2_u8(a: uint8x8_t, b: uint8x8x2_t, c: uint8x8_t) -> uint8x8_t { + transmute(vtbx2( + transmute(a), + transmute(b.0), + transmute(b.1), + transmute(c), + )) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx2_p8(a: poly8x8_t, b: poly8x8x2_t, c: uint8x8_t) -> poly8x8_t { + transmute(vtbx2( + transmute(a), + transmute(b.0), + transmute(b.1), + transmute(c), + )) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx3_s8(a: int8x8_t, b: int8x8x3_t, c: int8x8_t) -> int8x8_t { + vtbx3(a, b.0, b.1, b.2, c) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx3_u8(a: uint8x8_t, b: uint8x8x3_t, c: uint8x8_t) -> uint8x8_t { + transmute(vtbx3( + transmute(a), + transmute(b.0), + transmute(b.1), + transmute(b.2), + transmute(c), + )) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx3_p8(a: poly8x8_t, b: poly8x8x3_t, c: uint8x8_t) -> poly8x8_t { + transmute(vtbx3( + transmute(a), + transmute(b.0), + transmute(b.1), + transmute(b.2), + transmute(c), + )) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx4_s8(a: int8x8_t, b: int8x8x4_t, c: int8x8_t) -> int8x8_t { + vtbx4(a, b.0, b.1, b.2, b.3, c) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx4_u8(a: uint8x8_t, b: uint8x8x4_t, c: uint8x8_t) -> uint8x8_t { + transmute(vtbx4( + transmute(a), + transmute(b.0), + transmute(b.1), + transmute(b.2), + transmute(b.3), + transmute(c), + )) +} + +/// Extended table look-up +#[inline] +#[cfg(target_arch = "arm")] +#[cfg(target_endian = "little")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr(vtbx))] +pub unsafe fn vtbx4_p8(a: poly8x8_t, b: poly8x8x4_t, c: uint8x8_t) -> poly8x8_t { + transmute(vtbx4( + transmute(a), + transmute(b.0), + transmute(b.1), + transmute(b.2), + transmute(b.3), + transmute(c), + )) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(1)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 1))] +// Based on the discussion in https://github.com/rust-lang/stdarch/pull/792 +// `mov` seems to be an acceptable intrinsic to compile to +// #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(vmov, imm5 = 1))] +pub unsafe fn vgetq_lane_u64(v: uint64x2_t, imm5: i32) -> u64 { + assert!(imm5 >= 0 && imm5 <= 1); + simd_extract(v, imm5 as u32) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(1)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 0))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmov, imm5 = 0))] +// FIXME: no 32bit this seems to be turned into two vmov.32 instructions +// validate correctness +pub unsafe fn vget_lane_u64(v: uint64x1_t, imm5: i32) -> u64 { + assert!(imm5 == 0); + simd_extract(v, 0) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(1)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u16", imm5 = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, imm5 = 2))] +pub unsafe fn vgetq_lane_u16(v: uint16x8_t, imm5: i32) -> u16 { + assert!(imm5 >= 0 && imm5 <= 7); + simd_extract(v, imm5 as u32) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(1)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 2))] +pub unsafe fn vgetq_lane_u32(v: uint32x4_t, imm5: i32) -> u32 { + assert!(imm5 >= 0 && imm5 <= 3); + simd_extract(v, imm5 as u32) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(1)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.32", imm5 = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(mov, imm5 = 2))] +pub unsafe fn vgetq_lane_s32(v: int32x4_t, imm5: i32) -> i32 { + assert!(imm5 >= 0 && imm5 <= 3); + simd_extract(v, imm5 as u32) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(1)] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov.u8", imm5 = 2))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(umov, imm5 = 2))] +pub unsafe fn vget_lane_u8(v: uint8x8_t, imm5: i32) -> u8 { + assert!(imm5 >= 0 && imm5 <= 7); + simd_extract(v, imm5 as u32) +} + +/// Duplicate vector element to vector or scalar +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] +pub unsafe fn vdupq_n_s8(value: i8) -> int8x16_t { + int8x16_t( + value, value, value, value, value, value, value, value, value, value, value, value, value, + value, value, value, + ) +} + +/// Duplicate vector element to vector or scalar +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] +pub unsafe fn vdupq_n_u8(value: u8) -> uint8x16_t { + uint8x16_t( + value, value, value, value, value, value, value, value, value, value, value, value, value, + value, value, value, + ) +} + +/// Duplicate vector element to vector or scalar +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vdup.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(dup))] +pub unsafe fn vmovq_n_u8(value: u8) -> uint8x16_t { + vdupq_n_u8(value) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(test, assert_instr(nop))] +pub unsafe fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(test, assert_instr(nop))] +pub unsafe fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(test, assert_instr(nop))] +pub unsafe fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(test, assert_instr(nop))] +pub unsafe fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(test, assert_instr(nop))] +pub unsafe fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { + transmute(a) +} + +/// Vector reinterpret cast operation +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(test, assert_instr(nop))] +pub unsafe fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { + transmute(a) +} + +/// Unsigned shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshr.u8", imm3 = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr("ushr", imm3 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn vshrq_n_u8(a: uint8x16_t, imm3: i32) -> uint8x16_t { + if imm3 < 0 || imm3 > 7 { + unreachable_unchecked(); + } else { + uint8x16_t( + a.0 >> imm3, + a.1 >> imm3, + a.2 >> imm3, + a.3 >> imm3, + a.4 >> imm3, + a.5 >> imm3, + a.6 >> imm3, + a.7 >> imm3, + a.8 >> imm3, + a.9 >> imm3, + a.10 >> imm3, + a.11 >> imm3, + a.12 >> imm3, + a.13 >> imm3, + a.14 >> imm3, + a.15 >> imm3, + ) + } +} + +/// Shift right +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vshl.s8", imm3 = 1))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(shl, imm3 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn vshlq_n_u8(a: uint8x16_t, imm3: i32) -> uint8x16_t { + if imm3 < 0 || imm3 > 7 { + unreachable_unchecked(); + } else { + uint8x16_t( + a.0 << imm3, + a.1 << imm3, + a.2 << imm3, + a.3 << imm3, + a.4 << imm3, + a.5 << imm3, + a.6 << imm3, + a.7 << imm3, + a.8 << imm3, + a.9 << imm3, + a.10 << imm3, + a.11 << imm3, + a.12 << imm3, + a.13 << imm3, + a.14 << imm3, + a.15 << imm3, + ) + } +} + +/// Extract vector from pair of vectors +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", n = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, n = 3))] +#[rustc_args_required_const(2)] +pub unsafe fn vextq_s8(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t { + if n < 0 || n > 15 { + unreachable_unchecked(); + }; + match n & 0b1111 { + 0 => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + 1 => simd_shuffle16( + a, + b, + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + ), + 2 => simd_shuffle16( + a, + b, + [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], + ), + 3 => simd_shuffle16( + a, + b, + [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], + ), + 4 => simd_shuffle16( + a, + b, + [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], + ), + 5 => simd_shuffle16( + a, + b, + [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + ), + 6 => simd_shuffle16( + a, + b, + [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], + ), + 7 => simd_shuffle16( + a, + b, + [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22], + ), + 8 => simd_shuffle16( + a, + b, + [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], + ), + 9 => simd_shuffle16( + a, + b, + [ + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + ], + ), + 10 => simd_shuffle16( + a, + b, + [ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + ], + ), + 11 => simd_shuffle16( + a, + b, + [ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + ], + ), + 12 => simd_shuffle16( + a, + b, + [ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + ], + ), + 13 => simd_shuffle16( + a, + b, + [ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + ], + ), + 14 => simd_shuffle16( + a, + b, + [ + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + ], + ), + 15 => simd_shuffle16( + a, + b, + [ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + ], + ), + _ => unreachable_unchecked(), + } +} + +/// Extract vector from pair of vectors +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vext.8", n = 3))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ext, n = 3))] +#[rustc_args_required_const(2)] +pub unsafe fn vextq_u8(a: uint8x16_t, b: uint8x16_t, n: i32) -> uint8x16_t { + if n < 0 || n > 15 { + unreachable_unchecked(); + }; + match n & 0b1111 { + 0 => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + 1 => simd_shuffle16( + a, + b, + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + ), + 2 => simd_shuffle16( + a, + b, + [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], + ), + 3 => simd_shuffle16( + a, + b, + [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], + ), + 4 => simd_shuffle16( + a, + b, + [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], + ), + 5 => simd_shuffle16( + a, + b, + [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + ), + 6 => simd_shuffle16( + a, + b, + [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], + ), + 7 => simd_shuffle16( + a, + b, + [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22], + ), + 8 => simd_shuffle16( + a, + b, + [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], + ), + 9 => simd_shuffle16( + a, + b, + [ + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + ], + ), + 10 => simd_shuffle16( + a, + b, + [ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + ], + ), + 11 => simd_shuffle16( + a, + b, + [ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + ], + ), + 12 => simd_shuffle16( + a, + b, + [ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + ], + ), + 13 => simd_shuffle16( + a, + b, + [ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + ], + ), + 14 => simd_shuffle16( + a, + b, + [ + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + ], + ), + 15 => simd_shuffle16( + a, + b, + [ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + ], + ), + _ => unreachable_unchecked(), + } +} + +// These float-to-int implementations have undefined behaviour when `a` overflows +// the destination type. Clang has the same problem: https://llvm.org/PR47510 + +/// Floating-point Convert to Signed fixed-point, rounding toward Zero (vector) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vcvt.s32.f32"))] +pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { + transmute(simd_cast::<_, i32x4>(transmute::<_, f32x4>(a))) +} + +/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vcvt.u32.f32"))] +pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { + transmute(simd_cast::<_, u32x4>(transmute::<_, f32x4>(a))) +} + +/// Population count per byte. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vcnt))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cnt))] +pub unsafe fn vcnt_s8(a: int8x8_t) -> int8x8_t { + vcnt_s8_(a) +} +/// Population count per byte. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vcnt))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cnt))] +pub unsafe fn vcntq_s8(a: int8x16_t) -> int8x16_t { + vcntq_s8_(a) +} +/// Population count per byte. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vcnt))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cnt))] +pub unsafe fn vcnt_u8(a: uint8x8_t) -> uint8x8_t { + transmute(vcnt_s8_(transmute(a))) +} +/// Population count per byte. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vcnt))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cnt))] +pub unsafe fn vcntq_u8(a: uint8x16_t) -> uint8x16_t { + transmute(vcntq_s8_(transmute(a))) +} +/// Population count per byte. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vcnt))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cnt))] +pub unsafe fn vcnt_p8(a: poly8x8_t) -> poly8x8_t { + transmute(vcnt_s8_(transmute(a))) +} +/// Population count per byte. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vcnt))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(cnt))] +pub unsafe fn vcntq_p8(a: poly8x16_t) -> poly8x16_t { + transmute(vcntq_s8_(transmute(a))) +} + +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s8(a: int8x8_t, b: int8x8_t, n: i32) -> int8x8_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + let n = n as i8; + vshiftins_v8i8(a, b, int8x8_t(n, n, n, n, n, n, n, n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s8(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + let n = n as i8; + vshiftins_v16i8( + a, + b, + int8x16_t(n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n), + ) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s16(a: int16x4_t, b: int16x4_t, n: i32) -> int16x4_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + let n = n as i16; + vshiftins_v4i16(a, b, int16x4_t(n, n, n, n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s16(a: int16x8_t, b: int16x8_t, n: i32) -> int16x8_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + let n = n as i16; + vshiftins_v8i16(a, b, int16x8_t(n, n, n, n, n, n, n, n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s32(a: int32x2_t, b: int32x2_t, n: i32) -> int32x2_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + vshiftins_v2i32(a, b, int32x2_t(n, n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s32(a: int32x4_t, b: int32x4_t, n: i32) -> int32x4_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + vshiftins_v4i32(a, b, int32x4_t(n, n, n, n)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_s64(a: int64x1_t, b: int64x1_t, n: i32) -> int64x1_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + vshiftins_v1i64(a, b, int64x1_t(n as i64)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_s64(a: int64x2_t, b: int64x2_t, n: i32) -> int64x2_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + vshiftins_v2i64(a, b, int64x2_t(n as i64, n as i64)) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u8(a: uint8x8_t, b: uint8x8_t, n: i32) -> uint8x8_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + let n = n as i8; + transmute(vshiftins_v8i8( + transmute(a), + transmute(b), + int8x8_t(n, n, n, n, n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u8(a: uint8x16_t, b: uint8x16_t, n: i32) -> uint8x16_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + let n = n as i8; + transmute(vshiftins_v16i8( + transmute(a), + transmute(b), + int8x16_t(n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u16(a: uint16x4_t, b: uint16x4_t, n: i32) -> uint16x4_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + let n = n as i16; + transmute(vshiftins_v4i16( + transmute(a), + transmute(b), + int16x4_t(n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u16(a: uint16x8_t, b: uint16x8_t, n: i32) -> uint16x8_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + let n = n as i16; + transmute(vshiftins_v8i16( + transmute(a), + transmute(b), + int16x8_t(n, n, n, n, n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u32(a: uint32x2_t, b: uint32x2_t, n: i32) -> uint32x2_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + transmute(vshiftins_v2i32(transmute(a), transmute(b), int32x2_t(n, n))) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u32(a: uint32x4_t, b: uint32x4_t, n: i32) -> uint32x4_t { + assert!(0 <= n && n <= 31, "must have 0 ≤ n ≤ 31, but n = {}", n); + transmute(vshiftins_v4i32( + transmute(a), + transmute(b), + int32x4_t(n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_u64(a: uint64x1_t, b: uint64x1_t, n: i32) -> uint64x1_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + transmute(vshiftins_v1i64( + transmute(a), + transmute(b), + int64x1_t(n as i64), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_u64(a: uint64x2_t, b: uint64x2_t, n: i32) -> uint64x2_t { + assert!(0 <= n && n <= 63, "must have 0 ≤ n ≤ 63, but n = {}", n); + transmute(vshiftins_v2i64( + transmute(a), + transmute(b), + int64x2_t(n as i64, n as i64), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_p8(a: poly8x8_t, b: poly8x8_t, n: i32) -> poly8x8_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + let n = n as i8; + transmute(vshiftins_v8i8( + transmute(a), + transmute(b), + int8x8_t(n, n, n, n, n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_p8(a: poly8x16_t, b: poly8x16_t, n: i32) -> poly8x16_t { + assert!(0 <= n && n <= 7, "must have 0 ≤ n ≤ 7, but n = {}", n); + let n = n as i8; + transmute(vshiftins_v16i8( + transmute(a), + transmute(b), + int8x16_t(n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsli_n_p16(a: poly16x4_t, b: poly16x4_t, n: i32) -> poly16x4_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + let n = n as i16; + transmute(vshiftins_v4i16( + transmute(a), + transmute(b), + int16x4_t(n, n, n, n), + )) +} +/// Shift Left and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsli.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsliq_n_p16(a: poly16x8_t, b: poly16x8_t, n: i32) -> poly16x8_t { + assert!(0 <= n && n <= 15, "must have 0 ≤ n ≤ 15, but n = {}", n); + let n = n as i16; + transmute(vshiftins_v8i16( + transmute(a), + transmute(b), + int16x8_t(n, n, n, n, n, n, n, n), + )) +} + +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s8(a: int8x8_t, b: int8x8_t, n: i32) -> int8x8_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + let n = -n as i8; + vshiftins_v8i8(a, b, int8x8_t(n, n, n, n, n, n, n, n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s8(a: int8x16_t, b: int8x16_t, n: i32) -> int8x16_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + let n = -n as i8; + vshiftins_v16i8( + a, + b, + int8x16_t(n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n), + ) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s16(a: int16x4_t, b: int16x4_t, n: i32) -> int16x4_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + let n = -n as i16; + vshiftins_v4i16(a, b, int16x4_t(n, n, n, n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s16(a: int16x8_t, b: int16x8_t, n: i32) -> int16x8_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + let n = -n as i16; + vshiftins_v8i16(a, b, int16x8_t(n, n, n, n, n, n, n, n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s32(a: int32x2_t, b: int32x2_t, n: i32) -> int32x2_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + vshiftins_v2i32(a, b, int32x2_t(-n, -n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s32(a: int32x4_t, b: int32x4_t, n: i32) -> int32x4_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + vshiftins_v4i32(a, b, int32x4_t(-n, -n, -n, -n)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_s64(a: int64x1_t, b: int64x1_t, n: i32) -> int64x1_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + vshiftins_v1i64(a, b, int64x1_t(-n as i64)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_s64(a: int64x2_t, b: int64x2_t, n: i32) -> int64x2_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + vshiftins_v2i64(a, b, int64x2_t(-n as i64, -n as i64)) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u8(a: uint8x8_t, b: uint8x8_t, n: i32) -> uint8x8_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + let n = -n as i8; + transmute(vshiftins_v8i8( + transmute(a), + transmute(b), + int8x8_t(n, n, n, n, n, n, n, n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u8(a: uint8x16_t, b: uint8x16_t, n: i32) -> uint8x16_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + let n = -n as i8; + transmute(vshiftins_v16i8( + transmute(a), + transmute(b), + int8x16_t(n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u16(a: uint16x4_t, b: uint16x4_t, n: i32) -> uint16x4_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + let n = -n as i16; + transmute(vshiftins_v4i16( + transmute(a), + transmute(b), + int16x4_t(n, n, n, n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u16(a: uint16x8_t, b: uint16x8_t, n: i32) -> uint16x8_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + let n = -n as i16; + transmute(vshiftins_v8i16( + transmute(a), + transmute(b), + int16x8_t(n, n, n, n, n, n, n, n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u32(a: uint32x2_t, b: uint32x2_t, n: i32) -> uint32x2_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + transmute(vshiftins_v2i32( + transmute(a), + transmute(b), + int32x2_t(-n, -n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.32", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u32(a: uint32x4_t, b: uint32x4_t, n: i32) -> uint32x4_t { + assert!(1 <= n && n <= 32, "must have 1 ≤ n ≤ 32, but n = {}", n); + transmute(vshiftins_v4i32( + transmute(a), + transmute(b), + int32x4_t(-n, -n, -n, -n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_u64(a: uint64x1_t, b: uint64x1_t, n: i32) -> uint64x1_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + transmute(vshiftins_v1i64( + transmute(a), + transmute(b), + int64x1_t(-n as i64), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.64", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_u64(a: uint64x2_t, b: uint64x2_t, n: i32) -> uint64x2_t { + assert!(1 <= n && n <= 64, "must have 1 ≤ n ≤ 64, but n = {}", n); + transmute(vshiftins_v2i64( + transmute(a), + transmute(b), + int64x2_t(-n as i64, -n as i64), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_p8(a: poly8x8_t, b: poly8x8_t, n: i32) -> poly8x8_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + let n = -n as i8; + transmute(vshiftins_v8i8( + transmute(a), + transmute(b), + int8x8_t(n, n, n, n, n, n, n, n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.8", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_p8(a: poly8x16_t, b: poly8x16_t, n: i32) -> poly8x16_t { + assert!(1 <= n && n <= 8, "must have 1 ≤ n ≤ 8, but n = {}", n); + let n = -n as i8; + transmute(vshiftins_v16i8( + transmute(a), + transmute(b), + int8x16_t(n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsri_n_p16(a: poly16x4_t, b: poly16x4_t, n: i32) -> poly16x4_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + let n = -n as i16; + transmute(vshiftins_v4i16( + transmute(a), + transmute(b), + int16x4_t(n, n, n, n), + )) +} +/// Shift Right and Insert (immediate) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon,v7")] +#[cfg_attr(test, assert_instr("vsri.16", n = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn vsriq_n_p16(a: poly16x8_t, b: poly16x8_t, n: i32) -> poly16x8_t { + assert!(1 <= n && n <= 16, "must have 1 ≤ n ≤ 16, but n = {}", n); + let n = -n as i16; + transmute(vshiftins_v8i16( + transmute(a), + transmute(b), + int16x8_t(n, n, n, n, n, n, n, n), + )) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev16.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev16))] +pub unsafe fn vrev16_s8(a: int8x8_t) -> int8x8_t { + simd_shuffle8(a, a, [1, 0, 3, 2, 5, 4, 7, 6]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev16.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev16))] +pub unsafe fn vrev16q_s8(a: int8x16_t) -> int8x16_t { + simd_shuffle16(a, a, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev16.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev16))] +pub unsafe fn vrev16_u8(a: uint8x8_t) -> uint8x8_t { + simd_shuffle8(a, a, [1, 0, 3, 2, 5, 4, 7, 6]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev16.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev16))] +pub unsafe fn vrev16q_u8(a: uint8x16_t) -> uint8x16_t { + simd_shuffle16(a, a, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev16.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev16))] +pub unsafe fn vrev16_p8(a: poly8x8_t) -> poly8x8_t { + simd_shuffle8(a, a, [1, 0, 3, 2, 5, 4, 7, 6]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev16.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev16))] +pub unsafe fn vrev16q_p8(a: poly8x16_t) -> poly8x16_t { + simd_shuffle16(a, a, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32_s8(a: int8x8_t) -> int8x8_t { + simd_shuffle8(a, a, [3, 2, 1, 0, 7, 6, 5, 4]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32q_s8(a: int8x16_t) -> int8x16_t { + simd_shuffle16(a, a, [3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32_u8(a: uint8x8_t) -> uint8x8_t { + simd_shuffle8(a, a, [3, 2, 1, 0, 7, 6, 5, 4]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32q_u8(a: uint8x16_t) -> uint8x16_t { + simd_shuffle16(a, a, [3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32_u16(a: uint16x4_t) -> uint16x4_t { + simd_shuffle4(a, a, [1, 0, 3, 2]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32q_u16(a: uint16x8_t) -> uint16x8_t { + simd_shuffle8(a, a, [1, 0, 3, 2, 5, 4, 7, 6]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32_p8(a: poly8x8_t) -> poly8x8_t { + simd_shuffle8(a, a, [3, 2, 1, 0, 7, 6, 5, 4]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev32.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev32))] +pub unsafe fn vrev32q_p8(a: poly8x16_t) -> poly8x16_t { + simd_shuffle16(a, a, [3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_s8(a: int8x8_t) -> int8x8_t { + simd_shuffle8(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_s8(a: int8x16_t) -> int8x16_t { + simd_shuffle16(a, a, [7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_s16(a: int16x4_t) -> int16x4_t { + simd_shuffle4(a, a, [3, 2, 1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_s16(a: int16x8_t) -> int16x8_t { + simd_shuffle8(a, a, [3, 2, 1, 0, 7, 6, 5, 4]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_s32(a: int32x2_t) -> int32x2_t { + simd_shuffle2(a, a, [1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_s32(a: int32x4_t) -> int32x4_t { + simd_shuffle4(a, a, [1, 0, 3, 2]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_u8(a: uint8x8_t) -> uint8x8_t { + simd_shuffle8(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_u8(a: uint8x16_t) -> uint8x16_t { + simd_shuffle16(a, a, [7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_u16(a: uint16x4_t) -> uint16x4_t { + simd_shuffle4(a, a, [3, 2, 1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_u16(a: uint16x8_t) -> uint16x8_t { + simd_shuffle8(a, a, [3, 2, 1, 0, 7, 6, 5, 4]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_u32(a: uint32x2_t) -> uint32x2_t { + simd_shuffle2(a, a, [1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_u32(a: uint32x4_t) -> uint32x4_t { + simd_shuffle4(a, a, [1, 0, 3, 2]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_f32(a: float32x2_t) -> float32x2_t { + simd_shuffle2(a, a, [1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_f32(a: float32x4_t) -> float32x4_t { + simd_shuffle4(a, a, [1, 0, 3, 2]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_p8(a: poly8x8_t) -> poly8x8_t { + simd_shuffle8(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.8"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_p8(a: poly8x16_t) -> poly8x16_t { + simd_shuffle16(a, a, [7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64_p16(a: poly16x4_t) -> poly16x4_t { + simd_shuffle4(a, a, [3, 2, 1, 0]) +} + +/// Reversing vector elements (swap endianness) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vrev64.16"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(rev64))] +pub unsafe fn vrev64q_p16(a: poly16x8_t) -> poly16x8_t { + simd_shuffle8(a, a, [3, 2, 1, 0, 7, 6, 5, 4]) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::core_arch::arm::test_support::*; + use crate::core_arch::{arm::*, simd::*}; + use std::{i16, i32, i8, mem::transmute, u16, u32, u8, vec::Vec}; + use stdarch_test::simd_test; + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_s8() { + let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let elem: i8 = 42; + let e = i8x8::new(0, 1, 2, 3, 4, 5, 6, 42); + let r: i8x8 = transmute(vld1_lane_s8(&elem, transmute(a), 7)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_s8() { + let a = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let elem: i8 = 42; + let e = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 42); + let r: i8x16 = transmute(vld1q_lane_s8(&elem, transmute(a), 15)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_s16() { + let a = i16x4::new(0, 1, 2, 3); + let elem: i16 = 42; + let e = i16x4::new(0, 1, 2, 42); + let r: i16x4 = transmute(vld1_lane_s16(&elem, transmute(a), 3)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_s16() { + let a = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let elem: i16 = 42; + let e = i16x8::new(0, 1, 2, 3, 4, 5, 6, 42); + let r: i16x8 = transmute(vld1q_lane_s16(&elem, transmute(a), 7)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_s32() { + let a = i32x2::new(0, 1); + let elem: i32 = 42; + let e = i32x2::new(0, 42); + let r: i32x2 = transmute(vld1_lane_s32(&elem, transmute(a), 1)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_s32() { + let a = i32x4::new(0, 1, 2, 3); + let elem: i32 = 42; + let e = i32x4::new(0, 1, 2, 42); + let r: i32x4 = transmute(vld1q_lane_s32(&elem, transmute(a), 3)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_s64() { + let a = i64x1::new(0); + let elem: i64 = 42; + let e = i64x1::new(42); + let r: i64x1 = transmute(vld1_lane_s64(&elem, transmute(a), 0)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_s64() { + let a = i64x2::new(0, 1); + let elem: i64 = 42; + let e = i64x2::new(0, 42); + let r: i64x2 = transmute(vld1q_lane_s64(&elem, transmute(a), 1)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_u8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let elem: u8 = 42; + let e = u8x8::new(0, 1, 2, 3, 4, 5, 6, 42); + let r: u8x8 = transmute(vld1_lane_u8(&elem, transmute(a), 7)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_u8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let elem: u8 = 42; + let e = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 42); + let r: u8x16 = transmute(vld1q_lane_u8(&elem, transmute(a), 15)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_u16() { + let a = u16x4::new(0, 1, 2, 3); + let elem: u16 = 42; + let e = u16x4::new(0, 1, 2, 42); + let r: u16x4 = transmute(vld1_lane_u16(&elem, transmute(a), 3)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let elem: u16 = 42; + let e = u16x8::new(0, 1, 2, 3, 4, 5, 6, 42); + let r: u16x8 = transmute(vld1q_lane_u16(&elem, transmute(a), 7)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_u32() { + let a = u32x2::new(0, 1); + let elem: u32 = 42; + let e = u32x2::new(0, 42); + let r: u32x2 = transmute(vld1_lane_u32(&elem, transmute(a), 1)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_u32() { + let a = u32x4::new(0, 1, 2, 3); + let elem: u32 = 42; + let e = u32x4::new(0, 1, 2, 42); + let r: u32x4 = transmute(vld1q_lane_u32(&elem, transmute(a), 3)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_u64() { + let a = u64x1::new(0); + let elem: u64 = 42; + let e = u64x1::new(42); + let r: u64x1 = transmute(vld1_lane_u64(&elem, transmute(a), 0)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_u64() { + let a = u64x2::new(0, 1); + let elem: u64 = 42; + let e = u64x2::new(0, 42); + let r: u64x2 = transmute(vld1q_lane_u64(&elem, transmute(a), 1)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_p8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let elem: p8 = 42; + let e = u8x8::new(0, 1, 2, 3, 4, 5, 6, 42); + let r: u8x8 = transmute(vld1_lane_p8(&elem, transmute(a), 7)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_p8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let elem: p8 = 42; + let e = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 42); + let r: u8x16 = transmute(vld1q_lane_p8(&elem, transmute(a), 15)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_p16() { + let a = u16x4::new(0, 1, 2, 3); + let elem: p16 = 42; + let e = u16x4::new(0, 1, 2, 42); + let r: u16x4 = transmute(vld1_lane_p16(&elem, transmute(a), 3)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_p16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let elem: p16 = 42; + let e = u16x8::new(0, 1, 2, 3, 4, 5, 6, 42); + let r: u16x8 = transmute(vld1q_lane_p16(&elem, transmute(a), 7)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_lane_f32() { + let a = f32x2::new(0., 1.); + let elem: f32 = 42.; + let e = f32x2::new(0., 42.); + let r: f32x2 = transmute(vld1_lane_f32(&elem, transmute(a), 1)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_lane_f32() { + let a = f32x4::new(0., 1., 2., 3.); + let elem: f32 = 42.; + let e = f32x4::new(0., 1., 2., 42.); + let r: f32x4 = transmute(vld1q_lane_f32(&elem, transmute(a), 3)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_s8() { + let elem: i8 = 42; + let e = i8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let r: i8x8 = transmute(vld1_dup_s8(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_s8() { + let elem: i8 = 42; + let e = i8x16::new( + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + ); + let r: i8x16 = transmute(vld1q_dup_s8(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_s16() { + let elem: i16 = 42; + let e = i16x4::new(42, 42, 42, 42); + let r: i16x4 = transmute(vld1_dup_s16(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_s16() { + let elem: i16 = 42; + let e = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let r: i16x8 = transmute(vld1q_dup_s16(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_s32() { + let elem: i32 = 42; + let e = i32x2::new(42, 42); + let r: i32x2 = transmute(vld1_dup_s32(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_s32() { + let elem: i32 = 42; + let e = i32x4::new(42, 42, 42, 42); + let r: i32x4 = transmute(vld1q_dup_s32(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_s64() { + let elem: i64 = 42; + let e = i64x1::new(42); + let r: i64x1 = transmute(vld1_dup_s64(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_s64() { + let elem: i64 = 42; + let e = i64x2::new(42, 42); + let r: i64x2 = transmute(vld1q_dup_s64(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_u8() { + let elem: u8 = 42; + let e = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let r: u8x8 = transmute(vld1_dup_u8(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_u8() { + let elem: u8 = 42; + let e = u8x16::new( + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + ); + let r: u8x16 = transmute(vld1q_dup_u8(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_u16() { + let elem: u16 = 42; + let e = u16x4::new(42, 42, 42, 42); + let r: u16x4 = transmute(vld1_dup_u16(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_u16() { + let elem: u16 = 42; + let e = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let r: u16x8 = transmute(vld1q_dup_u16(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_u32() { + let elem: u32 = 42; + let e = u32x2::new(42, 42); + let r: u32x2 = transmute(vld1_dup_u32(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_u32() { + let elem: u32 = 42; + let e = u32x4::new(42, 42, 42, 42); + let r: u32x4 = transmute(vld1q_dup_u32(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_u64() { + let elem: u64 = 42; + let e = u64x1::new(42); + let r: u64x1 = transmute(vld1_dup_u64(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_u64() { + let elem: u64 = 42; + let e = u64x2::new(42, 42); + let r: u64x2 = transmute(vld1q_dup_u64(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_p8() { + let elem: p8 = 42; + let e = u8x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let r: u8x8 = transmute(vld1_dup_p8(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_p8() { + let elem: p8 = 42; + let e = u8x16::new( + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + ); + let r: u8x16 = transmute(vld1q_dup_p8(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_p16() { + let elem: p16 = 42; + let e = u16x4::new(42, 42, 42, 42); + let r: u16x4 = transmute(vld1_dup_p16(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_p16() { + let elem: p16 = 42; + let e = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let r: u16x8 = transmute(vld1q_dup_p16(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1_dup_f32() { + let elem: f32 = 42.; + let e = f32x2::new(42., 42.); + let r: f32x2 = transmute(vld1_dup_f32(&elem)); + assert_eq!(r, e) + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_f32() { + let elem: f32 = 42.; + let e = f32x4::new(42., 42., 42., 42.); + let r: f32x4 = transmute(vld1q_dup_f32(&elem)); + assert_eq!(r, e) + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_s32_f32() { + let f = f32x4::new(-1., 2., 3., 4.); + let e = i32x4::new(-1, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_u32_f32() { + let f = f32x4::new(1., 2., 3., 4.); + let e = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vget_lane_u8() { + let v = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r = vget_lane_u8(transmute(v), 1); + assert_eq!(r, 2); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vgetq_lane_u32() { + let v = i32x4::new(1, 2, 3, 4); + let r = vgetq_lane_u32(transmute(v), 1); + assert_eq!(r, 2); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vgetq_lane_s32() { + let v = i32x4::new(1, 2, 3, 4); + let r = vgetq_lane_s32(transmute(v), 1); + assert_eq!(r, 2); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vget_lane_u64() { + let v: u64 = 1; + let r = vget_lane_u64(transmute(v), 0); + assert_eq!(r, 1); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vgetq_lane_u16() { + let v = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r = vgetq_lane_u16(transmute(v), 1); + assert_eq!(r, 2); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vextq_s8() { + let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = i8x16::new( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 31, 32, + ); + let e = i8x16::new(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19); + let r: i8x16 = transmute(vextq_s8(transmute(a), transmute(b), 3)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vextq_u8() { + let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = u8x16::new( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 31, 32, + ); + let e = u8x16::new(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19); + let r: u8x16 = transmute(vextq_u8(transmute(a), transmute(b), 3)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vshrq_n_u8() { + let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e = u8x16::new(0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4); + let r: u8x16 = transmute(vshrq_n_u8(transmute(a), 2)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vshlq_n_u8() { + let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let e = u8x16::new(4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64); + let r: u8x16 = transmute(vshlq_n_u8(transmute(a), 2)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vqmovn_u64() { + let a = u64x2::new(1, 2); + let e = u32x2::new(1, 2); + let r: u32x2 = transmute(vqmovn_u64(transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vreinterpret_u64_u32() { + let v: i8 = 42; + let e = i8x16::new( + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + ); + let r: i8x16 = transmute(vdupq_n_s8(v)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vdupq_n_s8() { + let v: i8 = 42; + let e = i8x16::new( + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + ); + let r: i8x16 = transmute(vdupq_n_s8(v)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vdupq_n_u8() { + let v: u8 = 42; + let e = u8x16::new( + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + ); + let r: u8x16 = transmute(vdupq_n_u8(v)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vmovq_n_u8() { + let v: u8 = 42; + let e = u8x16::new( + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + ); + let r: u8x16 = transmute(vmovq_n_u8(v)); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vgetq_lane_u64() { + let v = i64x2::new(1, 2); + let r = vgetq_lane_u64(transmute(v), 1); + assert_eq!(r, 2); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vadd_s8() { + test_ari_s8( + |i, j| vadd_s8(i, j), + |a: i8, b: i8| -> i8 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddq_s8() { + testq_ari_s8( + |i, j| vaddq_s8(i, j), + |a: i8, b: i8| -> i8 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vadd_s16() { + test_ari_s16( + |i, j| vadd_s16(i, j), + |a: i16, b: i16| -> i16 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddq_s16() { + testq_ari_s16( + |i, j| vaddq_s16(i, j), + |a: i16, b: i16| -> i16 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vadd_s32() { + test_ari_s32( + |i, j| vadd_s32(i, j), + |a: i32, b: i32| -> i32 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddq_s32() { + testq_ari_s32( + |i, j| vaddq_s32(i, j), + |a: i32, b: i32| -> i32 { a.overflowing_add(b).0 }, + ); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vadd_u8() { + test_ari_u8( + |i, j| vadd_u8(i, j), + |a: u8, b: u8| -> u8 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddq_u8() { + testq_ari_u8( + |i, j| vaddq_u8(i, j), + |a: u8, b: u8| -> u8 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vadd_u16() { + test_ari_u16( + |i, j| vadd_u16(i, j), + |a: u16, b: u16| -> u16 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddq_u16() { + testq_ari_u16( + |i, j| vaddq_u16(i, j), + |a: u16, b: u16| -> u16 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vadd_u32() { + test_ari_u32( + |i, j| vadd_u32(i, j), + |a: u32, b: u32| -> u32 { a.overflowing_add(b).0 }, + ); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddq_u32() { + testq_ari_u32( + |i, j| vaddq_u32(i, j), + |a: u32, b: u32| -> u32 { a.overflowing_add(b).0 }, + ); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vadd_f32() { + test_ari_f32(|i, j| vadd_f32(i, j), |a: f32, b: f32| -> f32 { a + b }); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddq_f32() { + testq_ari_f32(|i, j| vaddq_f32(i, j), |a: f32, b: f32| -> f32 { a + b }); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_s8() { + let v = i8::MAX; + let a = i8x8::new(v, v, v, v, v, v, v, v); + let v = 2 * (v as i16); + let e = i16x8::new(v, v, v, v, v, v, v, v); + let r: i16x8 = transmute(vaddl_s8(transmute(a), transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_s16() { + let v = i16::MAX; + let a = i16x4::new(v, v, v, v); + let v = 2 * (v as i32); + let e = i32x4::new(v, v, v, v); + let r: i32x4 = transmute(vaddl_s16(transmute(a), transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_s32() { + let v = i32::MAX; + let a = i32x2::new(v, v); + let v = 2 * (v as i64); + let e = i64x2::new(v, v); + let r: i64x2 = transmute(vaddl_s32(transmute(a), transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_u8() { + let v = u8::MAX; + let a = u8x8::new(v, v, v, v, v, v, v, v); + let v = 2 * (v as u16); + let e = u16x8::new(v, v, v, v, v, v, v, v); + let r: u16x8 = transmute(vaddl_u8(transmute(a), transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_u16() { + let v = u16::MAX; + let a = u16x4::new(v, v, v, v); + let v = 2 * (v as u32); + let e = u32x4::new(v, v, v, v); + let r: u32x4 = transmute(vaddl_u16(transmute(a), transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_u32() { + let v = u32::MAX; + let a = u32x2::new(v, v); + let v = 2 * (v as u64); + let e = u64x2::new(v, v); + let r: u64x2 = transmute(vaddl_u32(transmute(a), transmute(a))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_high_s8() { + let a = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let x = i8::MAX; + let b = i8x16::new(x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x); + let x = x as i16; + let e = i16x8::new(x + 8, x + 9, x + 10, x + 11, x + 12, x + 13, x + 14, x + 15); + let r: i16x8 = transmute(vaddl_high_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_high_s16() { + let a = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let x = i16::MAX; + let b = i16x8::new(x, x, x, x, x, x, x, x); + let x = x as i32; + let e = i32x4::new(x + 4, x + 5, x + 6, x + 7); + let r: i32x4 = transmute(vaddl_high_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_high_s32() { + let a = i32x4::new(0, 1, 2, 3); + let x = i32::MAX; + let b = i32x4::new(x, x, x, x); + let x = x as i64; + let e = i64x2::new(x + 2, x + 3); + let r: i64x2 = transmute(vaddl_high_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_high_u8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let x = u8::MAX; + let b = u8x16::new(x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x); + let x = x as u16; + let e = u16x8::new(x + 8, x + 9, x + 10, x + 11, x + 12, x + 13, x + 14, x + 15); + let r: u16x8 = transmute(vaddl_high_u8(transmute(a), transmute(b))); + assert_eq!(r, e); } -} -/// Load multiple single-element structures to one, two, three, or four registers -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(ldr))] -// even gcc compiles this to ldr: https://clang.godbolt.org/z/1bvH2x -// #[cfg_attr(test, assert_instr(ld1))] -pub unsafe fn vld1q_s8(addr: *const i8) -> int8x16_t { - ptr::read(addr as *const int8x16_t) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_high_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let x = u16::MAX; + let b = u16x8::new(x, x, x, x, x, x, x, x); + let x = x as u32; + let e = u32x4::new(x + 4, x + 5, x + 6, x + 7); + let r: u32x4 = transmute(vaddl_high_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Load multiple single-element structures to one, two, three, or four registers -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(test, assert_instr(ldr))] -// even gcc compiles this to ldr: https://clang.godbolt.org/z/1bvH2x -// #[cfg_attr(test, assert_instr(ld1))] -pub unsafe fn vld1q_u8(addr: *const u8) -> uint8x16_t { - ptr::read(addr as *const uint8x16_t) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddl_high_u32() { + let a = u32x4::new(0, 1, 2, 3); + let x = u32::MAX; + let b = u32x4::new(x, x, x, x); + let x = x as u64; + let e = u64x2::new(x + 2, x + 3); + let r: u64x2 = transmute(vaddl_high_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Load multiple single-element structures to one, two, three, or four registers -#[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon")] -#[target_feature(enable = "v7")] -#[cfg_attr(test, assert_instr("vld1.32"))] -pub unsafe fn vld1q_s32(addr: *const i32) -> int32x4_t { - vld1q_v4i32(addr as *const u8, 4) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_s8() { + let x = i16::MAX; + let a = i16x8::new(x, 1, 2, 3, 4, 5, 6, 7); + let y = i8::MAX; + let b = i8x8::new(y, y, y, y, y, y, y, y); + let y = y as i16; + let e = i16x8::new(x + y, 1 + y, 2 + y, 3 + y, 4 + y, 5 + y, 6 + y, 7 + y); + let r: i16x8 = transmute(vaddw_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Load multiple single-element structures to one, two, three, or four registers -#[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon")] -#[target_feature(enable = "v7")] -#[cfg_attr(test, assert_instr("vld1.32"))] -pub unsafe fn vld1q_u32(addr: *const u32) -> uint32x4_t { - transmute(vld1q_v4i32(addr as *const u8, 4)) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_s16() { + let x = i32::MAX; + let a = i32x4::new(x, 1, 2, 3); + let y = i16::MAX; + let b = i16x4::new(y, y, y, y); + let y = y as i32; + let e = i32x4::new(x + y, 1 + y, 2 + y, 3 + y); + let r: i32x4 = transmute(vaddw_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Load multiple single-element structures to one, two, three, or four registers -#[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon")] -#[target_feature(enable = "v7")] -#[cfg_attr(test, assert_instr("vld1.32"))] -pub unsafe fn vld1q_f32(addr: *const f32) -> float32x4_t { - vld1q_v4f32(addr as *const u8, 4) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_s32() { + let x = i64::MAX; + let a = i64x2::new(x, 1); + let y = i32::MAX; + let b = i32x2::new(y, y); + let y = y as i64; + let e = i64x2::new(x + y, 1 + y); + let r: i64x2 = transmute(vaddw_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Load one single-element structure and Replicate to all lanes (of one register). -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] -pub unsafe fn vld1q_dup_f32(addr: *const f32) -> float32x4_t { - use crate::core_arch::simd::f32x4; - let v = *addr; - transmute(f32x4::new(v, v, v, v)) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_u8() { + let x = u16::MAX; + let a = u16x8::new(x, 1, 2, 3, 4, 5, 6, 7); + let y = u8::MAX; + let b = u8x8::new(y, y, y, y, y, y, y, y); + let y = y as u16; + let e = u16x8::new(x + y, 1 + y, 2 + y, 3 + y, 4 + y, 5 + y, 6 + y, 7 + y); + let r: u16x8 = transmute(vaddw_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } -// These float-to-int implementations have undefined behaviour when `a` overflows -// the destination type. Clang has the same problem: https://llvm.org/PR47510 + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_u16() { + let x = u32::MAX; + let a = u32x4::new(x, 1, 2, 3); + let y = u16::MAX; + let b = u16x4::new(y, y, y, y); + let y = y as u32; + let e = u32x4::new(x + y, 1 + y, 2 + y, 3 + y); + let r: u32x4 = transmute(vaddw_u16(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Floating-point Convert to Signed fixed-point, rounding toward Zero (vector) -#[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon")] -#[target_feature(enable = "v7")] -#[cfg_attr(test, assert_instr("vcvt.s32.f32"))] -pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { - use crate::core_arch::simd::{f32x4, i32x4}; - transmute(simd_cast::<_, i32x4>(transmute::<_, f32x4>(a))) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_u32() { + let x = u64::MAX; + let a = u64x2::new(x, 1); + let y = u32::MAX; + let b = u32x2::new(y, y); + let y = y as u64; + let e = u64x2::new(x + y, 1 + y); + let r: u64x2 = transmute(vaddw_u32(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) -#[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon")] -#[target_feature(enable = "v7")] -#[cfg_attr(test, assert_instr("vcvt.u32.f32"))] -pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { - use crate::core_arch::simd::{f32x4, u32x4}; - transmute(simd_cast::<_, u32x4>(transmute::<_, f32x4>(a))) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_high_s8() { + let x = i16::MAX; + let a = i16x8::new(x, 1, 2, 3, 4, 5, 6, 7); + let y = i8::MAX; + let b = i8x16::new(0, 0, 0, 0, 0, 0, 0, 0, y, y, y, y, y, y, y, y); + let y = y as i16; + let e = i16x8::new(x + y, 1 + y, 2 + y, 3 + y, 4 + y, 5 + y, 6 + y, 7 + y); + let r: i16x8 = transmute(vaddw_high_s8(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Floating-point minimum (vector). -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmin.f32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] -pub unsafe fn vminq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - vminq_f32_(a, b) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_high_s16() { + let x = i32::MAX; + let a = i32x4::new(x, 1, 2, 3); + let y = i16::MAX; + let b = i16x8::new(0, 0, 0, 0, y, y, y, y); + let y = y as i32; + let e = i32x4::new(x + y, 1 + y, 2 + y, 3 + y); + let r: i32x4 = transmute(vaddw_high_s16(transmute(a), transmute(b))); + assert_eq!(r, e); + } -/// Floating-point maxmimum (vector). -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmax.f32"))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] -pub unsafe fn vmaxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { - vmaxq_f32_(a, b) -} + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_high_s32() { + let x = i64::MAX; + let a = i64x2::new(x, 1); + let y = i32::MAX; + let b = i32x4::new(0, 0, y, y); + let y = y as i64; + let e = i64x2::new(x + y, 1 + y); + let r: i64x2 = transmute(vaddw_high_s32(transmute(a), transmute(b))); + assert_eq!(r, e); + } -#[cfg(test)] -mod tests { - use super::*; - use crate::core_arch::arm::test_support::*; - use crate::core_arch::{arm::*, simd::*}; - use std::{i16, i32, i8, mem::transmute, u16, u32, u8, vec::Vec}; - use stdarch_test::simd_test; + #[simd_test(enable = "neon")] + unsafe fn test_vaddw_high_u8() { + let x = u16::MAX; + let a = u16x8::new(x, 1, 2, 3, 4, 5, 6, 7); + let y = u8::MAX; + let b = u8x16::new(0, 0, 0, 0, 0, 0, 0, 0, y, y, y, y, y, y, y, y); + let y = y as u16; + let e = u16x8::new(x + y, 1 + y, 2 + y, 3 + y, 4 + y, 5 + y, 6 + y, 7 + y); + let r: u16x8 = transmute(vaddw_high_u8(transmute(a), transmute(b))); + assert_eq!(r, e); + } #[simd_test(enable = "neon")] - unsafe fn test_vld1q_s8() { - let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e = a; - let r: i8x16 = transmute(vld1q_s8(transmute(&a))); + unsafe fn test_vaddw_high_u16() { + let x = u32::MAX; + let a = u32x4::new(x, 1, 2, 3); + let y = u16::MAX; + let b = u16x8::new(0, 0, 0, 0, y, y, y, y); + let y = y as u32; + let e = u32x4::new(x + y, 1 + y, 2 + y, 3 + y); + let r: u32x4 = transmute(vaddw_high_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vld1q_u8() { - let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e = a; - let r: u8x16 = transmute(vld1q_u8(transmute(&a))); + unsafe fn test_vaddw_high_u32() { + let x = u64::MAX; + let a = u64x2::new(x, 1); + let y = u32::MAX; + let b = u32x4::new(0, 0, y, y); + let y = y as u64; + let e = u64x2::new(x + y, 1 + y); + let r: u64x2 = transmute(vaddw_high_u32(transmute(a), transmute(b))); assert_eq!(r, e); } - #[cfg(target_arch = "arm")] #[simd_test(enable = "neon")] - unsafe fn test_vld1q_f32() { - let e = f32x4::new(1., 2., 3., 4.); - let f = [0., 1., 2., 3., 4.]; - // do a load that has 4 byte alignment to make sure we're not - // over aligning it - let r: f32x4 = transmute(vld1q_f32(f[1..].as_ptr())); + unsafe fn test_vaddhn_s16() { + let a = i16x8::new( + (0 << 8) + 1, + (1 << 8) + 1, + (2 << 8) + 1, + (3 << 8) + 1, + (4 << 8) + 1, + (5 << 8) + 1, + (6 << 8) + 1, + (7 << 8) + 1, + ); + let e = i8x8::new(0, 2, 4, 6, 8, 10, 12, 14); + let r: i8x8 = transmute(vaddhn_s16(transmute(a), transmute(a))); assert_eq!(r, e); } - #[cfg(target_arch = "arm")] #[simd_test(enable = "neon")] - unsafe fn test_vld1q_s32() { - let e = i32x4::new(1, 2, 3, 4); - let f = [0, 1, 2, 3, 4]; - // do a load that has 4 byte alignment to make sure we're not - // over aligning it - let r: i32x4 = transmute(vld1q_s32(f[1..].as_ptr())); + unsafe fn test_vaddhn_s32() { + let a = i32x4::new((0 << 16) + 1, (1 << 16) + 1, (2 << 16) + 1, (3 << 16) + 1); + let e = i16x4::new(0, 2, 4, 6); + let r: i16x4 = transmute(vaddhn_s32(transmute(a), transmute(a))); assert_eq!(r, e); } - #[cfg(target_arch = "arm")] #[simd_test(enable = "neon")] - unsafe fn test_vld1q_u32() { - let e = u32x4::new(1, 2, 3, 4); - let f = [0, 1, 2, 3, 4]; - // do a load that has 4 byte alignment to make sure we're not - // over aligning it - let r: u32x4 = transmute(vld1q_u32(f[1..].as_ptr())); + unsafe fn test_vaddhn_s64() { + let a = i64x2::new((0 << 32) + 1, (1 << 32) + 1); + let e = i32x2::new(0, 2); + let r: i32x2 = transmute(vaddhn_s64(transmute(a), transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vld1q_dup_f32() { - let e = f32x4::new(1., 1., 1., 1.); - let f = [1., 2., 3., 4.]; - let r: f32x4 = transmute(vld1q_dup_f32(f.as_ptr())); + unsafe fn test_vaddhn_u16() { + let a = u16x8::new( + (0 << 8) + 1, + (1 << 8) + 1, + (2 << 8) + 1, + (3 << 8) + 1, + (4 << 8) + 1, + (5 << 8) + 1, + (6 << 8) + 1, + (7 << 8) + 1, + ); + let e = u8x8::new(0, 2, 4, 6, 8, 10, 12, 14); + let r: u8x8 = transmute(vaddhn_u16(transmute(a), transmute(a))); assert_eq!(r, e); } - #[cfg(target_arch = "arm")] #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_s32_f32() { - let f = f32x4::new(-1., 2., 3., 4.); - let e = i32x4::new(-1, 2, 3, 4); - let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + unsafe fn test_vaddhn_u32() { + let a = u32x4::new((0 << 16) + 1, (1 << 16) + 1, (2 << 16) + 1, (3 << 16) + 1); + let e = u16x4::new(0, 2, 4, 6); + let r: u16x4 = transmute(vaddhn_u32(transmute(a), transmute(a))); assert_eq!(r, e); } - #[cfg(target_arch = "arm")] #[simd_test(enable = "neon")] - unsafe fn test_vcvtq_u32_f32() { - let f = f32x4::new(1., 2., 3., 4.); - let e = u32x4::new(1, 2, 3, 4); - let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + unsafe fn test_vaddhn_u64() { + let a = u64x2::new((0 << 32) + 1, (1 << 32) + 1); + let e = u32x2::new(0, 2); + let r: u32x2 = transmute(vaddhn_u64(transmute(a), transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vget_lane_u8() { - let v = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let r = vget_lane_u8(transmute(v), 1); - assert_eq!(r, 2); + unsafe fn test_vaddhn_high_s16() { + let r = i8x8::splat(42); + let a = i16x8::new( + (0 << 8) + 1, + (1 << 8) + 1, + (2 << 8) + 1, + (3 << 8) + 1, + (4 << 8) + 1, + (5 << 8) + 1, + (6 << 8) + 1, + (7 << 8) + 1, + ); + let e = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 0, 2, 4, 6, 8, 10, 12, 14); + let r: i8x16 = transmute(vaddhn_high_s16(transmute(r), transmute(a), transmute(a))); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vgetq_lane_u32() { - let v = i32x4::new(1, 2, 3, 4); - let r = vgetq_lane_u32(transmute(v), 1); - assert_eq!(r, 2); + unsafe fn test_vaddhn_high_s32() { + let r = i16x4::splat(42); + let a = i32x4::new((0 << 16) + 1, (1 << 16) + 1, (2 << 16) + 1, (3 << 16) + 1); + let e = i16x8::new(42, 42, 42, 42, 0, 2, 4, 6); + let r: i16x8 = transmute(vaddhn_high_s32(transmute(r), transmute(a), transmute(a))); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vgetq_lane_s32() { - let v = i32x4::new(1, 2, 3, 4); - let r = vgetq_lane_s32(transmute(v), 1); - assert_eq!(r, 2); + unsafe fn test_vaddhn_high_s64() { + let r = i32x2::splat(42); + let a = i64x2::new((0 << 32) + 1, (1 << 32) + 1); + let e = i32x4::new(42, 42, 0, 2); + let r: i32x4 = transmute(vaddhn_high_s64(transmute(r), transmute(a), transmute(a))); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vget_lane_u64() { - let v: u64 = 1; - let r = vget_lane_u64(transmute(v), 0); - assert_eq!(r, 1); + unsafe fn test_vaddhn_high_u16() { + let r = u8x8::splat(42); + let a = u16x8::new( + (0 << 8) + 1, + (1 << 8) + 1, + (2 << 8) + 1, + (3 << 8) + 1, + (4 << 8) + 1, + (5 << 8) + 1, + (6 << 8) + 1, + (7 << 8) + 1, + ); + let e = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 0, 2, 4, 6, 8, 10, 12, 14); + let r: u8x16 = transmute(vaddhn_high_u16(transmute(r), transmute(a), transmute(a))); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vgetq_lane_u16() { - let v = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); - let r = vgetq_lane_u16(transmute(v), 1); - assert_eq!(r, 2); + unsafe fn test_vaddhn_high_u32() { + let r = u16x4::splat(42); + let a = u32x4::new((0 << 16) + 1, (1 << 16) + 1, (2 << 16) + 1, (3 << 16) + 1); + let e = u16x8::new(42, 42, 42, 42, 0, 2, 4, 6); + let r: u16x8 = transmute(vaddhn_high_u32(transmute(r), transmute(a), transmute(a))); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_s8() { - let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = i8x16::new( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 31, 32, - ); - let e = i8x16::new(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19); - let r: i8x16 = transmute(vextq_s8(transmute(a), transmute(b), 3)); + unsafe fn test_vaddhn_high_u64() { + let r = u32x2::splat(42); + let a = u64x2::new((0 << 32) + 1, (1 << 32) + 1); + let e = u32x4::new(42, 42, 0, 2); + let r: u32x4 = transmute(vaddhn_high_u64(transmute(r), transmute(a), transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vextq_u8() { - let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = u8x16::new( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 31, 32, - ); - let e = u8x16::new(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19); - let r: u8x16 = transmute(vextq_u8(transmute(a), transmute(b), 3)); + unsafe fn test_vraddhn_s16() { + let round_constant: i16 = (1 << 8) - 1; + let a = i16x8::new( + 0 << 8, + 1 << 8, + 2 << 8, + 3 << 8, + 4 << 8, + 5 << 8, + 6 << 8, + 7 << 8, + ); + let b = i16x8::new( + 0 << 8, + (1 << 8) + round_constant, + 2 << 8, + (3 << 8) + round_constant, + 4 << 8, + (5 << 8) + round_constant, + 6 << 8, + (7 << 8) + round_constant, + ); + let e = i8x8::new(0, 3, 4, 7, 8, 11, 12, 15); + let r: i8x8 = transmute(vraddhn_s16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vshrq_n_u8() { - let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e = u8x16::new(0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4); - let r: u8x16 = transmute(vshrq_n_u8(transmute(a), 2)); + unsafe fn test_vraddhn_s32() { + let round_constant: i32 = (1 << 16) - 1; + let a = i32x4::new(0 << 16, 1 << 16, 2 << 16, 3 << 16); + let b = i32x4::new( + 0 << 16, + (1 << 16) + round_constant, + 2 << 16, + (3 << 16) + round_constant, + ); + let e = i16x4::new(0, 3, 4, 7); + let r: i16x4 = transmute(vraddhn_s32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vshlq_n_u8() { - let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let e = u8x16::new(4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64); - let r: u8x16 = transmute(vshlq_n_u8(transmute(a), 2)); + unsafe fn test_vraddhn_s64() { + let round_constant: i64 = (1 << 32) - 1; + let a = i64x2::new(0 << 32, 1 << 32); + let b = i64x2::new(0 << 32, (1 << 32) + round_constant); + let e = i32x2::new(0, 3); + let r: i32x2 = transmute(vraddhn_s64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vqmovn_u64() { - let a = u64x2::new(1, 2); - let e = u32x2::new(1, 2); - let r: u32x2 = transmute(vqmovn_u64(transmute(a))); + unsafe fn test_vraddhn_u16() { + let round_constant: u16 = (1 << 8) - 1; + let a = u16x8::new( + 0 << 8, + 1 << 8, + 2 << 8, + 3 << 8, + 4 << 8, + 5 << 8, + 6 << 8, + 7 << 8, + ); + let b = u16x8::new( + 0 << 8, + (1 << 8) + round_constant, + 2 << 8, + (3 << 8) + round_constant, + 4 << 8, + (5 << 8) + round_constant, + 6 << 8, + (7 << 8) + round_constant, + ); + let e = u8x8::new(0, 3, 4, 7, 8, 11, 12, 15); + let r: u8x8 = transmute(vraddhn_u16(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vreinterpret_u64_u32() { - let v: i8 = 42; - let e = i8x16::new( - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + unsafe fn test_vraddhn_u32() { + let round_constant: u32 = (1 << 16) - 1; + let a = u32x4::new(0 << 16, 1 << 16, 2 << 16, 3 << 16); + let b = u32x4::new( + 0 << 16, + (1 << 16) + round_constant, + 2 << 16, + (3 << 16) + round_constant, ); - let r: i8x16 = transmute(vdupq_n_s8(v)); + let e = u16x4::new(0, 3, 4, 7); + let r: u16x4 = transmute(vraddhn_u32(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_n_s8() { - let v: i8 = 42; - let e = i8x16::new( - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - ); - let r: i8x16 = transmute(vdupq_n_s8(v)); + unsafe fn test_vraddhn_u64() { + let round_constant: u64 = (1 << 32) - 1; + let a = u64x2::new(0 << 32, 1 << 32); + let b = u64x2::new(0 << 32, (1 << 32) + round_constant); + let e = u32x2::new(0, 3); + let r: u32x2 = transmute(vraddhn_u64(transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vdupq_n_u8() { - let v: u8 = 42; - let e = u8x16::new( - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - ); - let r: u8x16 = transmute(vdupq_n_u8(v)); + unsafe fn test_vraddhn_high_s16() { + let r = i8x8::splat(42); + let round_constant: i16 = (1 << 8) - 1; + let a = i16x8::new( + 0 << 8, + 1 << 8, + 2 << 8, + 3 << 8, + 4 << 8, + 5 << 8, + 6 << 8, + 7 << 8, + ); + let b = i16x8::new( + 0 << 8, + (1 << 8) + round_constant, + 2 << 8, + (3 << 8) + round_constant, + 4 << 8, + (5 << 8) + round_constant, + 6 << 8, + (7 << 8) + round_constant, + ); + let e = i8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 0, 3, 4, 7, 8, 11, 12, 15); + let r: i8x16 = transmute(vraddhn_high_s16(transmute(r), transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmovq_n_u8() { - let v: u8 = 42; - let e = u8x16::new( - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + unsafe fn test_vraddhn_high_s32() { + let r = i16x4::splat(42); + let round_constant: i32 = (1 << 16) - 1; + let a = i32x4::new(0 << 16, 1 << 16, 2 << 16, 3 << 16); + let b = i32x4::new( + 0 << 16, + (1 << 16) + round_constant, + 2 << 16, + (3 << 16) + round_constant, ); - let r: u8x16 = transmute(vmovq_n_u8(v)); + let e = i16x8::new(42, 42, 42, 42, 0, 3, 4, 7); + let r: i16x8 = transmute(vraddhn_high_s32(transmute(r), transmute(a), transmute(b))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vgetq_lane_u64() { - let v = i64x2::new(1, 2); - let r = vgetq_lane_u64(transmute(v), 1); - assert_eq!(r, 2); + unsafe fn test_vraddhn_high_s64() { + let r = i32x2::splat(42); + let round_constant: i64 = (1 << 32) - 1; + let a = i64x2::new(0 << 32, 1 << 32); + let b = i64x2::new(0 << 32, (1 << 32) + round_constant); + let e = i32x4::new(42, 42, 0, 3); + let r: i32x4 = transmute(vraddhn_high_s64(transmute(r), transmute(a), transmute(b))); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vadd_s8() { - test_ari_s8( - |i, j| vadd_s8(i, j), - |a: i8, b: i8| -> i8 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vraddhn_high_u16() { + let r = u8x8::splat(42); + let round_constant: u16 = (1 << 8) - 1; + let a = u16x8::new( + 0 << 8, + 1 << 8, + 2 << 8, + 3 << 8, + 4 << 8, + 5 << 8, + 6 << 8, + 7 << 8, + ); + let b = u16x8::new( + 0 << 8, + (1 << 8) + round_constant, + 2 << 8, + (3 << 8) + round_constant, + 4 << 8, + (5 << 8) + round_constant, + 6 << 8, + (7 << 8) + round_constant, + ); + let e = u8x16::new(42, 42, 42, 42, 42, 42, 42, 42, 0, 3, 4, 7, 8, 11, 12, 15); + let r: u8x16 = transmute(vraddhn_high_u16(transmute(r), transmute(a), transmute(b))); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vaddq_s8() { - testq_ari_s8( - |i, j| vaddq_s8(i, j), - |a: i8, b: i8| -> i8 { a.overflowing_add(b).0 }, + unsafe fn test_vraddhn_high_u32() { + let r = u16x4::splat(42); + let round_constant: u32 = (1 << 16) - 1; + let a = u32x4::new(0 << 16, 1 << 16, 2 << 16, 3 << 16); + let b = u32x4::new( + 0 << 16, + (1 << 16) + round_constant, + 2 << 16, + (3 << 16) + round_constant, ); + let e = u16x8::new(42, 42, 42, 42, 0, 3, 4, 7); + let r: u16x8 = transmute(vraddhn_high_s32(transmute(r), transmute(a), transmute(b))); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vadd_s16() { - test_ari_s16( - |i, j| vadd_s16(i, j), - |a: i16, b: i16| -> i16 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vraddhn_high_u64() { + let r = u32x2::splat(42); + let round_constant: u64 = (1 << 32) - 1; + let a = u64x2::new(0 << 32, 1 << 32); + let b = u64x2::new(0 << 32, (1 << 32) + round_constant); + let e = u32x4::new(42, 42, 0, 3); + let r: u32x4 = transmute(vraddhn_high_s64(transmute(r), transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddl_s8() { + let a = i8x8::new(-4, -3, -2, -1, 0, 1, 2, 3); + let r: i16x4 = transmute(vpaddl_s8(transmute(a))); + let e = i16x4::new(-7, -3, 1, 5); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddl_s16() { + let a = i16x4::new(-2, -1, 0, 1); + let r: i32x2 = transmute(vpaddl_s16(transmute(a))); + let e = i32x2::new(-3, 1); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddl_s32() { + let a = i32x2::new(-1, 0); + let r: i64x1 = transmute(vpaddl_s32(transmute(a))); + let e = i64x1::new(-1); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddlq_s8() { + let a = i8x16::new(-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7); + let r: i16x8 = transmute(vpaddlq_s8(transmute(a))); + let e = i16x8::new(-15, -11, -7, -3, 1, 5, 9, 13); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddlq_s16() { + let a = i16x8::new(-4, -3, -2, -1, 0, 1, 2, 3); + let r: i32x4 = transmute(vpaddlq_s16(transmute(a))); + let e = i32x4::new(-7, -3, 1, 5); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddlq_s32() { + let a = i32x4::new(-2, -1, 0, 1); + let r: i64x2 = transmute(vpaddlq_s32(transmute(a))); + let e = i64x2::new(-3, 1); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vaddq_s16() { - testq_ari_s16( - |i, j| vaddq_s16(i, j), - |a: i16, b: i16| -> i16 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpaddl_u8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, u8::MAX); + let r: u16x4 = transmute(vpaddl_u8(transmute(a))); + let e = u16x4::new(1, 5, 9, u8::MAX as u16 + 6); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vadd_s32() { - test_ari_s32( - |i, j| vadd_s32(i, j), - |a: i32, b: i32| -> i32 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpaddl_u16() { + let a = u16x4::new(0, 1, 2, u16::MAX); + let r: u32x2 = transmute(vpaddl_u16(transmute(a))); + let e = u32x2::new(1, u16::MAX as u32 + 2); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vaddq_s32() { - testq_ari_s32( - |i, j| vaddq_s32(i, j), - |a: i32, b: i32| -> i32 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpaddl_u32() { + let a = u32x2::new(1, u32::MAX); + let r: u64x1 = transmute(vpaddl_u32(transmute(a))); + let e = u64x1::new(u32::MAX as u64 + 1); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vadd_u8() { - test_ari_u8( - |i, j| vadd_u8(i, j), - |a: u8, b: u8| -> u8 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpaddlq_u8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, u8::MAX); + let r: u16x8 = transmute(vpaddlq_u8(transmute(a))); + let e = u16x8::new(1, 5, 9, 13, 17, 21, 25, u8::MAX as u16 + 14); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vaddq_u8() { - testq_ari_u8( - |i, j| vaddq_u8(i, j), - |a: u8, b: u8| -> u8 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpaddlq_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, u16::MAX); + let r: u32x4 = transmute(vpaddlq_u16(transmute(a))); + let e = u32x4::new(1, 5, 9, u16::MAX as u32 + 6); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vadd_u16() { - test_ari_u16( - |i, j| vadd_u16(i, j), - |a: u16, b: u16| -> u16 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpaddlq_u32() { + let a = u32x4::new(0, 1, 2, u32::MAX); + let r: u64x2 = transmute(vpaddlq_u32(transmute(a))); + let e = u64x2::new(1, u32::MAX as u64 + 2); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vaddq_u16() { - testq_ari_u16( - |i, j| vaddq_u16(i, j), - |a: u16, b: u16| -> u16 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpadal_s8() { + let a = i16x4::new(42, 42, 42, 42); + let b = i8x8::new(-4, -3, -2, -1, 0, 1, 2, 3); + let r: i16x4 = transmute(vpadal_s8(transmute(a), transmute(b))); + let e = i16x4::new(35, 39, 43, 47); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vadd_u32() { - test_ari_u32( - |i, j| vadd_u32(i, j), - |a: u32, b: u32| -> u32 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpadal_s16() { + let a = i32x2::new(42, 42); + let b = i16x4::new(-2, -1, 0, 1); + let r: i32x2 = transmute(vpadal_s16(transmute(a), transmute(b))); + let e = i32x2::new(39, 43); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vaddq_u32() { - testq_ari_u32( - |i, j| vaddq_u32(i, j), - |a: u32, b: u32| -> u32 { a.overflowing_add(b).0 }, - ); + unsafe fn test_vpadal_s32() { + let a = i64x1::new(42); + let b = i32x2::new(-1, 0); + let r: i64x1 = transmute(vpadal_s32(transmute(a), transmute(b))); + let e = i64x1::new(41); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vadd_f32() { - test_ari_f32(|i, j| vadd_f32(i, j), |a: f32, b: f32| -> f32 { a + b }); + unsafe fn test_vpadalq_s8() { + let a = i16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b = i8x16::new(-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7); + let r: i16x8 = transmute(vpadalq_s8(transmute(a), transmute(b))); + let e = i16x8::new(27, 31, 35, 39, 43, 47, 51, 55); + assert_eq!(r, e); } + #[simd_test(enable = "neon")] - unsafe fn test_vaddq_f32() { - testq_ari_f32(|i, j| vaddq_f32(i, j), |a: f32, b: f32| -> f32 { a + b }); + unsafe fn test_vpadalq_s16() { + let a = i32x4::new(42, 42, 42, 42); + let b = i16x8::new(-4, -3, -2, -1, 0, 1, 2, 3); + let r: i32x4 = transmute(vpadalq_s16(transmute(a), transmute(b))); + let e = i32x4::new(35, 39, 43, 47); + assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vaddl_s8() { - let v = i8::MAX; - let a = i8x8::new(v, v, v, v, v, v, v, v); - let v = 2 * (v as i16); - let e = i16x8::new(v, v, v, v, v, v, v, v); - let r: i16x8 = transmute(vaddl_s8(transmute(a), transmute(a))); + unsafe fn test_vpadalq_s32() { + let a = i64x2::new(42, 42); + let b = i32x4::new(-2, -1, 0, 1); + let r: i64x2 = transmute(vpadalq_s32(transmute(a), transmute(b))); + let e = i64x2::new(39, 43); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vaddl_s16() { - let v = i16::MAX; - let a = i16x4::new(v, v, v, v); - let v = 2 * (v as i32); - let e = i32x4::new(v, v, v, v); - let r: i32x4 = transmute(vaddl_s16(transmute(a), transmute(a))); + unsafe fn test_vpadal_u8() { + let a = u16x4::new(42, 42, 42, 42); + let b = u8x8::new(0, 1, 2, 3, 4, 5, 6, u8::MAX); + let r: u16x4 = transmute(vpadal_u8(transmute(a), transmute(b))); + let e = u16x4::new(43, 47, 51, u8::MAX as u16 + 48); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vaddl_s32() { - let v = i32::MAX; - let a = i32x2::new(v, v); - let v = 2 * (v as i64); - let e = i64x2::new(v, v); - let r: i64x2 = transmute(vaddl_s32(transmute(a), transmute(a))); + unsafe fn test_vpadal_u16() { + let a = u32x2::new(42, 42); + let b = u16x4::new(0, 1, 2, u16::MAX); + let r: u32x2 = transmute(vpadal_u16(transmute(a), transmute(b))); + let e = u32x2::new(43, u16::MAX as u32 + 44); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vaddl_u8() { - let v = u8::MAX; - let a = u8x8::new(v, v, v, v, v, v, v, v); - let v = 2 * (v as u16); - let e = u16x8::new(v, v, v, v, v, v, v, v); - let r: u16x8 = transmute(vaddl_u8(transmute(a), transmute(a))); + unsafe fn test_vpadal_u32() { + let a = u64x1::new(42); + let b = u32x2::new(1, u32::MAX); + let r: u64x1 = transmute(vpadal_u32(transmute(a), transmute(b))); + let e = u64x1::new(u32::MAX as u64 + 43); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vaddl_u16() { - let v = u16::MAX; - let a = u16x4::new(v, v, v, v); - let v = 2 * (v as u32); - let e = u32x4::new(v, v, v, v); - let r: u32x4 = transmute(vaddl_u16(transmute(a), transmute(a))); + unsafe fn test_vpadalq_u8() { + let a = u16x8::new(42, 42, 42, 42, 42, 42, 42, 42); + let b = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, u8::MAX); + let r: u16x8 = transmute(vpadalq_u8(transmute(a), transmute(b))); + let e = u16x8::new(43, 47, 51, 55, 59, 63, 67, u8::MAX as u16 + 56); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vaddl_u32() { - let v = u32::MAX; - let a = u32x2::new(v, v); - let v = 2 * (v as u64); - let e = u64x2::new(v, v); - let r: u64x2 = transmute(vaddl_u32(transmute(a), transmute(a))); + unsafe fn test_vpadalq_u16() { + let a = u32x4::new(42, 42, 42, 42); + let b = u16x8::new(0, 1, 2, 3, 4, 5, 6, u16::MAX); + let r: u32x4 = transmute(vpadalq_u16(transmute(a), transmute(b))); + let e = u32x4::new(43, 47, 51, u16::MAX as u32 + 48); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpadalq_u32() { + let a = u64x2::new(42, 42); + let b = u32x4::new(0, 1, 2, u32::MAX); + let r: u64x2 = transmute(vpadalq_u32(transmute(a), transmute(b))); + let e = u64x2::new(43, u32::MAX as u64 + 44); assert_eq!(r, e); } @@ -4342,23 +7999,298 @@ mod tests { assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vminq_f32() { - let a = f32x4::new(1., -2., 3., -4.); - let b = f32x4::new(0., 3., 2., 8.); - let e = f32x4::new(0., -2., 2., -4.); - let r: f32x4 = transmute(vminq_f32(transmute(a), transmute(b))); + unsafe fn test_vcnt_s8() { + let a: i8x8 = transmute(u8x8::new( + 0b11001000, 0b11111111, 0b00000000, 0b11011111, 0b10000001, 0b10101001, 0b00001000, + 0b00111111, + )); + let e = i8x8::new(3, 8, 0, 7, 2, 4, 1, 6); + let r: i8x8 = transmute(vcnt_s8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vcntq_s8() { + let a: i8x16 = transmute(u8x16::new( + 0b11001000, 0b11111111, 0b00000000, 0b11011111, 0b10000001, 0b10101001, 0b00001000, + 0b00111111, 0b11101110, 0b00000000, 0b11111111, 0b00100001, 0b11111111, 0b10010111, + 0b11100000, 0b00010000, + )); + let e = i8x16::new(3, 8, 0, 7, 2, 4, 1, 6, 6, 0, 8, 2, 8, 5, 3, 1); + let r: i8x16 = transmute(vcntq_s8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vcnt_u8() { + let a = u8x8::new( + 0b11001000, 0b11111111, 0b00000000, 0b11011111, 0b10000001, 0b10101001, 0b00001000, + 0b00111111, + ); + let e = u8x8::new(3, 8, 0, 7, 2, 4, 1, 6); + let r: u8x8 = transmute(vcnt_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vcntq_u8() { + let a = u8x16::new( + 0b11001000, 0b11111111, 0b00000000, 0b11011111, 0b10000001, 0b10101001, 0b00001000, + 0b00111111, 0b11101110, 0b00000000, 0b11111111, 0b00100001, 0b11111111, 0b10010111, + 0b11100000, 0b00010000, + ); + let e = u8x16::new(3, 8, 0, 7, 2, 4, 1, 6, 6, 0, 8, 2, 8, 5, 3, 1); + let r: u8x16 = transmute(vcntq_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vcnt_p8() { + let a = u8x8::new( + 0b11001000, 0b11111111, 0b00000000, 0b11011111, 0b10000001, 0b10101001, 0b00001000, + 0b00111111, + ); + let e = u8x8::new(3, 8, 0, 7, 2, 4, 1, 6); + let r: u8x8 = transmute(vcnt_p8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vcntq_p8() { + let a = u8x16::new( + 0b11001000, 0b11111111, 0b00000000, 0b11011111, 0b10000001, 0b10101001, 0b00001000, + 0b00111111, 0b11101110, 0b00000000, 0b11111111, 0b00100001, 0b11111111, 0b10010111, + 0b11100000, 0b00010000, + ); + let e = u8x16::new(3, 8, 0, 7, 2, 4, 1, 6, 6, 0, 8, 2, 8, 5, 3, 1); + let r: u8x16 = transmute(vcntq_p8(transmute(a))); + assert_eq!(r, e); + } + unsafe fn test_vrev16_s8() { + let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = i8x8::new(1, 0, 3, 2, 5, 4, 7, 6); + let e: i8x8 = transmute(vrev16_s8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev16q_s8() { + let a = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = i8x16::new(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14); + let e: i8x16 = transmute(vrev16q_s8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev16_u8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u8x8::new(1, 0, 3, 2, 5, 4, 7, 6); + let e: u8x8 = transmute(vrev16_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev16q_u8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = u8x16::new(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14); + let e: u8x16 = transmute(vrev16q_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev16_p8() { + let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = i8x8::new(1, 0, 3, 2, 5, 4, 7, 6); + let e: i8x8 = transmute(vrev16_p8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev16q_p8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = u8x16::new(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14); + let e: u8x16 = transmute(vrev16q_p8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32_s8() { + let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = i8x8::new(3, 2, 1, 0, 7, 6, 5, 4); + let e: i8x8 = transmute(vrev32_s8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32q_s8() { + let a = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = i8x16::new(3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); + let e: i8x16 = transmute(vrev32q_s8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32_u8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u8x8::new(3, 2, 1, 0, 7, 6, 5, 4); + let e: u8x8 = transmute(vrev32_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32q_u8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = u8x16::new(3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); + let e: u8x16 = transmute(vrev32q_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32_u16() { + let a = u16x4::new(0, 1, 2, 3); + let r = u16x4::new(1, 0, 3, 2); + let e: u16x4 = transmute(vrev32_u16(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32q_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u16x8::new(1, 0, 3, 2, 5, 4, 7, 6); + let e: u16x8 = transmute(vrev32q_u16(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32_p8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u8x8::new(3, 2, 1, 0, 7, 6, 5, 4); + let e: u8x8 = transmute(vrev32_p8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev32q_p8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = u8x16::new(3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); + let e: u8x16 = transmute(vrev32q_p8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_s8() { + let a = i8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = i8x8::new(7, 6, 5, 4, 3, 2, 1, 0); + let e: i8x8 = transmute(vrev64_s8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_s8() { + let a = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = i8x16::new(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8); + let e: i8x16 = transmute(vrev64q_s8(transmute(a))); assert_eq!(r, e); } #[simd_test(enable = "neon")] - unsafe fn test_vmaxq_f32() { - let a = f32x4::new(1., -2., 3., -4.); - let b = f32x4::new(0., 3., 2., 8.); - let e = f32x4::new(1., 3., 3., 8.); - let r: f32x4 = transmute(vmaxq_f32(transmute(a), transmute(b))); + unsafe fn test_vrev64_s16() { + let a = i16x4::new(0, 1, 2, 3); + let r = i16x4::new(3, 2, 1, 0); + let e: i16x4 = transmute(vrev64_s16(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_s16() { + let a = i16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = i16x8::new(3, 2, 1, 0, 7, 6, 5, 4); + let e: i16x8 = transmute(vrev64q_s16(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_s32() { + let a = i32x2::new(0, 1); + let r = i32x2::new(1, 0); + let e: i32x2 = transmute(vrev64_s32(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_s32() { + let a = i32x4::new(0, 1, 2, 3); + let r = i32x4::new(1, 0, 3, 2); + let e: i32x4 = transmute(vrev64q_s32(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_u8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u8x8::new(7, 6, 5, 4, 3, 2, 1, 0); + let e: u8x8 = transmute(vrev64_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_u8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = u8x16::new(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8); + let e: u8x16 = transmute(vrev64q_u8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_u16() { + let a = u16x4::new(0, 1, 2, 3); + let r = u16x4::new(3, 2, 1, 0); + let e: u16x4 = transmute(vrev64_u16(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u16x8::new(3, 2, 1, 0, 7, 6, 5, 4); + let e: u16x8 = transmute(vrev64q_u16(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_u32() { + let a = u32x2::new(0, 1); + let r = u32x2::new(1, 0); + let e: u32x2 = transmute(vrev64_u32(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_u32() { + let a = u32x4::new(0, 1, 2, 3); + let r = u32x4::new(1, 0, 3, 2); + let e: u32x4 = transmute(vrev64q_u32(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_f32() { + let a = f32x2::new(1.0, 2.0); + let r = f32x2::new(2.0, 1.0); + let e: f32x2 = transmute(vrev64_f32(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_f32() { + let a = f32x4::new(1.0, 2.0, -2.0, -1.0); + let r = f32x4::new(2.0, 1.0, -1.0, -2.0); + let e: f32x4 = transmute(vrev64q_f32(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_p8() { + let a = u8x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u8x8::new(7, 6, 5, 4, 3, 2, 1, 0); + let e: u8x8 = transmute(vrev64_p8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_p8() { + let a = u8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = u8x16::new(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8); + let e: u8x16 = transmute(vrev64q_p8(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64_p16() { + let a = u16x4::new(0, 1, 2, 3); + let r = u16x4::new(3, 2, 1, 0); + let e: u16x4 = transmute(vrev64_p16(transmute(a))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vrev64q_p16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let r = u16x8::new(3, 2, 1, 0, 7, 6, 5, 4); + let e: u16x8 = transmute(vrev64q_p16(transmute(a))); assert_eq!(r, e); } } -#[cfg(test)] -#[cfg(target_endian = "little")] +#[cfg(all(test, target_arch = "arm", target_endian = "little"))] mod table_lookup_tests; + +#[cfg(all(test, target_arch = "arm"))] +mod shift_and_insert_tests; + +#[cfg(all(test, target_arch = "arm"))] +mod load_tests; diff --git a/library/stdarch/crates/core_arch/src/arm/neon/shift_and_insert_tests.rs b/library/stdarch/crates/core_arch/src/arm/neon/shift_and_insert_tests.rs new file mode 100644 index 0000000000..a556789245 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/arm/neon/shift_and_insert_tests.rs @@ -0,0 +1,89 @@ +//! Tests for ARM+v7+neon shift and insert (vsli[q]_n, vsri[q]_n) intrinsics. +//! +//! These are included in `{arm, aarch64}::neon`. + +use super::*; + +#[cfg(target_arch = "aarch64")] +use crate::core_arch::aarch64::*; + +#[cfg(target_arch = "arm")] +use crate::core_arch::arm::*; + +use crate::core_arch::simd::*; +use std::mem::transmute; +use stdarch_test::simd_test; + +macro_rules! test_vsli { + ($test_id:ident, $t:ty => $fn_id:ident ([$($a:expr),*], [$($b:expr),*], $n:expr)) => { + #[simd_test(enable = "neon")] + #[allow(unused_assignments)] + unsafe fn $test_id() { + let a = [$($a as $t),*]; + let b = [$($b as $t),*]; + let n_bit_mask: $t = (1 << $n) - 1; + let e = [$(($a as $t & n_bit_mask) | ($b as $t << $n)),*]; + let r = $fn_id(transmute(a), transmute(b), $n); + let mut d = e; + d = transmute(r); + assert_eq!(d, e); + } + } +} +test_vsli!(test_vsli_n_s8, i8 => vsli_n_s8([3, -44, 127, -56, 0, 24, -97, 10], [-128, -14, 125, -77, 27, 8, -1, 110], 5)); +test_vsli!(test_vsliq_n_s8, i8 => vsliq_n_s8([3, -44, 127, -56, 0, 24, -97, 10, -33, 1, -6, -39, 15, 101, -80, -1], [-128, -14, 125, -77, 27, 8, -1, 110, -4, -92, 111, 32, 1, -4, -29, 99], 2)); +test_vsli!(test_vsli_n_s16, i16 => vsli_n_s16([3304, -44, 2300, -546], [-1208, -140, 1225, -707], 7)); +test_vsli!(test_vsliq_n_s16, i16 => vsliq_n_s16([3304, -44, 2300, -20046, 0, 9924, -907, 1190], [-1208, -140, 4225, -707, 2701, 804, -71, 2110], 14)); +test_vsli!(test_vsli_n_s32, i32 => vsli_n_s32([125683, -78901], [-128, -112944], 23)); +test_vsli!(test_vsliq_n_s32, i32 => vsliq_n_s32([125683, -78901, 127, -12009], [-128, -112944, 125, -707], 15)); +test_vsli!(test_vsli_n_s64, i64 => vsli_n_s64([-333333], [1028], 45)); +test_vsli!(test_vsliq_n_s64, i64 => vsliq_n_s64([-333333, -52023], [1028, -99814], 33)); +test_vsli!(test_vsli_n_u8, u8 => vsli_n_u8([3, 44, 127, 56, 0, 24, 97, 10], [127, 14, 125, 77, 27, 8, 1, 110], 5)); +test_vsli!(test_vsliq_n_u8, u8 => vsliq_n_u8([3, 44, 127, 56, 0, 24, 97, 10, 33, 1, 6, 39, 15, 101, 80, 1], [127, 14, 125, 77, 27, 8, 1, 110, 4, 92, 111, 32, 1, 4, 29, 99], 2)); +test_vsli!(test_vsli_n_u16, u16 => vsli_n_u16([3304, 44, 2300, 546], [1208, 140, 1225, 707], 7)); +test_vsli!(test_vsliq_n_u16, u16 => vsliq_n_u16([3304, 44, 2300, 20046, 0, 9924, 907, 1190], [1208, 140, 4225, 707, 2701, 804, 71, 2110], 14)); +test_vsli!(test_vsli_n_u32, u32 => vsli_n_u32([125683, 78901], [128, 112944], 23)); +test_vsli!(test_vsliq_n_u32, u32 => vsliq_n_u32([125683, 78901, 127, 12009], [128, 112944, 125, 707], 15)); +test_vsli!(test_vsli_n_u64, u64 => vsli_n_u64([333333], [1028], 45)); +test_vsli!(test_vsliq_n_u64, u64 => vsliq_n_u64([333333, 52023], [1028, 99814], 33)); +test_vsli!(test_vsli_n_p8, i8 => vsli_n_p8([3, 44, 127, 56, 0, 24, 97, 10], [127, 14, 125, 77, 27, 8, 1, 110], 5)); +test_vsli!(test_vsliq_n_p8, i8 => vsliq_n_p8([3, 44, 127, 56, 0, 24, 97, 10, 33, 1, 6, 39, 15, 101, 80, 1], [127, 14, 125, 77, 27, 8, 1, 110, 4, 92, 111, 32, 1, 4, 29, 99], 2)); +test_vsli!(test_vsli_n_p16, i16 => vsli_n_p16([3304, 44, 2300, 546], [1208, 140, 1225, 707], 7)); +test_vsli!(test_vsliq_n_p16, i16 => vsliq_n_p16([3304, 44, 2300, 20046, 0, 9924, 907, 1190], [1208, 140, 4225, 707, 2701, 804, 71, 2110], 14)); + +macro_rules! test_vsri { + ($test_id:ident, $t:ty => $fn_id:ident ([$($a:expr),*], [$($b:expr),*], $n:expr)) => { + #[simd_test(enable = "neon")] + #[allow(unused_assignments)] + unsafe fn $test_id() { + let a = [$($a as $t),*]; + let b = [$($b as $t),*]; + let n_bit_mask = ((1 as $t << $n) - 1).rotate_right($n); + let e = [$(($a as $t & n_bit_mask) | (($b as $t >> $n) & !n_bit_mask)),*]; + let r = $fn_id(transmute(a), transmute(b), $n); + let mut d = e; + d = transmute(r); + assert_eq!(d, e); + } + } +} +test_vsri!(test_vsri_n_s8, i8 => vsri_n_s8([3, -44, 127, -56, 0, 24, -97, 10], [-128, -14, 125, -77, 27, 8, -1, 110], 5)); +test_vsri!(test_vsriq_n_s8, i8 => vsriq_n_s8([3, -44, 127, -56, 0, 24, -97, 10, -33, 1, -6, -39, 15, 101, -80, -1], [-128, -14, 125, -77, 27, 8, -1, 110, -4, -92, 111, 32, 1, -4, -29, 99], 2)); +test_vsri!(test_vsri_n_s16, i16 => vsri_n_s16([3304, -44, 2300, -546], [-1208, -140, 1225, -707], 7)); +test_vsri!(test_vsriq_n_s16, i16 => vsriq_n_s16([3304, -44, 2300, -20046, 0, 9924, -907, 1190], [-1208, -140, 4225, -707, 2701, 804, -71, 2110], 14)); +test_vsri!(test_vsri_n_s32, i32 => vsri_n_s32([125683, -78901], [-128, -112944], 23)); +test_vsri!(test_vsriq_n_s32, i32 => vsriq_n_s32([125683, -78901, 127, -12009], [-128, -112944, 125, -707], 15)); +test_vsri!(test_vsri_n_s64, i64 => vsri_n_s64([-333333], [1028], 45)); +test_vsri!(test_vsriq_n_s64, i64 => vsriq_n_s64([-333333, -52023], [1028, -99814], 33)); +test_vsri!(test_vsri_n_u8, u8 => vsri_n_u8([3, 44, 127, 56, 0, 24, 97, 10], [127, 14, 125, 77, 27, 8, 1, 110], 5)); +test_vsri!(test_vsriq_n_u8, u8 => vsriq_n_u8([3, 44, 127, 56, 0, 24, 97, 10, 33, 1, 6, 39, 15, 101, 80, 1], [127, 14, 125, 77, 27, 8, 1, 110, 4, 92, 111, 32, 1, 4, 29, 99], 2)); +test_vsri!(test_vsri_n_u16, u16 => vsri_n_u16([3304, 44, 2300, 546], [1208, 140, 1225, 707], 7)); +test_vsri!(test_vsriq_n_u16, u16 => vsriq_n_u16([3304, 44, 2300, 20046, 0, 9924, 907, 1190], [1208, 140, 4225, 707, 2701, 804, 71, 2110], 14)); +test_vsri!(test_vsri_n_u32, u32 => vsri_n_u32([125683, 78901], [128, 112944], 23)); +test_vsri!(test_vsriq_n_u32, u32 => vsriq_n_u32([125683, 78901, 127, 12009], [128, 112944, 125, 707], 15)); +test_vsri!(test_vsri_n_u64, u64 => vsri_n_u64([333333], [1028], 45)); +test_vsri!(test_vsriq_n_u64, u64 => vsriq_n_u64([333333, 52023], [1028, 99814], 33)); +test_vsri!(test_vsri_n_p8, i8 => vsri_n_p8([3, 44, 127, 56, 0, 24, 97, 10], [127, 14, 125, 77, 27, 8, 1, 110], 5)); +test_vsri!(test_vsriq_n_p8, i8 => vsriq_n_p8([3, 44, 127, 56, 0, 24, 97, 10, 33, 1, 6, 39, 15, 101, 80, 1], [127, 14, 125, 77, 27, 8, 1, 110, 4, 92, 111, 32, 1, 4, 29, 99], 2)); +test_vsri!(test_vsri_n_p16, i16 => vsri_n_p16([3304, 44, 2300, 546], [1208, 140, 1225, 707], 7)); +test_vsri!(test_vsriq_n_p16, i16 => vsriq_n_p16([3304, 44, 2300, 20046, 0, 9924, 907, 1190], [1208, 140, 4225, 707, 2701, 804, 71, 2110], 14)); diff --git a/library/stdarch/crates/core_arch/src/core_arch_docs.md b/library/stdarch/crates/core_arch/src/core_arch_docs.md index 3d363ea737..96634f200f 100644 --- a/library/stdarch/crates/core_arch/src/core_arch_docs.md +++ b/library/stdarch/crates/core_arch/src/core_arch_docs.md @@ -274,7 +274,7 @@ pub fn hex_encode(src: &[u8], dst: &mut [u8]) { } // translated from -// https://github.com/Matherunner/bin2hex-sse/blob/master/base16_sse4.cpp +// #[target_feature(enable = "sse4.1")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] unsafe fn hex_encode_sse41(mut src: &[u8], dst: &mut [u8]) { diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index 5638ccc11e..2c744c2ffb 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -39,7 +39,7 @@ allow_internal_unstable, decl_macro )] -#![cfg_attr(test, feature(test, abi_vectorcall, untagged_unions))] +#![cfg_attr(test, feature(test, abi_vectorcall))] #![cfg_attr(all(test, target_arch = "wasm32"), feature(wasm_simd))] #![deny(clippy::missing_inline_in_public_items)] #![allow( diff --git a/library/stdarch/crates/core_arch/src/mod.rs b/library/stdarch/crates/core_arch/src/mod.rs index 9d7300b271..e9e9fcff5b 100644 --- a/library/stdarch/crates/core_arch/src/mod.rs +++ b/library/stdarch/crates/core_arch/src/mod.rs @@ -1,5 +1,6 @@ //! `core_arch` +#![cfg_attr(not(bootstrap), allow(automatic_links))] #[macro_use] mod macros; diff --git a/library/stdarch/crates/core_arch/src/simd.rs b/library/stdarch/crates/core_arch/src/simd.rs index 4b71d6c2bf..6108bc40de 100644 --- a/library/stdarch/crates/core_arch/src/simd.rs +++ b/library/stdarch/crates/core_arch/src/simd.rs @@ -133,6 +133,7 @@ simd_ty!(i32x2[i32]: i32, i32 | x0, x1); simd_ty!(i64x1[i64]: i64 | x1); simd_ty!(f32x2[f32]: f32, f32 | x0, x1); +simd_ty!(f64x1[f64]: f64 | x1); // 128-bit wide types: @@ -554,6 +555,398 @@ simd_ty!( // 512-bit wide types: +simd_ty!( + i8x64[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31, + x32, + x33, + x34, + x35, + x36, + x37, + x38, + x39, + x40, + x41, + x42, + x43, + x44, + x45, + x46, + x47, + x48, + x49, + x50, + x51, + x52, + x53, + x54, + x55, + x56, + x57, + x58, + x59, + x60, + x61, + x62, + x63 +); + +simd_ty!( + u8x64[u8]: u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31, + x32, + x33, + x34, + x35, + x36, + x37, + x38, + x39, + x40, + x41, + x42, + x43, + x44, + x45, + x46, + x47, + x48, + x49, + x50, + x51, + x52, + x53, + x54, + x55, + x56, + x57, + x58, + x59, + x60, + x61, + x62, + x63 +); + +simd_ty!( + i16x32[i16]: i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31 +); + +simd_ty!( + u16x32[u16]: u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31 +); + simd_ty!( i32x16[i32]: i32, i32, diff --git a/library/stdarch/crates/core_arch/src/x86/avx.rs b/library/stdarch/crates/core_arch/src/x86/avx.rs index 0b6f13fe82..6c9a03322d 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx.rs @@ -120,7 +120,7 @@ pub unsafe fn _mm256_shuffle_pd(a: __m256d, b: __m256d, imm8: i32) -> __m256d { let imm8 = (imm8 & 0xFF) as u8; macro_rules! shuffle4 { ($a:expr, $b:expr, $c:expr, $d:expr) => { - simd_shuffle4(a, b, [$a, $b, $c, $d]); + simd_shuffle4(a, b, [$a, $b, $c, $d]) }; } macro_rules! shuffle3 { @@ -175,7 +175,7 @@ pub unsafe fn _mm256_shuffle_ps(a: __m256, b: __m256, imm8: i32) -> __m256 { $g:expr, $h:expr ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) }; } macro_rules! shuffle3 { @@ -532,7 +532,7 @@ pub unsafe fn _mm256_blend_pd(a: __m256d, b: __m256d, imm8: i32) -> __m256d { let imm8 = (imm8 & 0xFF) as u8; macro_rules! blend4 { ($a:expr, $b:expr, $c:expr, $d:expr) => { - simd_shuffle4(a, b, [$a, $b, $c, $d]); + simd_shuffle4(a, b, [$a, $b, $c, $d]) }; } macro_rules! blend3 { @@ -587,7 +587,7 @@ pub unsafe fn _mm256_blend_ps(a: __m256, b: __m256, imm8: i32) -> __m256 { $g:expr, $h:expr ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) }; } macro_rules! blend3 { @@ -1186,11 +1186,12 @@ pub unsafe fn _mm_permutevar_ps(a: __m128, b: __m128i) -> __m128 { #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _mm256_permute_ps(a: __m256, imm8: i32) -> __m256 { let imm8 = (imm8 & 0xFF) as u8; + let undefined = _mm256_undefined_ps(); macro_rules! shuffle4 { ($a:expr, $b:expr, $c:expr, $d:expr) => { simd_shuffle8( a, - _mm256_undefined_ps(), + undefined, [$a, $b, $c, $d, $a + 4, $b + 4, $c + 4, $d + 4], ) }; @@ -1244,9 +1245,10 @@ pub unsafe fn _mm256_permute_ps(a: __m256, imm8: i32) -> __m256 { #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _mm_permute_ps(a: __m128, imm8: i32) -> __m128 { let imm8 = (imm8 & 0xFF) as u8; + let undefined = _mm_undefined_ps(); macro_rules! shuffle4 { ($a:expr, $b:expr, $c:expr, $d:expr) => { - simd_shuffle4(a, _mm_undefined_ps(), [$a, $b, $c, $d]) + simd_shuffle4(a, undefined, [$a, $b, $c, $d]) }; } macro_rules! shuffle3 { @@ -1322,9 +1324,10 @@ pub unsafe fn _mm_permutevar_pd(a: __m128d, b: __m128i) -> __m128d { #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _mm256_permute_pd(a: __m256d, imm8: i32) -> __m256d { let imm8 = (imm8 & 0xFF) as u8; + let undefined = _mm256_undefined_pd(); macro_rules! shuffle4 { ($a:expr, $b:expr, $c:expr, $d:expr) => { - simd_shuffle4(a, _mm256_undefined_pd(), [$a, $b, $c, $d]); + simd_shuffle4(a, undefined, [$a, $b, $c, $d]) }; } macro_rules! shuffle3 { @@ -1368,9 +1371,10 @@ pub unsafe fn _mm256_permute_pd(a: __m256d, imm8: i32) -> __m256d { #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _mm_permute_pd(a: __m128d, imm8: i32) -> __m128d { let imm8 = (imm8 & 0xFF) as u8; + let undefined = _mm_undefined_pd(); macro_rules! shuffle2 { ($a:expr, $b:expr) => { - simd_shuffle2(a, _mm_undefined_pd(), [$a, $b]); + simd_shuffle2(a, undefined, [$a, $b]) }; } macro_rules! shuffle1 { @@ -1623,7 +1627,7 @@ pub unsafe fn _mm256_insert_epi32(a: __m256i, i: i32, index: i32) -> __m256i { simd_insert(a, $index, i) }; } - transmute(constify_imm8!((index & 7), call)) + transmute(constify_imm3!(index, call)) } /// Loads 256-bits (composed of 4 packed double-precision (64-bit) diff --git a/library/stdarch/crates/core_arch/src/x86/avx2.rs b/library/stdarch/crates/core_arch/src/x86/avx2.rs index 87af536cc9..5fe898922f 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx2.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx2.rs @@ -372,7 +372,7 @@ pub unsafe fn _mm_blend_epi32(a: __m128i, b: __m128i, imm8: i32) -> __m128i { let b = b.as_i32x4(); macro_rules! blend2 { ($a:expr, $b:expr, $c:expr, $d:expr) => { - simd_shuffle4(a, b, [$a, $b, $c, $d]); + simd_shuffle4(a, b, [$a, $b, $c, $d]) }; } macro_rules! blend1 { @@ -417,7 +417,7 @@ pub unsafe fn _mm256_blend_epi32(a: __m256i, b: __m256i, imm8: i32) -> __m256i { $g:expr, $h:expr ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) }; } macro_rules! blend3 { @@ -1080,7 +1080,7 @@ pub unsafe fn _mm256_hsubs_epi16(a: __m256i, b: __m256i) -> __m256i { /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i32gather_epi32) #[inline] @@ -1098,13 +1098,13 @@ pub unsafe fn _mm_i32gather_epi32(slice: *const i32, offsets: __m128i, scale: i3 pgatherdd(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i32gather_epi32) @@ -1129,13 +1129,13 @@ pub unsafe fn _mm_mask_i32gather_epi32( pgatherdd(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i32gather_epi32) #[inline] @@ -1153,13 +1153,13 @@ pub unsafe fn _mm256_i32gather_epi32(slice: *const i32, offsets: __m256i, scale: vpgatherdd(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i32gather_epi32) @@ -1184,13 +1184,13 @@ pub unsafe fn _mm256_mask_i32gather_epi32( vpgatherdd(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i32gather_ps) #[inline] @@ -1208,12 +1208,12 @@ pub unsafe fn _mm_i32gather_ps(slice: *const f32, offsets: __m128i, scale: i32) pgatherdps(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i32gather_ps) @@ -1236,12 +1236,12 @@ pub unsafe fn _mm_mask_i32gather_ps( pgatherdps(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i32gather_ps) #[inline] @@ -1259,12 +1259,12 @@ pub unsafe fn _mm256_i32gather_ps(slice: *const f32, offsets: __m256i, scale: i3 vpgatherdps(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i32gather_ps) @@ -1287,12 +1287,12 @@ pub unsafe fn _mm256_mask_i32gather_ps( vpgatherdps(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i32gather_epi64) #[inline] @@ -1310,13 +1310,13 @@ pub unsafe fn _mm_i32gather_epi64(slice: *const i64, offsets: __m128i, scale: i3 pgatherdq(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i32gather_epi64) @@ -1341,13 +1341,13 @@ pub unsafe fn _mm_mask_i32gather_epi64( pgatherdq(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 and 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i32gather_epi64) #[inline] @@ -1365,13 +1365,13 @@ pub unsafe fn _mm256_i32gather_epi64(slice: *const i64, offsets: __m128i, scale: vpgatherdq(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i32gather_epi64) @@ -1396,13 +1396,13 @@ pub unsafe fn _mm256_mask_i32gather_epi64( vpgatherdq(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i32gather_pd) #[inline] @@ -1420,12 +1420,12 @@ pub unsafe fn _mm_i32gather_pd(slice: *const f64, offsets: __m128i, scale: i32) pgatherdpd(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i32gather_pd) @@ -1448,12 +1448,12 @@ pub unsafe fn _mm_mask_i32gather_pd( pgatherdpd(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i32gather_pd) #[inline] @@ -1471,12 +1471,12 @@ pub unsafe fn _mm256_i32gather_pd(slice: *const f64, offsets: __m128i, scale: i3 vpgatherdpd(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i32gather_pd) @@ -1499,12 +1499,12 @@ pub unsafe fn _mm256_mask_i32gather_pd( vpgatherdpd(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i64gather_epi32) #[inline] @@ -1522,13 +1522,13 @@ pub unsafe fn _mm_i64gather_epi32(slice: *const i32, offsets: __m128i, scale: i3 pgatherqd(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i64gather_epi32) @@ -1553,13 +1553,13 @@ pub unsafe fn _mm_mask_i64gather_epi32( pgatherqd(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i64gather_epi32) #[inline] @@ -1577,13 +1577,13 @@ pub unsafe fn _mm256_i64gather_epi32(slice: *const i32, offsets: __m256i, scale: vpgatherqd(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i64gather_epi32) @@ -1608,13 +1608,13 @@ pub unsafe fn _mm256_mask_i64gather_epi32( vpgatherqd(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i64gather_ps) #[inline] @@ -1632,12 +1632,12 @@ pub unsafe fn _mm_i64gather_ps(slice: *const f32, offsets: __m128i, scale: i32) pgatherqps(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i64gather_ps) @@ -1660,12 +1660,12 @@ pub unsafe fn _mm_mask_i64gather_ps( pgatherqps(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i64gather_ps) #[inline] @@ -1683,12 +1683,12 @@ pub unsafe fn _mm256_i64gather_ps(slice: *const f32, offsets: __m256i, scale: i3 vpgatherqps(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i64gather_ps) @@ -1711,12 +1711,12 @@ pub unsafe fn _mm256_mask_i64gather_ps( vpgatherqps(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i64gather_epi64) #[inline] @@ -1734,13 +1734,13 @@ pub unsafe fn _mm_i64gather_epi64(slice: *const i64, offsets: __m128i, scale: i3 pgatherqq(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i64gather_epi64) @@ -1765,13 +1765,13 @@ pub unsafe fn _mm_mask_i64gather_epi64( pgatherqq(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i64gather_epi64) #[inline] @@ -1789,13 +1789,13 @@ pub unsafe fn _mm256_i64gather_epi64(slice: *const i64, offsets: __m256i, scale: vpgatherqq(zero, slice, offsets, neg_one, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i64gather_epi64) @@ -1820,13 +1820,13 @@ pub unsafe fn _mm256_mask_i64gather_epi64( vpgatherqq(src, slice, offsets, mask, $imm8) }; } - let r = constify_imm8!(scale, call); + let r = constify_imm8_gather!(scale, call); transmute(r) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_i64gather_pd) #[inline] @@ -1844,12 +1844,12 @@ pub unsafe fn _mm_i64gather_pd(slice: *const f64, offsets: __m128i, scale: i32) pgatherqpd(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_i64gather_pd) @@ -1872,12 +1872,12 @@ pub unsafe fn _mm_mask_i64gather_pd( pgatherqpd(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. +/// `scale` should be 1, 2, 4 or 8. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_i64gather_pd) #[inline] @@ -1895,12 +1895,12 @@ pub unsafe fn _mm256_i64gather_pd(slice: *const f64, offsets: __m256i, scale: i3 vpgatherqpd(zero, slice, offsets, neg_one, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Returns values from `slice` at offsets determined by `offsets * scale`, /// where -/// `scale` is between 1 and 8. If mask is set, load the value from `src` in +/// `scale` should be 1, 2, 4 or 8. If mask is set, load the value from `src` in /// that position instead. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_i64gather_pd) @@ -1923,7 +1923,7 @@ pub unsafe fn _mm256_mask_i64gather_pd( vpgatherqpd(src, slice, offsets, mask, $imm8) }; } - constify_imm8!(scale, call) + constify_imm8_gather!(scale, call) } /// Copies `a` to `dst`, then insert 128 bits (of integer data) from `b` at the @@ -2443,7 +2443,7 @@ pub unsafe fn _mm256_permute4x64_epi64(a: __m256i, imm8: i32) -> __m256i { let a = a.as_i64x4(); macro_rules! permute4 { ($a:expr, $b:expr, $c:expr, $d:expr) => { - simd_shuffle4(a, zero, [$a, $b, $c, $d]); + simd_shuffle4(a, zero, [$a, $b, $c, $d]) }; } macro_rules! permute3 { @@ -2746,7 +2746,7 @@ pub unsafe fn _mm256_shufflehi_epi16(a: __m256i, imm8: i32) -> __m256i { simd_shuffle16(a, a, [ 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67, 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67 - ]); + ]) }; } macro_rules! shuffle_x67 { @@ -2807,7 +2807,7 @@ pub unsafe fn _mm256_shufflelo_epi16(a: __m256i, imm8: i32) -> __m256i { simd_shuffle16(a, a, [ 0+$x01, 0+$x23, 0+$x45, 0+$x67, 4, 5, 6, 7, 8+$x01, 8+$x23, 8+$x45, 8+$x67, 12, 13, 14, 15, - ]); + ]) }; } macro_rules! shuffle_x67 { @@ -3735,7 +3735,7 @@ pub unsafe fn _mm256_xor_si256(a: __m256i, b: __m256i) -> __m256i { /// Extracts an 8-bit integer from `a`, selected with `imm8`. Returns a 32-bit /// integer containing the zero-extended integer data. /// -/// See [LLVM commit D20468][https://reviews.llvm.org/D20468]. +/// See [LLVM commit D20468](https://reviews.llvm.org/D20468). /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_extract_epi8) #[inline] @@ -3756,7 +3756,7 @@ pub unsafe fn _mm256_extract_epi8(a: __m256i, imm8: i32) -> i32 { /// Extracts a 16-bit integer from `a`, selected with `imm8`. Returns a 32-bit /// integer containing the zero-extended integer data. /// -/// See [LLVM commit D20468][https://reviews.llvm.org/D20468]. +/// See [LLVM commit D20468](https://reviews.llvm.org/D20468). /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_extract_epi16) #[inline] @@ -4052,7 +4052,7 @@ extern "C" { #[cfg(test)] mod tests { - use std; + use stdarch_test::simd_test; use crate::core_arch::x86::*; diff --git a/library/stdarch/crates/core_arch/src/x86/avx512bitalg.rs b/library/stdarch/crates/core_arch/src/x86/avx512bitalg.rs new file mode 100644 index 0000000000..3c9df3912f --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/avx512bitalg.rs @@ -0,0 +1,760 @@ +//! Bit-oriented Algorithms (BITALG) +//! +//! The intrinsics here correspond to those in the `immintrin.h` C header. +//! +//! The reference is [Intel 64 and IA-32 Architectures Software Developer's +//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref]. +//! +//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + +use crate::core_arch::simd::i16x16; +use crate::core_arch::simd::i16x32; +use crate::core_arch::simd::i16x8; +use crate::core_arch::simd::i8x16; +use crate::core_arch::simd::i8x32; +use crate::core_arch::simd::i8x64; +use crate::core_arch::simd_llvm::simd_select_bitmask; +use crate::core_arch::x86::__m128i; +use crate::core_arch::x86::__m256i; +use crate::core_arch::x86::__m512i; +use crate::core_arch::x86::__mmask16; +use crate::core_arch::x86::__mmask32; +use crate::core_arch::x86::__mmask64; +use crate::core_arch::x86::__mmask8; +use crate::core_arch::x86::_mm256_setzero_si256; +use crate::core_arch::x86::_mm512_setzero_si512; +use crate::core_arch::x86::_mm_setzero_si128; +use crate::core_arch::x86::m128iExt; +use crate::core_arch::x86::m256iExt; +use crate::core_arch::x86::m512iExt; +use crate::mem::transmute; + +#[cfg(test)] +use stdarch_test::assert_instr; + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.ctpop.v32i16"] + fn popcnt_v32i16(x: i16x32) -> i16x32; + #[link_name = "llvm.ctpop.v16i16"] + fn popcnt_v16i16(x: i16x16) -> i16x16; + #[link_name = "llvm.ctpop.v8i16"] + fn popcnt_v8i16(x: i16x8) -> i16x8; + + #[link_name = "llvm.ctpop.v64i8"] + fn popcnt_v64i8(x: i8x64) -> i8x64; + #[link_name = "llvm.ctpop.v32i8"] + fn popcnt_v32i8(x: i8x32) -> i8x32; + #[link_name = "llvm.ctpop.v16i8"] + fn popcnt_v16i8(x: i8x16) -> i8x16; + + #[link_name = "llvm.x86.avx512.mask.vpshufbitqmb.512"] + fn bitshuffle_512(data: i8x64, indices: i8x64, mask: __mmask64) -> __mmask64; + #[link_name = "llvm.x86.avx512.mask.vpshufbitqmb.256"] + fn bitshuffle_256(data: i8x32, indices: i8x32, mask: __mmask32) -> __mmask32; + #[link_name = "llvm.x86.avx512.mask.vpshufbitqmb.128"] + fn bitshuffle_128(data: i8x16, indices: i8x16, mask: __mmask16) -> __mmask16; +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm512_popcnt_epi16(a: __m512i) -> __m512i { + transmute(popcnt_v32i16(a.as_i16x32())) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm512_maskz_popcnt_epi16(k: __mmask32, a: __m512i) -> __m512i { + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, popcnt_v32i16(a.as_i16x32()), zero)) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm512_mask_popcnt_epi16(src: __m512i, k: __mmask32, a: __m512i) -> __m512i { + transmute(simd_select_bitmask( + k, + popcnt_v32i16(a.as_i16x32()), + src.as_i16x32(), + )) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm256_popcnt_epi16(a: __m256i) -> __m256i { + transmute(popcnt_v16i16(a.as_i16x16())) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm256_maskz_popcnt_epi16(k: __mmask16, a: __m256i) -> __m256i { + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, popcnt_v16i16(a.as_i16x16()), zero)) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm256_mask_popcnt_epi16(src: __m256i, k: __mmask16, a: __m256i) -> __m256i { + transmute(simd_select_bitmask( + k, + popcnt_v16i16(a.as_i16x16()), + src.as_i16x16(), + )) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm_popcnt_epi16(a: __m128i) -> __m128i { + transmute(popcnt_v8i16(a.as_i16x8())) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm_maskz_popcnt_epi16(k: __mmask8, a: __m128i) -> __m128i { + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, popcnt_v8i16(a.as_i16x8()), zero)) +} + +/// For each packed 16-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_popcnt_epi16) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntw))] +pub unsafe fn _mm_mask_popcnt_epi16(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + transmute(simd_select_bitmask( + k, + popcnt_v8i16(a.as_i16x8()), + src.as_i16x8(), + )) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm512_popcnt_epi8(a: __m512i) -> __m512i { + transmute(popcnt_v64i8(a.as_i8x64())) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm512_maskz_popcnt_epi8(k: __mmask64, a: __m512i) -> __m512i { + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, popcnt_v64i8(a.as_i8x64()), zero)) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm512_mask_popcnt_epi8(src: __m512i, k: __mmask64, a: __m512i) -> __m512i { + transmute(simd_select_bitmask( + k, + popcnt_v64i8(a.as_i8x64()), + src.as_i8x64(), + )) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm256_popcnt_epi8(a: __m256i) -> __m256i { + transmute(popcnt_v32i8(a.as_i8x32())) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm256_maskz_popcnt_epi8(k: __mmask32, a: __m256i) -> __m256i { + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, popcnt_v32i8(a.as_i8x32()), zero)) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm256_mask_popcnt_epi8(src: __m256i, k: __mmask32, a: __m256i) -> __m256i { + transmute(simd_select_bitmask( + k, + popcnt_v32i8(a.as_i8x32()), + src.as_i8x32(), + )) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm_popcnt_epi8(a: __m128i) -> __m128i { + transmute(popcnt_v16i8(a.as_i8x16())) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm_maskz_popcnt_epi8(k: __mmask16, a: __m128i) -> __m128i { + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, popcnt_v16i8(a.as_i8x16()), zero)) +} + +/// For each packed 8-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_popcnt_epi8) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntb))] +pub unsafe fn _mm_mask_popcnt_epi8(src: __m128i, k: __mmask16, a: __m128i) -> __m128i { + transmute(simd_select_bitmask( + k, + popcnt_v16i8(a.as_i8x16()), + src.as_i8x16(), + )) +} + +/// Considers the input `b` as packed 64-bit integers and `c` as packed 8-bit integers. +/// Then groups 8 8-bit values from `c`as indices into the the bits of the corresponding 64-bit integer. +/// It then selects these bits and packs them into the output. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_bitshuffle_epi64_mask) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpshufbitqmb))] +pub unsafe fn _mm512_bitshuffle_epi64_mask(b: __m512i, c: __m512i) -> __mmask64 { + transmute(bitshuffle_512(b.as_i8x64(), c.as_i8x64(), !0)) +} + +/// Considers the input `b` as packed 64-bit integers and `c` as packed 8-bit integers. +/// Then groups 8 8-bit values from `c`as indices into the the bits of the corresponding 64-bit integer. +/// It then selects these bits and packs them into the output. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_bitshuffle_epi64_mask) +#[inline] +#[target_feature(enable = "avx512bitalg")] +#[cfg_attr(test, assert_instr(vpshufbitqmb))] +pub unsafe fn _mm512_mask_bitshuffle_epi64_mask(k: __mmask64, b: __m512i, c: __m512i) -> __mmask64 { + transmute(bitshuffle_512(b.as_i8x64(), c.as_i8x64(), k)) +} + +/// Considers the input `b` as packed 64-bit integers and `c` as packed 8-bit integers. +/// Then groups 8 8-bit values from `c`as indices into the the bits of the corresponding 64-bit integer. +/// It then selects these bits and packs them into the output. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_bitshuffle_epi64_mask) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpshufbitqmb))] +pub unsafe fn _mm256_bitshuffle_epi64_mask(b: __m256i, c: __m256i) -> __mmask32 { + transmute(bitshuffle_256(b.as_i8x32(), c.as_i8x32(), !0)) +} + +/// Considers the input `b` as packed 64-bit integers and `c` as packed 8-bit integers. +/// Then groups 8 8-bit values from `c`as indices into the the bits of the corresponding 64-bit integer. +/// It then selects these bits and packs them into the output. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_bitshuffle_epi64_mask) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpshufbitqmb))] +pub unsafe fn _mm256_mask_bitshuffle_epi64_mask(k: __mmask32, b: __m256i, c: __m256i) -> __mmask32 { + transmute(bitshuffle_256(b.as_i8x32(), c.as_i8x32(), k)) +} + +/// Considers the input `b` as packed 64-bit integers and `c` as packed 8-bit integers. +/// Then groups 8 8-bit values from `c`as indices into the the bits of the corresponding 64-bit integer. +/// It then selects these bits and packs them into the output. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bitshuffle_epi64_mask) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpshufbitqmb))] +pub unsafe fn _mm_bitshuffle_epi64_mask(b: __m128i, c: __m128i) -> __mmask16 { + transmute(bitshuffle_128(b.as_i8x16(), c.as_i8x16(), !0)) +} + +/// Considers the input `b` as packed 64-bit integers and `c` as packed 8-bit integers. +/// Then groups 8 8-bit values from `c`as indices into the the bits of the corresponding 64-bit integer. +/// It then selects these bits and packs them into the output. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_bitshuffle_epi64_mask) +#[inline] +#[target_feature(enable = "avx512bitalg,avx512vl")] +#[cfg_attr(test, assert_instr(vpshufbitqmb))] +pub unsafe fn _mm_mask_bitshuffle_epi64_mask(k: __mmask16, b: __m128i, c: __m128i) -> __mmask16 { + transmute(bitshuffle_128(b.as_i8x16(), c.as_i8x16(), k)) +} + +#[cfg(test)] +mod tests { + // Some of the constants in the tests below are just bit patterns. They should not + // be interpreted as integers; signedness does not make sense for them, but + // __mXXXi happens to be defined in terms of signed integers. + #![allow(overflowing_literals)] + + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_popcnt_epi16() { + let test_data = _mm512_set_epi16( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1_FF, 0x3_FF, 0x7_FF, 0xF_FF, 0x1F_FF, + 0x3F_FF, 0x7F_FF, 0xFF_FF, -1, -100, 255, 256, 2, 4, 8, 16, 32, 64, 128, 256, 512, + 1024, 2048, + ); + let actual_result = _mm512_popcnt_epi16(test_data); + let reference_result = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 12, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, + ); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_maskz_popcnt_epi16() { + let test_data = _mm512_set_epi16( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1_FF, 0x3_FF, 0x7_FF, 0xF_FF, 0x1F_FF, + 0x3F_FF, 0x7F_FF, 0xFF_FF, -1, -100, 255, 256, 2, 4, 8, 16, 32, 64, 128, 256, 512, + 1024, 2048, + ); + let mask = 0xFF_FF_00_00; + let actual_result = _mm512_maskz_popcnt_epi16(mask, test_data); + let reference_result = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + ); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_mask_popcnt_epi16() { + let test_data = _mm512_set_epi16( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1_FF, 0x3_FF, 0x7_FF, 0xF_FF, 0x1F_FF, + 0x3F_FF, 0x7F_FF, 0xFF_FF, -1, -100, 255, 256, 2, 4, 8, 16, 32, 64, 128, 256, 512, + 1024, 2048, + ); + let mask = 0xFF_FF_00_00; + let actual_result = _mm512_mask_popcnt_epi16(test_data, mask, test_data); + let reference_result = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xFF_FF, -1, -100, 255, 256, 2, + 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, + ); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_popcnt_epi16() { + let test_data = _mm256_set_epi16( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1_FF, 0x3_FF, 0x7_FF, 0xF_FF, 0x1F_FF, + 0x3F_FF, 0x7F_FF, + ); + let actual_result = _mm256_popcnt_epi16(test_data); + let reference_result = + _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_maskz_popcnt_epi16() { + let test_data = _mm256_set_epi16( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1_FF, 0x3_FF, 0x7_FF, 0xF_FF, 0x1F_FF, + 0x3F_FF, 0x7F_FF, + ); + let mask = 0xFF_00; + let actual_result = _mm256_maskz_popcnt_epi16(mask, test_data); + let reference_result = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_mask_popcnt_epi16() { + let test_data = _mm256_set_epi16( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1_FF, 0x3_FF, 0x7_FF, 0xF_FF, 0x1F_FF, + 0x3F_FF, 0x7F_FF, + ); + let mask = 0xFF_00; + let actual_result = _mm256_mask_popcnt_epi16(test_data, mask, test_data); + let reference_result = _mm256_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 0xFF, 0x1_FF, 0x3_FF, 0x7_FF, 0xF_FF, 0x1F_FF, 0x3F_FF, 0x7F_FF, + ); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_popcnt_epi16() { + let test_data = _mm_set_epi16(0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F); + let actual_result = _mm_popcnt_epi16(test_data); + let reference_result = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_maskz_popcnt_epi16() { + let test_data = _mm_set_epi16(0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F); + let mask = 0xF0; + let actual_result = _mm_maskz_popcnt_epi16(mask, test_data); + let reference_result = _mm_set_epi16(0, 1, 2, 3, 0, 0, 0, 0); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_mask_popcnt_epi16() { + let test_data = _mm_set_epi16(0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F); + let mask = 0xF0; + let actual_result = _mm_mask_popcnt_epi16(test_data, mask, test_data); + let reference_result = _mm_set_epi16(0, 1, 2, 3, 0xF, 0x1F, 0x3F, 0x7F); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_popcnt_epi8() { + let test_data = _mm512_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, -1, 2, 4, 8, 16, 32, 64, 128, 171, 206, 100, + 217, 109, 253, 190, 177, 254, 179, 215, 230, 68, 201, 172, 183, 154, 84, 56, 227, 189, + 140, 35, 117, 219, 169, 226, 170, 13, 22, 159, 251, 73, 121, 143, 145, 85, 91, 137, 90, + 225, 21, 249, 211, 155, 228, 70, + ); + let actual_result = _mm512_popcnt_epi8(test_data); + let reference_result = _mm512_set_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 1, 1, 1, 1, 1, 1, 1, 5, 5, 3, 5, 5, 7, 6, 4, 7, 5, 6, 5, + 2, 4, 4, 6, 4, 3, 3, 5, 6, 3, 3, 5, 6, 4, 4, 4, 3, 3, 6, 7, 3, 5, 5, 3, 4, 5, 3, 4, 4, + 3, 6, 5, 5, 4, 3, + ); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_maskz_popcnt_epi8() { + let test_data = _mm512_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, -1, 2, 4, 8, 16, 32, 64, 128, 171, 206, 100, + 217, 109, 253, 190, 177, 254, 179, 215, 230, 68, 201, 172, 183, 154, 84, 56, 227, 189, + 140, 35, 117, 219, 169, 226, 170, 13, 22, 159, 251, 73, 121, 143, 145, 85, 91, 137, 90, + 225, 21, 249, 211, 155, 228, 70, + ); + let mask = 0xFF_FF_FF_FF_00_00_00_00; + let actual_result = _mm512_maskz_popcnt_epi8(mask, test_data); + let reference_result = _mm512_set_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 1, 1, 1, 1, 1, 1, 1, 5, 5, 3, 5, 5, 7, 6, 4, 7, 5, 6, 5, + 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_mask_popcnt_epi8() { + let test_data = _mm512_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, -1, 2, 4, 8, 16, 32, 64, 128, 171, 206, 100, + 217, 109, 253, 190, 177, 254, 179, 215, 230, 68, 201, 172, 183, 154, 84, 56, 227, 189, + 140, 35, 117, 219, 169, 226, 170, 13, 22, 159, 251, 73, 121, 143, 145, 85, 91, 137, 90, + 225, 21, 249, 211, 155, 228, 70, + ); + let mask = 0xFF_FF_FF_FF_00_00_00_00; + let actual_result = _mm512_mask_popcnt_epi8(test_data, mask, test_data); + let reference_result = _mm512_set_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 1, 1, 1, 1, 1, 1, 1, 5, 5, 3, 5, 5, 7, 6, 4, 7, 5, 6, 5, + 2, 4, 4, 183, 154, 84, 56, 227, 189, 140, 35, 117, 219, 169, 226, 170, 13, 22, 159, + 251, 73, 121, 143, 145, 85, 91, 137, 90, 225, 21, 249, 211, 155, 228, 70, + ); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_popcnt_epi8() { + let test_data = _mm256_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, -1, 2, 4, 8, 16, 32, 64, 128, 171, 206, 100, + 217, 109, 253, 190, 177, 254, 179, 215, 230, 68, 201, 172, + ); + let actual_result = _mm256_popcnt_epi8(test_data); + let reference_result = _mm256_set_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 1, 1, 1, 1, 1, 1, 1, 5, 5, 3, 5, 5, 7, 6, 4, 7, 5, 6, 5, + 2, 4, 4, + ); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_maskz_popcnt_epi8() { + let test_data = _mm256_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, -1, 2, 4, 8, 16, 32, 64, 251, 73, 121, 143, + 145, 85, 91, 137, 90, 225, 21, 249, 211, 155, 228, 70, + ); + let mask = 0xFF_FF_00_00; + let actual_result = _mm256_maskz_popcnt_epi8(mask, test_data); + let reference_result = _mm256_set_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_mask_popcnt_epi8() { + let test_data = _mm256_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, -1, 2, 4, 8, 16, 32, 64, 251, 73, 121, 143, + 145, 85, 91, 137, 90, 225, 21, 249, 211, 155, 228, 70, + ); + let mask = 0xFF_FF_00_00; + let actual_result = _mm256_mask_popcnt_epi8(test_data, mask, test_data); + let reference_result = _mm256_set_epi8( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 1, 1, 1, 1, 1, 1, 251, 73, 121, 143, 145, 85, 91, 137, + 90, 225, 21, 249, 211, 155, 228, 70, + ); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_popcnt_epi8() { + let test_data = _mm_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, -1, 2, 4, 8, 16, 32, 64, + ); + let actual_result = _mm_popcnt_epi8(test_data); + let reference_result = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 1, 1, 1, 1, 1, 1); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_maskz_popcnt_epi8() { + let test_data = _mm_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 90, 225, 21, 249, 211, 155, 228, 70, + ); + let mask = 0xFF_00; + let actual_result = _mm_maskz_popcnt_epi8(mask, test_data); + let reference_result = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_mask_popcnt_epi8() { + let test_data = _mm_set_epi8( + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 90, 225, 21, 249, 211, 155, 228, 70, + ); + let mask = 0xFF_00; + let actual_result = _mm_mask_popcnt_epi8(test_data, mask, test_data); + let reference_result = + _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 90, 225, 21, 249, 211, 155, 228, 70); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_bitshuffle_epi64_mask() { + let test_indices = _mm512_set_epi8( + 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, 58, 57, 56, 32, 32, 16, 16, 0, 0, + 8, 8, 56, 48, 40, 32, 24, 16, 8, 0, 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, + 58, 57, 56, 32, 32, 16, 16, 0, 0, 8, 8, 56, 48, 40, 32, 24, 16, 8, 0, + ); + let test_data = _mm512_setr_epi64( + 0xFF_FF_FF_FF_00_00_00_00, + 0xFF_00_FF_00_FF_00_FF_00, + 0xFF_00_00_00_00_00_00_00, + 0xAC_00_00_00_00_00_00_00, + 0xFF_FF_FF_FF_00_00_00_00, + 0xFF_00_FF_00_FF_00_FF_00, + 0xFF_00_00_00_00_00_00_00, + 0xAC_00_00_00_00_00_00_00, + ); + let actual_result = _mm512_bitshuffle_epi64_mask(test_data, test_indices); + let reference_result = 0xF0 << 0 + | 0x03 << 8 + | 0xFF << 16 + | 0xAC << 24 + | 0xF0 << 32 + | 0x03 << 40 + | 0xFF << 48 + | 0xAC << 56; + + assert_eq!(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f")] + unsafe fn test_mm512_mask_bitshuffle_epi64_mask() { + let test_indices = _mm512_set_epi8( + 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, 58, 57, 56, 32, 32, 16, 16, 0, 0, + 8, 8, 56, 48, 40, 32, 24, 16, 8, 0, 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, + 58, 57, 56, 32, 32, 16, 16, 0, 0, 8, 8, 56, 48, 40, 32, 24, 16, 8, 0, + ); + let test_data = _mm512_setr_epi64( + 0xFF_FF_FF_FF_00_00_00_00, + 0xFF_00_FF_00_FF_00_FF_00, + 0xFF_00_00_00_00_00_00_00, + 0xAC_00_00_00_00_00_00_00, + 0xFF_FF_FF_FF_00_00_00_00, + 0xFF_00_FF_00_FF_00_FF_00, + 0xFF_00_00_00_00_00_00_00, + 0xAC_00_00_00_00_00_00_00, + ); + let mask = 0xFF_FF_FF_FF_00_00_00_00; + let actual_result = _mm512_mask_bitshuffle_epi64_mask(mask, test_data, test_indices); + let reference_result = 0x00 << 0 + | 0x00 << 8 + | 0x00 << 16 + | 0x00 << 24 + | 0xF0 << 32 + | 0x03 << 40 + | 0xFF << 48 + | 0xAC << 56; + + assert_eq!(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_bitshuffle_epi64_mask() { + let test_indices = _mm256_set_epi8( + 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, 58, 57, 56, 32, 32, 16, 16, 0, 0, + 8, 8, 56, 48, 40, 32, 24, 16, 8, 0, + ); + let test_data = _mm256_setr_epi64x( + 0xFF_FF_FF_FF_00_00_00_00, + 0xFF_00_FF_00_FF_00_FF_00, + 0xFF_00_00_00_00_00_00_00, + 0xAC_00_00_00_00_00_00_00, + ); + let actual_result = _mm256_bitshuffle_epi64_mask(test_data, test_indices); + let reference_result = 0xF0 << 0 | 0x03 << 8 | 0xFF << 16 | 0xAC << 24; + + assert_eq!(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm256_mask_bitshuffle_epi64_mask() { + let test_indices = _mm256_set_epi8( + 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, 58, 57, 56, 32, 32, 16, 16, 0, 0, + 8, 8, 56, 48, 40, 32, 24, 16, 8, 0, + ); + let test_data = _mm256_setr_epi64x( + 0xFF_FF_FF_FF_00_00_00_00, + 0xFF_00_FF_00_FF_00_FF_00, + 0xFF_00_00_00_00_00_00_00, + 0xAC_00_00_00_00_00_00_00, + ); + let mask = 0xFF_FF_00_00; + let actual_result = _mm256_mask_bitshuffle_epi64_mask(mask, test_data, test_indices); + let reference_result = 0x00 << 0 | 0x00 << 8 | 0xFF << 16 | 0xAC << 24; + + assert_eq!(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_bitshuffle_epi64_mask() { + let test_indices = _mm_set_epi8( + 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, 58, 57, 56, + ); + let test_data = _mm_setr_epi64x(0xFF_00_00_00_00_00_00_00, 0xAC_00_00_00_00_00_00_00); + let actual_result = _mm_bitshuffle_epi64_mask(test_data, test_indices); + let reference_result = 0xFF << 0 | 0xAC << 8; + + assert_eq!(actual_result, reference_result); + } + + #[simd_test(enable = "avx512bitalg,avx512f,avx512vl")] + unsafe fn test_mm_mask_bitshuffle_epi64_mask() { + let test_indices = _mm_set_epi8( + 63, 62, 61, 60, 59, 58, 57, 56, 63, 62, 61, 60, 59, 58, 57, 56, + ); + let test_data = _mm_setr_epi64x(0xFF_00_00_00_00_00_00_00, 0xAC_00_00_00_00_00_00_00); + let mask = 0xFF_00; + let actual_result = _mm_mask_bitshuffle_epi64_mask(mask, test_data, test_indices); + let reference_result = 0x00 << 0 | 0xAC << 8; + + assert_eq!(actual_result, reference_result); + } +} diff --git a/library/stdarch/crates/core_arch/src/x86/avx512bw.rs b/library/stdarch/crates/core_arch/src/x86/avx512bw.rs new file mode 100644 index 0000000000..8530fc7cbe --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/avx512bw.rs @@ -0,0 +1,13881 @@ +use crate::{ + core_arch::{simd::*, simd_llvm::*, x86::*}, + mem::{self, transmute}, + ptr, +}; + +#[cfg(test)] +use stdarch_test::assert_instr; + +/// Compute the absolute value of packed signed 16-bit integers in a, and store the unsigned results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_epi16&expand=30) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpabsw))] +pub unsafe fn _mm512_abs_epi16(a: __m512i) -> __m512i { + let a = a.as_i16x32(); + // all-0 is a properly initialized i16x32 + let zero: i16x32 = mem::zeroed(); + let sub = simd_sub(zero, a); + let cmp: i16x32 = simd_gt(a, zero); + transmute(simd_select(cmp, a, sub)) +} + +/// Compute the absolute value of packed signed 16-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_epi16&expand=31) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpabsw))] +pub unsafe fn _mm512_mask_abs_epi16(src: __m512i, k: __mmask32, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi16(a).as_i16x32(); + transmute(simd_select_bitmask(k, abs, src.as_i16x32())) +} + +/// Compute the absolute value of packed signed 16-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_abs_epi16&expand=32) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpabsw))] +pub unsafe fn _mm512_maskz_abs_epi16(k: __mmask32, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi16(a).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, abs, zero)) +} + +/// Compute the absolute value of packed signed 16-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_abs_epi16&expand=28) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsw))] +pub unsafe fn _mm256_mask_abs_epi16(src: __m256i, k: __mmask16, a: __m256i) -> __m256i { + let abs = _mm256_abs_epi16(a).as_i16x16(); + transmute(simd_select_bitmask(k, abs, src.as_i16x16())) +} + +/// Compute the absolute value of packed signed 16-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_abs_epi16&expand=29) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsw))] +pub unsafe fn _mm256_maskz_abs_epi16(k: __mmask16, a: __m256i) -> __m256i { + let abs = _mm256_abs_epi16(a).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, abs, zero)) +} + +/// Compute the absolute value of packed signed 16-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_abs_epi16&expand=25) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsw))] +pub unsafe fn _mm_mask_abs_epi16(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + let abs = _mm_abs_epi16(a).as_i16x8(); + transmute(simd_select_bitmask(k, abs, src.as_i16x8())) +} + +/// Compute the absolute value of packed signed 16-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_abs_epi16&expand=26) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsw))] +pub unsafe fn _mm_maskz_abs_epi16(k: __mmask8, a: __m128i) -> __m128i { + let abs = _mm_abs_epi16(a).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, abs, zero)) +} + +/// Compute the absolute value of packed signed 8-bit integers in a, and store the unsigned results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_epi8&expand=57) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpabsb))] +pub unsafe fn _mm512_abs_epi8(a: __m512i) -> __m512i { + let a = a.as_i8x64(); + // all-0 is a properly initialized i8x64 + let zero: i8x64 = mem::zeroed(); + let sub = simd_sub(zero, a); + let cmp: i8x64 = simd_gt(a, zero); + transmute(simd_select(cmp, a, sub)) +} + +/// Compute the absolute value of packed signed 8-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_epi8&expand=58) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpabsb))] +pub unsafe fn _mm512_mask_abs_epi8(src: __m512i, k: __mmask64, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi8(a).as_i8x64(); + transmute(simd_select_bitmask(k, abs, src.as_i8x64())) +} + +/// Compute the absolute value of packed signed 8-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_abs_epi8&expand=59) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpabsb))] +pub unsafe fn _mm512_maskz_abs_epi8(k: __mmask64, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi8(a).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, abs, zero)) +} + +/// Compute the absolute value of packed signed 8-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_abs_epi8&expand=55) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsb))] +pub unsafe fn _mm256_mask_abs_epi8(src: __m256i, k: __mmask32, a: __m256i) -> __m256i { + let abs = _mm256_abs_epi8(a).as_i8x32(); + transmute(simd_select_bitmask(k, abs, src.as_i8x32())) +} + +/// Compute the absolute value of packed signed 8-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_abs_epi8&expand=56) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsb))] +pub unsafe fn _mm256_maskz_abs_epi8(k: __mmask32, a: __m256i) -> __m256i { + let abs = _mm256_abs_epi8(a).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, abs, zero)) +} + +/// Compute the absolute value of packed signed 8-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set) +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_abs_epi8&expand=52) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsb))] +pub unsafe fn _mm_mask_abs_epi8(src: __m128i, k: __mmask16, a: __m128i) -> __m128i { + let abs = _mm_abs_epi8(a).as_i8x16(); + transmute(simd_select_bitmask(k, abs, src.as_i8x16())) +} + +/// Compute the absolute value of packed signed 8-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_abs_epi8&expand=53) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpabsb))] +pub unsafe fn _mm_maskz_abs_epi8(k: __mmask16, a: __m128i) -> __m128i { + let abs = _mm_abs_epi8(a).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, abs, zero)) +} + +/// Add packed 16-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_epi16&expand=91) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddw))] +pub unsafe fn _mm512_add_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_add(a.as_i16x32(), b.as_i16x32())) +} + +/// Add packed 16-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_epi16&expand=92) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddw))] +pub unsafe fn _mm512_mask_add_epi16(src: __m512i, k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, add, src.as_i16x32())) +} + +/// Add packed 16-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_epi16&expand=93) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddw))] +pub unsafe fn _mm512_maskz_add_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed 16-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_add_epi&expand=89) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddw))] +pub unsafe fn _mm256_mask_add_epi16(src: __m256i, k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let add = _mm256_add_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, add, src.as_i16x16())) +} + +/// Add packed 16-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_add_epi16&expand=90) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddw))] +pub unsafe fn _mm256_maskz_add_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let add = _mm256_add_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed 16-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_epi16&expand=86) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddw))] +pub unsafe fn _mm_mask_add_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let add = _mm_add_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, add, src.as_i16x8())) +} + +/// Add packed 16-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_epi16&expand=87) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddw))] +pub unsafe fn _mm_maskz_add_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let add = _mm_add_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed 8-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_epi8&expand=118) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddb))] +pub unsafe fn _mm512_add_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_add(a.as_i8x64(), b.as_i8x64())) +} + +/// Add packed 8-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_epi8&expand=119) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddb))] +pub unsafe fn _mm512_mask_add_epi8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi8(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, add, src.as_i8x64())) +} + +/// Add packed 8-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_epi8&expand=120) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddb))] +pub unsafe fn _mm512_maskz_add_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi8(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed 8-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_add_epi8&expand=116) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddb))] +pub unsafe fn _mm256_mask_add_epi8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let add = _mm256_add_epi8(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, add, src.as_i8x32())) +} + +/// Add packed 8-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_add_epi8&expand=117) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddb))] +pub unsafe fn _mm256_maskz_add_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let add = _mm256_add_epi8(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed 8-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_epi8&expand=113) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddb))] +pub unsafe fn _mm_mask_add_epi8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let add = _mm_add_epi8(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, add, src.as_i8x16())) +} + +/// Add packed 8-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_epi8&expand=114) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddb))] +pub unsafe fn _mm_maskz_add_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let add = _mm_add_epi8(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed unsigned 16-bit integers in a and b using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_adds_epu16&expand=197) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddusw))] +pub unsafe fn _mm512_adds_epu16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddusw( + a.as_u16x32(), + b.as_u16x32(), + _mm512_setzero_si512().as_u16x32(), + 0b11111111_11111111_11111111_11111111, + )) +} + +/// Add packed unsigned 16-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_adds_epu16&expand=198) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddusw))] +pub unsafe fn _mm512_mask_adds_epu16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + transmute(vpaddusw(a.as_u16x32(), b.as_u16x32(), src.as_u16x32(), k)) +} + +/// Add packed unsigned 16-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_adds_epu16&expand=199) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddusw))] +pub unsafe fn _mm512_maskz_adds_epu16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddusw( + a.as_u16x32(), + b.as_u16x32(), + _mm512_setzero_si512().as_u16x32(), + k, + )) +} + +/// Add packed unsigned 16-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_adds_epu16&expand=195) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusw))] +pub unsafe fn _mm256_mask_adds_epu16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + transmute(vpaddusw256( + a.as_u16x16(), + b.as_u16x16(), + src.as_u16x16(), + k, + )) +} + +/// Add packed unsigned 16-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_adds_epu16&expand=196) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusw))] +pub unsafe fn _mm256_maskz_adds_epu16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + transmute(vpaddusw256( + a.as_u16x16(), + b.as_u16x16(), + _mm256_setzero_si256().as_u16x16(), + k, + )) +} + +/// Add packed unsigned 16-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_adds_epu16&expand=192) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusw))] +pub unsafe fn _mm_mask_adds_epu16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddusw128(a.as_u16x8(), b.as_u16x8(), src.as_u16x8(), k)) +} + +/// Add packed unsigned 16-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_adds_epu16&expand=193) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusw))] +pub unsafe fn _mm_maskz_adds_epu16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddusw128( + a.as_u16x8(), + b.as_u16x8(), + _mm_setzero_si128().as_u16x8(), + k, + )) +} + +/// Add packed unsigned 8-bit integers in a and b using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_adds_epu8&expand=206) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddusb))] +pub unsafe fn _mm512_adds_epu8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddusb( + a.as_u8x64(), + b.as_u8x64(), + _mm512_setzero_si512().as_u8x64(), + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + )) +} + +/// Add packed unsigned 8-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_adds_epu8&expand=207) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddusb))] +pub unsafe fn _mm512_mask_adds_epu8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddusb(a.as_u8x64(), b.as_u8x64(), src.as_u8x64(), k)) +} + +/// Add packed unsigned 8-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_adds_epu8&expand=208) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddusb))] +pub unsafe fn _mm512_maskz_adds_epu8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddusb( + a.as_u8x64(), + b.as_u8x64(), + _mm512_setzero_si512().as_u8x64(), + k, + )) +} + +/// Add packed unsigned 8-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_adds_epu8&expand=204) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusb))] +pub unsafe fn _mm256_mask_adds_epu8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpaddusb256(a.as_u8x32(), b.as_u8x32(), src.as_u8x32(), k)) +} + +/// Add packed unsigned 8-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_adds_epu8&expand=205) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusb))] +pub unsafe fn _mm256_maskz_adds_epu8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpaddusb256( + a.as_u8x32(), + b.as_u8x32(), + _mm256_setzero_si256().as_u8x32(), + k, + )) +} + +/// Add packed unsigned 8-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_adds_epu8&expand=201) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusb))] +pub unsafe fn _mm_mask_adds_epu8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddusb128(a.as_u8x16(), b.as_u8x16(), src.as_u8x16(), k)) +} + +/// Add packed unsigned 8-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_adds_epu8&expand=202) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddusb))] +pub unsafe fn _mm_maskz_adds_epu8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddusb128( + a.as_u8x16(), + b.as_u8x16(), + _mm_setzero_si128().as_u8x16(), + k, + )) +} + +/// Add packed signed 16-bit integers in a and b using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_adds_epi16&expand=179) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddsw))] +pub unsafe fn _mm512_adds_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddsw( + a.as_i16x32(), + b.as_i16x32(), + _mm512_setzero_si512().as_i16x32(), + 0b11111111_11111111_11111111_11111111, + )) +} + +/// Add packed signed 16-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_adds_epi16&expand=180) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddsw))] +pub unsafe fn _mm512_mask_adds_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + transmute(vpaddsw(a.as_i16x32(), b.as_i16x32(), src.as_i16x32(), k)) +} + +/// Add packed signed 16-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_adds_epi16&expand=181) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddsw))] +pub unsafe fn _mm512_maskz_adds_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddsw( + a.as_i16x32(), + b.as_i16x32(), + _mm512_setzero_si512().as_i16x32(), + k, + )) +} + +/// Add packed signed 16-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_adds_epi16&expand=177) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsw))] +pub unsafe fn _mm256_mask_adds_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + transmute(vpaddsw256(a.as_i16x16(), b.as_i16x16(), src.as_i16x16(), k)) +} + +/// Add packed signed 16-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_adds_epi16&expand=178) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsw))] +pub unsafe fn _mm256_maskz_adds_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + transmute(vpaddsw256( + a.as_i16x16(), + b.as_i16x16(), + _mm256_setzero_si256().as_i16x16(), + k, + )) +} + +/// Add packed signed 16-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_adds_epi16&expand=174) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsw))] +pub unsafe fn _mm_mask_adds_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddsw128(a.as_i16x8(), b.as_i16x8(), src.as_i16x8(), k)) +} + +/// Add packed signed 16-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_adds_epi16&expand=175) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsw))] +pub unsafe fn _mm_maskz_adds_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddsw128( + a.as_i16x8(), + b.as_i16x8(), + _mm_setzero_si128().as_i16x8(), + k, + )) +} + +/// Add packed signed 8-bit integers in a and b using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_adds_epi8&expand=188) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddsb))] +pub unsafe fn _mm512_adds_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddsb( + a.as_i8x64(), + b.as_i8x64(), + _mm512_setzero_si512().as_i8x64(), + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + )) +} + +/// Add packed signed 8-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_adds_epi8&expand=189) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddsb))] +pub unsafe fn _mm512_mask_adds_epi8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddsb(a.as_i8x64(), b.as_i8x64(), src.as_i8x64(), k)) +} + +/// Add packed signed 8-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_adds_epi8&expand=190) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpaddsb))] +pub unsafe fn _mm512_maskz_adds_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpaddsb( + a.as_i8x64(), + b.as_i8x64(), + _mm512_setzero_si512().as_i8x64(), + k, + )) +} + +/// Add packed signed 8-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_adds_epi8&expand=186) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsb))] +pub unsafe fn _mm256_mask_adds_epi8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpaddsb256(a.as_i8x32(), b.as_i8x32(), src.as_i8x32(), k)) +} + +/// Add packed signed 8-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_adds_epi8&expand=187) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsb))] +pub unsafe fn _mm256_maskz_adds_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpaddsb256( + a.as_i8x32(), + b.as_i8x32(), + _mm256_setzero_si256().as_i8x32(), + k, + )) +} + +/// Add packed signed 8-bit integers in a and b using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_adds_epi8&expand=183) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsb))] +pub unsafe fn _mm_mask_adds_epi8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddsb128(a.as_i8x16(), b.as_i8x16(), src.as_i8x16(), k)) +} + +/// Add packed signed 8-bit integers in a and b using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_adds_epi8&expand=184) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpaddsb))] +pub unsafe fn _mm_maskz_adds_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpaddsb128( + a.as_i8x16(), + b.as_i8x16(), + _mm_setzero_si128().as_i8x16(), + k, + )) +} + +/// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi16&expand=5685) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubw))] +pub unsafe fn _mm512_sub_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_sub(a.as_i16x32(), b.as_i16x32())) +} + +/// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_epi16&expand=5683) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubw))] +pub unsafe fn _mm512_mask_sub_epi16(src: __m512i, k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, sub, src.as_i16x32())) +} + +/// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_epi16&expand=5684) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubw))] +pub unsafe fn _mm512_maskz_sub_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_sub_epi16&expand=5680) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubw))] +pub unsafe fn _mm256_mask_sub_epi16(src: __m256i, k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let sub = _mm256_sub_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, sub, src.as_i16x16())) +} + +/// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_sub_epi16&expand=5681) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubw))] +pub unsafe fn _mm256_maskz_sub_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let sub = _mm256_sub_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_epi16&expand=5677) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubw))] +pub unsafe fn _mm_mask_sub_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let sub = _mm_sub_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, sub, src.as_i16x8())) +} + +/// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_epi16&expand=5678) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubw))] +pub unsafe fn _mm_maskz_sub_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let sub = _mm_sub_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi8&expand=5712) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubb))] +pub unsafe fn _mm512_sub_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_sub(a.as_i8x64(), b.as_i8x64())) +} + +/// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_epi8&expand=5710) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubb))] +pub unsafe fn _mm512_mask_sub_epi8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi8(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, sub, src.as_i8x64())) +} + +/// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_epi8&expand=5711) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubb))] +pub unsafe fn _mm512_maskz_sub_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi8(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_sub_epi8&expand=5707) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubb))] +pub unsafe fn _mm256_mask_sub_epi8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let sub = _mm256_sub_epi8(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, sub, src.as_i8x32())) +} + +/// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_sub_epi8&expand=5708) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubb))] +pub unsafe fn _mm256_maskz_sub_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let sub = _mm256_sub_epi8(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_epi8&expand=5704) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubb))] +pub unsafe fn _mm_mask_sub_epi8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let sub = _mm_sub_epi8(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, sub, src.as_i8x16())) +} + +/// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_epi8&expand=5705) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubb))] +pub unsafe fn _mm_maskz_sub_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let sub = _mm_sub_epi8(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed unsigned 16-bit integers in b from packed unsigned 16-bit integers in a using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_subs_epu16&expand=5793) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubusw))] +pub unsafe fn _mm512_subs_epu16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubusw( + a.as_u16x32(), + b.as_u16x32(), + _mm512_setzero_si512().as_u16x32(), + 0b11111111_11111111_11111111_11111111, + )) +} + +/// Subtract packed unsigned 16-bit integers in b from packed unsigned 16-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_subs_epu16&expand=5791) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubusw))] +pub unsafe fn _mm512_mask_subs_epu16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + transmute(vpsubusw(a.as_u16x32(), b.as_u16x32(), src.as_u16x32(), k)) +} + +/// Subtract packed unsigned 16-bit integers in b from packed unsigned 16-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_subs_epu16&expand=5792) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubusw))] +pub unsafe fn _mm512_maskz_subs_epu16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubusw( + a.as_u16x32(), + b.as_u16x32(), + _mm512_setzero_si512().as_u16x32(), + k, + )) +} + +/// Subtract packed unsigned 16-bit integers in b from packed unsigned 16-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_subs_epu16&expand=5788) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusw))] +pub unsafe fn _mm256_mask_subs_epu16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + transmute(vpsubusw256( + a.as_u16x16(), + b.as_u16x16(), + src.as_u16x16(), + k, + )) +} + +/// Subtract packed unsigned 16-bit integers in b from packed unsigned 16-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_subs_epu16&expand=5789) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusw))] +pub unsafe fn _mm256_maskz_subs_epu16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + transmute(vpsubusw256( + a.as_u16x16(), + b.as_u16x16(), + _mm256_setzero_si256().as_u16x16(), + k, + )) +} + +/// Subtract packed unsigned 16-bit integers in b from packed unsigned 16-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_subs_epu16&expand=5785) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusw))] +pub unsafe fn _mm_mask_subs_epu16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubusw128(a.as_u16x8(), b.as_u16x8(), src.as_u16x8(), k)) +} + +/// Subtract packed unsigned 16-bit integers in b from packed unsigned 16-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_subs_epu16&expand=5786) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusw))] +pub unsafe fn _mm_maskz_subs_epu16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubusw128( + a.as_u16x8(), + b.as_u16x8(), + _mm_setzero_si128().as_u16x8(), + k, + )) +} + +/// Subtract packed unsigned 8-bit integers in b from packed unsigned 8-bit integers in a using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_subs_epu8&expand=5802) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubusb))] +pub unsafe fn _mm512_subs_epu8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubusb( + a.as_u8x64(), + b.as_u8x64(), + _mm512_setzero_si512().as_u8x64(), + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + )) +} + +/// Subtract packed unsigned 8-bit integers in b from packed unsigned 8-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_subs_epu8&expand=5800) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubusb))] +pub unsafe fn _mm512_mask_subs_epu8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubusb(a.as_u8x64(), b.as_u8x64(), src.as_u8x64(), k)) +} + +/// Subtract packed unsigned 8-bit integers in b from packed unsigned 8-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_subs_epu8&expand=5801) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubusb))] +pub unsafe fn _mm512_maskz_subs_epu8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubusb( + a.as_u8x64(), + b.as_u8x64(), + _mm512_setzero_si512().as_u8x64(), + k, + )) +} + +/// Subtract packed unsigned 8-bit integers in b from packed unsigned 8-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_subs_epu8&expand=5797) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusb))] +pub unsafe fn _mm256_mask_subs_epu8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpsubusb256(a.as_u8x32(), b.as_u8x32(), src.as_u8x32(), k)) +} + +/// Subtract packed unsigned 8-bit integers in b from packed unsigned 8-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_subs_epu8&expand=5798) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusb))] +pub unsafe fn _mm256_maskz_subs_epu8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpsubusb256( + a.as_u8x32(), + b.as_u8x32(), + _mm256_setzero_si256().as_u8x32(), + k, + )) +} + +/// Subtract packed unsigned 8-bit integers in b from packed unsigned 8-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_subs_epu8&expand=5794) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusb))] +pub unsafe fn _mm_mask_subs_epu8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubusb128(a.as_u8x16(), b.as_u8x16(), src.as_u8x16(), k)) +} + +/// Subtract packed unsigned 8-bit integers in b from packed unsigned 8-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_subs_epu8&expand=5795) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubusb))] +pub unsafe fn _mm_maskz_subs_epu8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubusb128( + a.as_u8x16(), + b.as_u8x16(), + _mm_setzero_si128().as_u8x16(), + k, + )) +} + +/// Subtract packed signed 16-bit integers in b from packed 16-bit integers in a using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_subs_epi16&expand=5775) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubsw))] +pub unsafe fn _mm512_subs_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubsw( + a.as_i16x32(), + b.as_i16x32(), + _mm512_setzero_si512().as_i16x32(), + 0b11111111_11111111_11111111_11111111, + )) +} + +/// Subtract packed signed 16-bit integers in b from packed 16-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_subs_epi16&expand=5773) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubsw))] +pub unsafe fn _mm512_mask_subs_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + transmute(vpsubsw(a.as_i16x32(), b.as_i16x32(), src.as_i16x32(), k)) +} + +/// Subtract packed signed 16-bit integers in b from packed 16-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_subs_epi16&expand=5774) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubsw))] +pub unsafe fn _mm512_maskz_subs_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubsw( + a.as_i16x32(), + b.as_i16x32(), + _mm512_setzero_si512().as_i16x32(), + k, + )) +} + +/// Subtract packed signed 16-bit integers in b from packed 16-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_subs_epi16&expand=5770) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsw))] +pub unsafe fn _mm256_mask_subs_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + transmute(vpsubsw256(a.as_i16x16(), b.as_i16x16(), src.as_i16x16(), k)) +} + +/// Subtract packed signed 16-bit integers in b from packed 16-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_subs_epi16&expand=5771) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsw))] +pub unsafe fn _mm256_maskz_subs_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + transmute(vpsubsw256( + a.as_i16x16(), + b.as_i16x16(), + _mm256_setzero_si256().as_i16x16(), + k, + )) +} + +/// Subtract packed signed 16-bit integers in b from packed 16-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_subs_epi16&expand=5767) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsw))] +pub unsafe fn _mm_mask_subs_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubsw128(a.as_i16x8(), b.as_i16x8(), src.as_i16x8(), k)) +} + +/// Subtract packed signed 16-bit integers in b from packed 16-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_subs_epi16&expand=5768) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsw))] +pub unsafe fn _mm_maskz_subs_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubsw128( + a.as_i16x8(), + b.as_i16x8(), + _mm_setzero_si128().as_i16x8(), + k, + )) +} + +/// Subtract packed signed 8-bit integers in b from packed 8-bit integers in a using saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_subs_epi8&expand=5784) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubsb))] +pub unsafe fn _mm512_subs_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubsb( + a.as_i8x64(), + b.as_i8x64(), + _mm512_setzero_si512().as_i8x64(), + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + )) +} + +/// Subtract packed signed 8-bit integers in b from packed 8-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_subs_epi8&expand=5782) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubsb))] +pub unsafe fn _mm512_mask_subs_epi8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubsb(a.as_i8x64(), b.as_i8x64(), src.as_i8x64(), k)) +} + +/// Subtract packed signed 8-bit integers in b from packed 8-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_subs_epi8&expand=5783) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsubsb))] +pub unsafe fn _mm512_maskz_subs_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(vpsubsb( + a.as_i8x64(), + b.as_i8x64(), + _mm512_setzero_si512().as_i8x64(), + k, + )) +} + +/// Subtract packed signed 8-bit integers in b from packed 8-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_subs_epi8&expand=5779) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsb))] +pub unsafe fn _mm256_mask_subs_epi8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpsubsb256(a.as_i8x32(), b.as_i8x32(), src.as_i8x32(), k)) +} + +/// Subtract packed signed 8-bit integers in b from packed 8-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_subs_epi8&expand=5780) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsb))] +pub unsafe fn _mm256_maskz_subs_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(vpsubsb256( + a.as_i8x32(), + b.as_i8x32(), + _mm256_setzero_si256().as_i8x32(), + k, + )) +} + +/// Subtract packed signed 8-bit integers in b from packed 8-bit integers in a using saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_subs_epi8&expand=5776) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsb))] +pub unsafe fn _mm_mask_subs_epi8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubsb128(a.as_i8x16(), b.as_i8x16(), src.as_i8x16(), k)) +} + +/// Subtract packed signed 8-bit integers in b from packed 8-bit integers in a using saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_subs_epi8&expand=5777) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsubsb))] +pub unsafe fn _mm_maskz_subs_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(vpsubsb128( + a.as_i8x16(), + b.as_i8x16(), + _mm_setzero_si128().as_i8x16(), + k, + )) +} + +/// Multiply the packed unsigned 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mulhi_epu16&expand=3973) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhuw))] +pub unsafe fn _mm512_mulhi_epu16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmulhuw(a.as_u16x32(), b.as_u16x32())) +} + +/// Multiply the packed unsigned 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mulhi_epu16&expand=3971) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhuw))] +pub unsafe fn _mm512_mask_mulhi_epu16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mulhi_epu16(a, b).as_u16x32(); + transmute(simd_select_bitmask(k, mul, src.as_u16x32())) +} + +/// Multiply the packed unsigned 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mulhi_epu16&expand=3972) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhuw))] +pub unsafe fn _mm512_maskz_mulhi_epu16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mulhi_epu16(a, b).as_u16x32(); + let zero = _mm512_setzero_si512().as_u16x32(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed unsigned 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_mulhi_epu16&expand=3968) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhuw))] +pub unsafe fn _mm256_mask_mulhi_epu16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let mul = _mm256_mulhi_epu16(a, b).as_u16x16(); + transmute(simd_select_bitmask(k, mul, src.as_u16x16())) +} + +/// Multiply the packed unsigned 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_mulhi_epu16&expand=3969) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhuw))] +pub unsafe fn _mm256_maskz_mulhi_epu16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let mul = _mm256_mulhi_epu16(a, b).as_u16x16(); + let zero = _mm256_setzero_si256().as_u16x16(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed unsigned 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mulhi_epu16&expand=3965) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhuw))] +pub unsafe fn _mm_mask_mulhi_epu16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mulhi_epu16(a, b).as_u16x8(); + transmute(simd_select_bitmask(k, mul, src.as_u16x8())) +} + +/// Multiply the packed unsigned 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mulhi_epu16&expand=3966) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhuw))] +pub unsafe fn _mm_maskz_mulhi_epu16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mulhi_epu16(a, b).as_u16x8(); + let zero = _mm_setzero_si128().as_u16x8(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed signed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mulhi_epi16&expand=3962) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhw))] +pub unsafe fn _mm512_mulhi_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmulhw(a.as_i16x32(), b.as_i16x32())) +} + +/// Multiply the packed signed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mulhi_epi16&expand=3960) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhw))] +pub unsafe fn _mm512_mask_mulhi_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mulhi_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, mul, src.as_i16x32())) +} + +/// Multiply the packed signed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mulhi_epi16&expand=3961) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhw))] +pub unsafe fn _mm512_maskz_mulhi_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mulhi_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed signed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_mulhi_epi16&expand=3957) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhw))] +pub unsafe fn _mm256_mask_mulhi_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let mul = _mm256_mulhi_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, mul, src.as_i16x16())) +} + +/// Multiply the packed signed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_mulhi_epi16&expand=3958) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhw))] +pub unsafe fn _mm256_maskz_mulhi_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let mul = _mm256_mulhi_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed signed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mulhi_epi16&expand=3954) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhw))] +pub unsafe fn _mm_mask_mulhi_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mulhi_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, mul, src.as_i16x8())) +} + +/// Multiply the packed signed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the high 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mulhi_epi16&expand=3955) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhw))] +pub unsafe fn _mm_maskz_mulhi_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mulhi_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Truncate each intermediate integer to the 18 most significant bits, round by adding 1, and store bits \[16:1\] to dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mulhrs_epi16&expand=3986) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhrsw))] +pub unsafe fn _mm512_mulhrs_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmulhrsw(a.as_i16x32(), b.as_i16x32())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Truncate each intermediate integer to the 18 most significant bits, round by adding 1, and store bits \[16:1\] to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mulhrs_epi16&expand=3984) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhrsw))] +pub unsafe fn _mm512_mask_mulhrs_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mulhrs_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, mul, src.as_i16x32())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Truncate each intermediate integer to the 18 most significant bits, round by adding 1, and store bits \[16:1\] to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mulhrs_epi16&expand=3985) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmulhrsw))] +pub unsafe fn _mm512_maskz_mulhrs_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mulhrs_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Truncate each intermediate integer to the 18 most significant bits, round by adding 1, and store bits \[16:1\] to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_mulhrs_epi16&expand=3981) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhrsw))] +pub unsafe fn _mm256_mask_mulhrs_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let mul = _mm256_mulhrs_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, mul, src.as_i16x16())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Truncate each intermediate integer to the 18 most significant bits, round by adding 1, and store bits \[16:1\] to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_mulhrs_epi16&expand=3982) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhrsw))] +pub unsafe fn _mm256_maskz_mulhrs_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let mul = _mm256_mulhrs_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Truncate each intermediate integer to the 18 most significant bits, round by adding 1, and store bits \[16:1\] to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mulhrs_epi16&expand=3978) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhrsw))] +pub unsafe fn _mm_mask_mulhrs_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mulhrs_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, mul, src.as_i16x8())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Truncate each intermediate integer to the 18 most significant bits, round by adding 1, and store bits \[16:1\] to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mulhrs_epi16&expand=3979) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmulhrsw))] +pub unsafe fn _mm_maskz_mulhrs_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mulhrs_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the low 16 bits of the intermediate integers in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mullo_epi16&expand=3996) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmullw))] +pub unsafe fn _mm512_mullo_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_mul(a.as_i16x32(), b.as_i16x32())) +} + +/// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the low 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mullo_epi16&expand=3994) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmullw))] +pub unsafe fn _mm512_mask_mullo_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mullo_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, mul, src.as_i16x32())) +} + +/// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the low 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mullo_epi16&expand=3995) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmullw))] +pub unsafe fn _mm512_maskz_mullo_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mullo_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the low 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_mullo_epi16&expand=3991) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmullw))] +pub unsafe fn _mm256_mask_mullo_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let mul = _mm256_mullo_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, mul, src.as_i16x16())) +} + +/// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the low 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_mullo_epi16&expand=3992) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmullw))] +pub unsafe fn _mm256_maskz_mullo_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let mul = _mm256_mullo_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the low 16 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mullo_epi16&expand=3988) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmullw))] +pub unsafe fn _mm_mask_mullo_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mullo_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, mul, src.as_i16x8())) +} + +/// Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit integers, and store the low 16 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mullo_epi16&expand=3989) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmullw))] +pub unsafe fn _mm_maskz_mullo_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let mul = _mm_mullo_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epu16&expand=3609) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxuw))] +pub unsafe fn _mm512_max_epu16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxuw(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epu16&expand=3607) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxuw))] +pub unsafe fn _mm512_mask_max_epu16(src: __m512i, k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu16(a, b).as_u16x32(); + transmute(simd_select_bitmask(k, max, src.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epu16&expand=3608) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxuw))] +pub unsafe fn _mm512_maskz_max_epu16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu16(a, b).as_u16x32(); + let zero = _mm512_setzero_si512().as_u16x32(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_max_epu16&expand=3604) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxuw))] +pub unsafe fn _mm256_mask_max_epu16(src: __m256i, k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epu16(a, b).as_u16x16(); + transmute(simd_select_bitmask(k, max, src.as_u16x16())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_max_epu16&expand=3605) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxuw))] +pub unsafe fn _mm256_maskz_max_epu16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epu16(a, b).as_u16x16(); + let zero = _mm256_setzero_si256().as_u16x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_epu16&expand=3601) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxuw))] +pub unsafe fn _mm_mask_max_epu16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epu16(a, b).as_u16x8(); + transmute(simd_select_bitmask(k, max, src.as_u16x8())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_epu16&expand=3602) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxuw))] +pub unsafe fn _mm_maskz_max_epu16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epu16(a, b).as_u16x8(); + let zero = _mm_setzero_si128().as_u16x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epu8&expand=3636) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxub))] +pub unsafe fn _mm512_max_epu8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxub(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epu8&expand=3634) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxub))] +pub unsafe fn _mm512_mask_max_epu8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu8(a, b).as_u8x64(); + transmute(simd_select_bitmask(k, max, src.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epu8&expand=3635) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxub))] +pub unsafe fn _mm512_maskz_max_epu8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu8(a, b).as_u8x64(); + let zero = _mm512_setzero_si512().as_u8x64(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_max_epu8&expand=3631) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxub))] +pub unsafe fn _mm256_mask_max_epu8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epu8(a, b).as_u8x32(); + transmute(simd_select_bitmask(k, max, src.as_u8x32())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_max_epu8&expand=3632) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxub))] +pub unsafe fn _mm256_maskz_max_epu8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epu8(a, b).as_u8x32(); + let zero = _mm256_setzero_si256().as_u8x32(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_epu8&expand=3628) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxub))] +pub unsafe fn _mm_mask_max_epu8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epu8(a, b).as_u8x16(); + transmute(simd_select_bitmask(k, max, src.as_u8x16())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_epu8&expand=3629) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxub))] +pub unsafe fn _mm_maskz_max_epu8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epu8(a, b).as_u8x16(); + let zero = _mm_setzero_si128().as_u8x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epi16&expand=3573) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxsw))] +pub unsafe fn _mm512_max_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxsw(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epi16&expand=3571) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxsw))] +pub unsafe fn _mm512_mask_max_epi16(src: __m512i, k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, max, src.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epi16&expand=3572) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxsw))] +pub unsafe fn _mm512_maskz_max_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_max_epi16&expand=3568) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsw))] +pub unsafe fn _mm256_mask_max_epi16(src: __m256i, k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, max, src.as_i16x16())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_max_epi16&expand=3569) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsw))] +pub unsafe fn _mm256_maskz_max_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_epi16&expand=3565) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsw))] +pub unsafe fn _mm_mask_max_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, max, src.as_i16x8())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_epi16&expand=3566) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsw))] +pub unsafe fn _mm_maskz_max_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epi8&expand=3600) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxsb))] +pub unsafe fn _mm512_max_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxsb(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epi8&expand=3598) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxsb))] +pub unsafe fn _mm512_mask_max_epi8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi8(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, max, src.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epi8&expand=3599) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaxsb))] +pub unsafe fn _mm512_maskz_max_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi8(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_max_epi8&expand=3595) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsb))] +pub unsafe fn _mm256_mask_max_epi8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epi8(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, max, src.as_i8x32())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_max_epi8&expand=3596) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsb))] +pub unsafe fn _mm256_maskz_max_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let max = _mm256_max_epi8(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_epi8&expand=3592) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsb))] +pub unsafe fn _mm_mask_max_epi8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epi8(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, max, src.as_i8x16())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_epi8&expand=3593) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaxsb))] +pub unsafe fn _mm_maskz_max_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let max = _mm_max_epi8(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epu16&expand=3723) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminuw))] +pub unsafe fn _mm512_min_epu16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminuw(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epu16&expand=3721) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminuw))] +pub unsafe fn _mm512_mask_min_epu16(src: __m512i, k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epu16(a, b).as_u16x32(); + transmute(simd_select_bitmask(k, min, src.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epu16&expand=3722) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminuw))] +pub unsafe fn _mm512_maskz_min_epu16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epu16(a, b).as_u16x32(); + let zero = _mm512_setzero_si512().as_u16x32(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_min_epu16&expand=3718) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminuw))] +pub unsafe fn _mm256_mask_min_epu16(src: __m256i, k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epu16(a, b).as_u16x16(); + transmute(simd_select_bitmask(k, min, src.as_u16x16())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_min_epu16&expand=3719) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminuw))] +pub unsafe fn _mm256_maskz_min_epu16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epu16(a, b).as_u16x16(); + let zero = _mm256_setzero_si256().as_u16x16(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_epu16&expand=3715) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminuw))] +pub unsafe fn _mm_mask_min_epu16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epu16(a, b).as_u16x8(); + transmute(simd_select_bitmask(k, min, src.as_u16x8())) +} + +/// Compare packed unsigned 16-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_epu16&expand=3716) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminuw))] +pub unsafe fn _mm_maskz_min_epu16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epu16(a, b).as_u16x8(); + let zero = _mm_setzero_si128().as_u16x8(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epu8&expand=3750) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminub))] +pub unsafe fn _mm512_min_epu8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminub(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epu8&expand=3748) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminub))] +pub unsafe fn _mm512_mask_min_epu8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epu8(a, b).as_u8x64(); + transmute(simd_select_bitmask(k, min, src.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epu8&expand=3749) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminub))] +pub unsafe fn _mm512_maskz_min_epu8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epu8(a, b).as_u8x64(); + let zero = _mm512_setzero_si512().as_u8x64(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_min_epu8&expand=3745) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminub))] +pub unsafe fn _mm256_mask_min_epu8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epu8(a, b).as_u8x32(); + transmute(simd_select_bitmask(k, min, src.as_u8x32())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_min_epu8&expand=3746) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminub))] +pub unsafe fn _mm256_maskz_min_epu8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epu8(a, b).as_u8x32(); + let zero = _mm256_setzero_si256().as_u8x32(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_epu8&expand=3742) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminub))] +pub unsafe fn _mm_mask_min_epu8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epu8(a, b).as_u8x16(); + transmute(simd_select_bitmask(k, min, src.as_u8x16())) +} + +/// Compare packed unsigned 8-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_epu8&expand=3743) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminub))] +pub unsafe fn _mm_maskz_min_epu8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epu8(a, b).as_u8x16(); + let zero = _mm_setzero_si128().as_u8x16(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epi16&expand=3687) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminsw))] +pub unsafe fn _mm512_min_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminsw(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epi16&expand=3685) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminsw))] +pub unsafe fn _mm512_mask_min_epi16(src: __m512i, k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, min, src.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epi16&expand=3686) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminsw))] +pub unsafe fn _mm512_maskz_min_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_min_epi16&expand=3682) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsw))] +pub unsafe fn _mm256_mask_min_epi16(src: __m256i, k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, min, src.as_i16x16())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_min_epi16&expand=3683) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsw))] +pub unsafe fn _mm256_maskz_min_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_epi16&expand=3679) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsw))] +pub unsafe fn _mm_mask_min_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, min, src.as_i16x8())) +} + +/// Compare packed signed 16-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_epi16&expand=3680) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsw))] +pub unsafe fn _mm_maskz_min_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epi8&expand=3714) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminsb))] +pub unsafe fn _mm512_min_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminsb(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epi8&expand=3712) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminsb))] +pub unsafe fn _mm512_mask_min_epi8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epi8(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, min, src.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epi8&expand=3713) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpminsb))] +pub unsafe fn _mm512_maskz_min_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let min = _mm512_min_epi8(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_min_epi8&expand=3709) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsb))] +pub unsafe fn _mm256_mask_min_epi8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epi8(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, min, src.as_i8x32())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_min_epi8&expand=3710) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsb))] +pub unsafe fn _mm256_maskz_min_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let min = _mm256_min_epi8(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_epi8&expand=3706) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsb))] +pub unsafe fn _mm_mask_min_epi8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epi8(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, min, src.as_i8x16())) +} + +/// Compare packed signed 8-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_epi8&expand=3707) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpminsb))] +pub unsafe fn _mm_maskz_min_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let min = _mm_min_epi8(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, min, zero)) +} + +/// Compare packed unsigned 16-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmplt_epu16_mask&expand=1050) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epu16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_lt(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu16_mask&expand=1051) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epu16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmplt_epu16_mask(a, b) & k1 +} + +/// Compare packed unsigned 8-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm512_cmplt_epu8_mask&expand=1068) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epu8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_lt(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu8_mask&expand=1069) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epu8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmplt_epu8_mask(a, b) & k1 +} + +/// Compare packed signed 16-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi16_mask&expand=1022) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_lt(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi16_mask&expand=1023) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epi16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmplt_epi16_mask(a, b) & k1 +} + +/// Compare packed signed 8-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi8_mask&expand=1044) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_lt(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi8_mask&expand=1045) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epi8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmplt_epi8_mask(a, b) & k1 +} + +/// Compare packed unsigned 16-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu16_mask&expand=927) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epu16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_gt(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu16_mask&expand=928) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epu16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpgt_epu16_mask(a, b) & k1 +} + +/// Compare packed unsigned 8-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu8_mask&expand=945) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epu8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_gt(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu8_mask&expand=946) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epu8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpgt_epu8_mask(a, b) & k1 +} + +/// Compare packed signed 16-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi16_mask&expand=897) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_gt(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi16_mask&expand=898) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epi16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpgt_epi16_mask(a, b) & k1 +} + +/// Compare packed signed 8-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi8_mask&expand=921) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_gt(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi8_mask&expand=922) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epi8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpgt_epi8_mask(a, b) & k1 +} + +/// Compare packed unsigned 16-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu16_mask&expand=989) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epu16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_le(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu16_mask&expand=990) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epu16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmple_epu16_mask(a, b) & k1 +} + +/// Compare packed unsigned 8-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu8_mask&expand=1007) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epu8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_le(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu8_mask&expand=1008) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epu8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmple_epu8_mask(a, b) & k1 +} + +/// Compare packed signed 16-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi16_mask&expand=965) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_le(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi16_mask&expand=966) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epi16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmple_epi16_mask(a, b) & k1 +} + +/// Compare packed signed 8-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi8_mask&expand=983) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_le(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi8_mask&expand=984) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epi8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmple_epi8_mask(a, b) & k1 +} + +/// Compare packed unsigned 16-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu16_mask&expand=867) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epu16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_ge(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu16_mask&expand=868) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epu16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpge_epu16_mask(a, b) & k1 +} + +/// Compare packed unsigned 8-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu8_mask&expand=885) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epu8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_ge(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu8_mask&expand=886) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epu8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpge_epu8_mask(a, b) & k1 +} + +/// Compare packed signed 16-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi16_mask&expand=843) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_ge(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi16_mask&expand=844) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epi16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpge_epi16_mask(a, b) & k1 +} + +/// Compare packed signed 8-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi8_mask&expand=861) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_ge(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi8_mask&expand=862) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epi8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpge_epi8_mask(a, b) & k1 +} + +/// Compare packed unsigned 16-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu16_mask&expand=801) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epu16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_eq(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu16_mask&expand=802) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epu16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpeq_epu16_mask(a, b) & k1 +} + +/// Compare packed unsigned 8-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu8_mask&expand=819) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epu8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_eq(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu8_mask&expand=820) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epu8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpeq_epu8_mask(a, b) & k1 +} + +/// Compare packed signed 16-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi16_mask&expand=771) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_eq(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi16_mask&expand=772) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epi16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpeq_epi16_mask(a, b) & k1 +} + +/// Compare packed signed 8-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi8_mask&expand=795) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_eq(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi8_mask&expand=796) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epi8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpeq_epi8_mask(a, b) & k1 +} + +/// Compare packed unsigned 16-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu16_mask&expand=1106) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epu16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_ne(a.as_u16x32(), b.as_u16x32())) +} + +/// Compare packed unsigned 16-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu16_mask&expand=1107) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epu16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpneq_epu16_mask(a, b) & k1 +} + +/// Compare packed unsigned 8-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu8_mask&expand=1124) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epu8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_ne(a.as_u8x64(), b.as_u8x64())) +} + +/// Compare packed unsigned 8-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu8_mask&expand=1125) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epu8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpneq_epu8_mask(a, b) & k1 +} + +/// Compare packed signed 16-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi16_mask&expand=1082) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + simd_bitmask::(simd_ne(a.as_i16x32(), b.as_i16x32())) +} + +/// Compare packed signed 16-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi16_mask&expand=1083) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epi16_mask(k1: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + _mm512_cmpneq_epi16_mask(a, b) & k1 +} + +/// Compare packed signed 8-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi8_mask&expand=1100) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + simd_bitmask::(simd_ne(a.as_i8x64(), b.as_i8x64())) +} + +/// Compare packed signed 8-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi8_mask&expand=1101) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epi8_mask(k1: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + _mm512_cmpneq_epi8_mask(a, b) & k1 +} + +/// Compare packed unsigned 16-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu16_mask&expand=715) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epu16_mask(a: __m512i, b: __m512i, imm8: i32) -> __mmask32 { + let a = a.as_u16x32(); + let b = b.as_u16x32(); + macro_rules! call { + ($imm3:expr) => { + vpcmpuw(a, b, $imm3, 0b11111111_11111111_11111111_11111111) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed unsigned 16-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu16_mask&expand=716) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epu16_mask( + k1: __mmask32, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __mmask32 { + let a = a.as_u16x32(); + let b = b.as_u16x32(); + macro_rules! call { + ($imm3:expr) => { + vpcmpuw(a, b, $imm3, k1) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed unsigned 8-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu8_mask&expand=733) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epu8_mask(a: __m512i, b: __m512i, imm8: i32) -> __mmask64 { + let a = a.as_u8x64(); + let b = b.as_u8x64(); + macro_rules! call { + ($imm3:expr) => { + vpcmpub( + a, + b, + $imm3, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + ) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed unsigned 8-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu8_mask&expand=734) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epu8_mask( + k1: __mmask64, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __mmask64 { + let a = a.as_u8x64(); + let b = b.as_u8x64(); + macro_rules! call { + ($imm3:expr) => { + vpcmpub(a, b, $imm3, k1) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 16-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi16_mask&expand=691) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epi16_mask(a: __m512i, b: __m512i, imm8: i32) -> __mmask32 { + let a = a.as_i16x32(); + let b = b.as_i16x32(); + macro_rules! call { + ($imm3:expr) => { + vpcmpw(a, b, $imm3, 0b11111111_11111111_11111111_11111111) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 16-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi16_mask&expand=692) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epi16_mask( + k1: __mmask32, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __mmask32 { + let a = a.as_i16x32(); + let b = b.as_i16x32(); + macro_rules! call { + ($imm3:expr) => { + vpcmpw(a, b, $imm3, k1) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 8-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi8_mask&expand=709) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epi8_mask(a: __m512i, b: __m512i, imm8: i32) -> __mmask64 { + let a = a.as_i8x64(); + let b = b.as_i8x64(); + macro_rules! call { + ($imm3:expr) => { + vpcmpb( + a, + b, + $imm3, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + ) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 8-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi8_mask&expand=710) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epi8_mask( + k1: __mmask64, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __mmask64 { + let a = a.as_i8x64(); + let b = b.as_i8x64(); + macro_rules! call { + ($imm3:expr) => { + vpcmpb(a, b, $imm3, k1) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Load 512-bits (composed of 32 packed 16-bit integers) from memory into dst. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_epi16&expand=3368) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu16 +pub unsafe fn _mm512_loadu_epi16(mem_addr: *const i16) -> __m512i { + ptr::read_unaligned(mem_addr as *const __m512i) +} + +/// Load 512-bits (composed of 64 packed 8-bit integers) from memory into dst. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_epi8&expand=3395) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu8 +pub unsafe fn _mm512_loadu_epi8(mem_addr: *const i8) -> __m512i { + ptr::read_unaligned(mem_addr as *const __m512i) +} + +/// Store 512-bits (composed of 32 packed 16-bit integers) from a into memory. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_epi16&expand=5622) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu32 +pub unsafe fn _mm512_storeu_epi16(mem_addr: *mut i16, a: __m512i) { + ptr::write_unaligned(mem_addr as *mut __m512i, a); +} + +/// Store 512-bits (composed of 64 packed 8-bit integers) from a into memory. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_epi8&expand=5640) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu8 +pub unsafe fn _mm512_storeu_epi8(mem_addr: *mut i8, a: __m512i) { + ptr::write_unaligned(mem_addr as *mut __m512i, a); +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_madd_epi16&expand=3511) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaddwd))] +pub unsafe fn _mm512_madd_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaddwd(a.as_i16x32(), b.as_i16x32())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_madd_epi16&expand=3512) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaddwd))] +pub unsafe fn _mm512_mask_madd_epi16( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let madd = _mm512_madd_epi16(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, madd, src.as_i32x16())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_madd_epi16&expand=3513) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaddwd))] +pub unsafe fn _mm512_maskz_madd_epi16(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let madd = _mm512_madd_epi16(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, madd, zero)) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_madd_epi16&expand=3509) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddwd))] +pub unsafe fn _mm256_mask_madd_epi16(src: __m256i, k: __mmask8, a: __m256i, b: __m256i) -> __m256i { + let madd = _mm256_madd_epi16(a, b).as_i32x8(); + transmute(simd_select_bitmask(k, madd, src.as_i32x8())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_madd_epi16&expand=3510) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddwd))] +pub unsafe fn _mm256_maskz_madd_epi16(k: __mmask8, a: __m256i, b: __m256i) -> __m256i { + let madd = _mm256_madd_epi16(a, b).as_i32x8(); + let zero = _mm256_setzero_si256().as_i32x8(); + transmute(simd_select_bitmask(k, madd, zero)) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_madd_epi16&expand=3506) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddwd))] +pub unsafe fn _mm_mask_madd_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let madd = _mm_madd_epi16(a, b).as_i32x4(); + transmute(simd_select_bitmask(k, madd, src.as_i32x4())) +} + +/// Multiply packed signed 16-bit integers in a and b, producing intermediate signed 32-bit integers. Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_madd_epi16&expand=3507) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddwd))] +pub unsafe fn _mm_maskz_madd_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let madd = _mm_madd_epi16(a, b).as_i32x4(); + let zero = _mm_setzero_si128().as_i32x4(); + transmute(simd_select_bitmask(k, madd, zero)) +} + +/// Vertically multiply each unsigned 8-bit integer from a with the corresponding signed 8-bit integer from b, producing intermediate signed 16-bit integers. Horizontally add adjacent pairs of intermediate signed 16-bit integers, and pack the saturated results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maddubs_epi16&expand=3539) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaddubsw))] +pub unsafe fn _mm512_maddubs_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaddubsw(a.as_i8x64(), b.as_i8x64())) +} + +/// Multiply packed unsigned 8-bit integers in a by packed signed 8-bit integers in b, producing intermediate signed 16-bit integers. Horizontally add adjacent pairs of intermediate signed 16-bit integers, and pack the saturated results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_maddubs_epi16&expand=3540) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaddubsw))] +pub unsafe fn _mm512_mask_maddubs_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let madd = _mm512_maddubs_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, madd, src.as_i16x32())) +} + +/// Multiply packed unsigned 8-bit integers in a by packed signed 8-bit integers in b, producing intermediate signed 16-bit integers. Horizontally add adjacent pairs of intermediate signed 16-bit integers, and pack the saturated results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_maddubs_epi16&expand=3541) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmaddubsw))] +pub unsafe fn _mm512_maskz_maddubs_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let madd = _mm512_maddubs_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, madd, zero)) +} + +/// Multiply packed unsigned 8-bit integers in a by packed signed 8-bit integers in b, producing intermediate signed 16-bit integers. Horizontally add adjacent pairs of intermediate signed 16-bit integers, and pack the saturated results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_maddubs_epi16&expand=3537) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddubsw))] +pub unsafe fn _mm256_mask_maddubs_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let madd = _mm256_maddubs_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, madd, src.as_i16x16())) +} + +/// Multiply packed unsigned 8-bit integers in a by packed signed 8-bit integers in b, producing intermediate signed 16-bit integers. Horizontally add adjacent pairs of intermediate signed 16-bit integers, and pack the saturated results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_maddubs_epi16&expand=3538) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddubsw))] +pub unsafe fn _mm256_maskz_maddubs_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let madd = _mm256_maddubs_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, madd, zero)) +} + +/// Multiply packed unsigned 8-bit integers in a by packed signed 8-bit integers in b, producing intermediate signed 16-bit integers. Horizontally add adjacent pairs of intermediate signed 16-bit integers, and pack the saturated results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_maddubs_epi16&expand=3534) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddubsw))] +pub unsafe fn _mm_mask_maddubs_epi16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let madd = _mm_maddubs_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, madd, src.as_i16x8())) +} + +/// Multiply packed unsigned 8-bit integers in a by packed signed 8-bit integers in b, producing intermediate signed 16-bit integers. Horizontally add adjacent pairs of intermediate signed 16-bit integers, and pack the saturated results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_maddubs_epi16&expand=3535) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpmaddubsw))] +pub unsafe fn _mm_maskz_maddubs_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let madd = _mm_maddubs_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, madd, zero)) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using signed saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_packs_epi32&expand=4091) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackssdw))] +pub unsafe fn _mm512_packs_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpackssdw(a.as_i32x16(), b.as_i32x16())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_packs_epi32&expand=4089) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackssdw))] +pub unsafe fn _mm512_mask_packs_epi32( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let pack = _mm512_packs_epi32(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, pack, src.as_i16x32())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_packs_epi32&expand=4090) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackssdw))] +pub unsafe fn _mm512_maskz_packs_epi32(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let pack = _mm512_packs_epi32(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_packs_epi32&expand=4086) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackssdw))] +pub unsafe fn _mm256_mask_packs_epi32( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let pack = _mm256_packs_epi32(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, pack, src.as_i16x16())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_packs_epi32&expand=4087) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackssdw))] +pub unsafe fn _mm256_maskz_packs_epi32(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let pack = _mm256_packs_epi32(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_packs_epi32&expand=4083) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackssdw))] +pub unsafe fn _mm_mask_packs_epi32(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packs_epi32(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, pack, src.as_i16x8())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_packs_epi32&expand=4084) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackssdw))] +pub unsafe fn _mm_maskz_packs_epi32(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packs_epi32(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using signed saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_packs_epi16&expand=4082) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpacksswb))] +pub unsafe fn _mm512_packs_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpacksswb(a.as_i16x32(), b.as_i16x32())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_packs_epi16&expand=4080) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpacksswb))] +pub unsafe fn _mm512_mask_packs_epi16( + src: __m512i, + k: __mmask64, + a: __m512i, + b: __m512i, +) -> __m512i { + let pack = _mm512_packs_epi16(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, pack, src.as_i8x64())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_packs_epi16&expand=4081) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpacksswb))] +pub unsafe fn _mm512_maskz_packs_epi16(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let pack = _mm512_packs_epi16(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_packs_epi16&expand=4077) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpacksswb))] +pub unsafe fn _mm256_mask_packs_epi16( + src: __m256i, + k: __mmask32, + a: __m256i, + b: __m256i, +) -> __m256i { + let pack = _mm256_packs_epi16(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, pack, src.as_i8x32())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=#text=_mm256_maskz_packs_epi16&expand=4078) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpacksswb))] +pub unsafe fn _mm256_maskz_packs_epi16(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let pack = _mm256_packs_epi16(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_packs_epi16&expand=4074) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpacksswb))] +pub unsafe fn _mm_mask_packs_epi16(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packs_epi16(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, pack, src.as_i8x16())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_packs_epi16&expand=4075) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpacksswb))] +pub unsafe fn _mm_maskz_packs_epi16(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packs_epi16(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using unsigned saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_packus_epi32&expand=4130) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackusdw))] +pub unsafe fn _mm512_packus_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpackusdw(a.as_i32x16(), b.as_i32x16())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_packus_epi32&expand=4128) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackusdw))] +pub unsafe fn _mm512_mask_packus_epi32( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let pack = _mm512_packus_epi32(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, pack, src.as_i16x32())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_packus_epi32&expand=4129) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackusdw))] +pub unsafe fn _mm512_maskz_packus_epi32(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let pack = _mm512_packus_epi32(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_packus_epi32&expand=4125) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackusdw))] +pub unsafe fn _mm256_mask_packus_epi32( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let pack = _mm256_packus_epi32(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, pack, src.as_i16x16())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_packus_epi32&expand=4126) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackusdw))] +pub unsafe fn _mm256_maskz_packus_epi32(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let pack = _mm256_packus_epi32(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_packus_epi32&expand=4122) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackusdw))] +pub unsafe fn _mm_mask_packus_epi32(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packus_epi32(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, pack, src.as_i16x8())) +} + +/// Convert packed signed 32-bit integers from a and b to packed 16-bit integers using unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_packus_epi32&expand=4123) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackusdw))] +pub unsafe fn _mm_maskz_packus_epi32(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packus_epi32(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using unsigned saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_packus_epi16&expand=4121) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackuswb))] +pub unsafe fn _mm512_packus_epi16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpackuswb(a.as_i16x32(), b.as_i16x32())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_packus_epi16&expand=4119) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackuswb))] +pub unsafe fn _mm512_mask_packus_epi16( + src: __m512i, + k: __mmask64, + a: __m512i, + b: __m512i, +) -> __m512i { + let pack = _mm512_packus_epi16(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, pack, src.as_i8x64())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_packus_epi16&expand=4120) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpackuswb))] +pub unsafe fn _mm512_maskz_packus_epi16(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let pack = _mm512_packus_epi16(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_packus_epi16&expand=4116) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackuswb))] +pub unsafe fn _mm256_mask_packus_epi16( + src: __m256i, + k: __mmask32, + a: __m256i, + b: __m256i, +) -> __m256i { + let pack = _mm256_packus_epi16(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, pack, src.as_i8x32())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_packus_epi16&expand=4117) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackuswb))] +pub unsafe fn _mm256_maskz_packus_epi16(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let pack = _mm256_packus_epi16(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_packus_epi16&expand=4113) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackuswb))] +pub unsafe fn _mm_mask_packus_epi16(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packus_epi16(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, pack, src.as_i8x16())) +} + +/// Convert packed signed 16-bit integers from a and b to packed 8-bit integers using unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_packus_epi16&expand=4114) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpackuswb))] +pub unsafe fn _mm_maskz_packus_epi16(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let pack = _mm_packus_epi16(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, pack, zero)) +} + +/// Average packed unsigned 16-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_avg_epu16&expand=388) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpavgw))] +pub unsafe fn _mm512_avg_epu16(a: __m512i, b: __m512i) -> __m512i { + transmute(vpavgw(a.as_u16x32(), b.as_u16x32())) +} + +/// Average packed unsigned 16-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_avg_epu16&expand=389) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpavgw))] +pub unsafe fn _mm512_mask_avg_epu16(src: __m512i, k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let avg = _mm512_avg_epu16(a, b).as_u16x32(); + transmute(simd_select_bitmask(k, avg, src.as_u16x32())) +} + +/// Average packed unsigned 16-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_avg_epu16&expand=390) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpavgw))] +pub unsafe fn _mm512_maskz_avg_epu16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let avg = _mm512_avg_epu16(a, b).as_u16x32(); + let zero = _mm512_setzero_si512().as_u16x32(); + transmute(simd_select_bitmask(k, avg, zero)) +} + +/// Average packed unsigned 16-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_avg_epu16&expand=386) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgw))] +pub unsafe fn _mm256_mask_avg_epu16(src: __m256i, k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let avg = _mm256_avg_epu16(a, b).as_u16x16(); + transmute(simd_select_bitmask(k, avg, src.as_u16x16())) +} + +/// Average packed unsigned 16-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_avg_epu16&expand=387) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgw))] +pub unsafe fn _mm256_maskz_avg_epu16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let avg = _mm256_avg_epu16(a, b).as_u16x16(); + let zero = _mm256_setzero_si256().as_u16x16(); + transmute(simd_select_bitmask(k, avg, zero)) +} + +/// Average packed unsigned 16-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_avg_epu16&expand=383) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgw))] +pub unsafe fn _mm_mask_avg_epu16(src: __m128i, k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let avg = _mm_avg_epu16(a, b).as_u16x8(); + transmute(simd_select_bitmask(k, avg, src.as_u16x8())) +} + +/// Average packed unsigned 16-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_avg_epu16&expand=384) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgw))] +pub unsafe fn _mm_maskz_avg_epu16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let avg = _mm_avg_epu16(a, b).as_u16x8(); + let zero = _mm_setzero_si128().as_u16x8(); + transmute(simd_select_bitmask(k, avg, zero)) +} + +/// Average packed unsigned 8-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_avg_epu8&expand=397) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpavgb))] +pub unsafe fn _mm512_avg_epu8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpavgb(a.as_u8x64(), b.as_u8x64())) +} + +/// Average packed unsigned 8-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_avg_epu8&expand=398) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpavgb))] +pub unsafe fn _mm512_mask_avg_epu8(src: __m512i, k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let avg = _mm512_avg_epu8(a, b).as_u8x64(); + transmute(simd_select_bitmask(k, avg, src.as_u8x64())) +} + +/// Average packed unsigned 8-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_avg_epu8&expand=399) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpavgb))] +pub unsafe fn _mm512_maskz_avg_epu8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let avg = _mm512_avg_epu8(a, b).as_u8x64(); + let zero = _mm512_setzero_si512().as_u8x64(); + transmute(simd_select_bitmask(k, avg, zero)) +} + +/// Average packed unsigned 8-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_avg_epu8&expand=395) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgb))] +pub unsafe fn _mm256_mask_avg_epu8(src: __m256i, k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let avg = _mm256_avg_epu8(a, b).as_u8x32(); + transmute(simd_select_bitmask(k, avg, src.as_u8x32())) +} + +/// Average packed unsigned 8-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_avg_epu8&expand=396) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgb))] +pub unsafe fn _mm256_maskz_avg_epu8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let avg = _mm256_avg_epu8(a, b).as_u8x32(); + let zero = _mm256_setzero_si256().as_u8x32(); + transmute(simd_select_bitmask(k, avg, zero)) +} + +/// Average packed unsigned 8-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_avg_epu8&expand=392) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgb))] +pub unsafe fn _mm_mask_avg_epu8(src: __m128i, k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let avg = _mm_avg_epu8(a, b).as_u8x16(); + transmute(simd_select_bitmask(k, avg, src.as_u8x16())) +} + +/// Average packed unsigned 8-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_avg_epu8&expand=393) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpavgb))] +pub unsafe fn _mm_maskz_avg_epu8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let avg = _mm_avg_epu8(a, b).as_u8x16(); + let zero = _mm_setzero_si128().as_u8x16(); + transmute(simd_select_bitmask(k, avg, zero)) +} + +/// Shift packed 16-bit integers in a left by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sll_epi16&expand=5271) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllw))] +pub unsafe fn _mm512_sll_epi16(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsllw(a.as_i16x32(), count.as_i16x8())) +} + +/// Shift packed 16-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sll_epi16&expand=5269) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllw))] +pub unsafe fn _mm512_mask_sll_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sll_epi16(a, count).as_i16x32(); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sll_epi16&expand=5270) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllw))] +pub unsafe fn _mm512_maskz_sll_epi16(k: __mmask32, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sll_epi16(a, count).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_sll_epi16&expand=5266) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw))] +pub unsafe fn _mm256_mask_sll_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + count: __m128i, +) -> __m256i { + let shf = _mm256_sll_epi16(a, count).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_sll_epi16&expand=5267) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw))] +pub unsafe fn _mm256_maskz_sll_epi16(k: __mmask16, a: __m256i, count: __m128i) -> __m256i { + let shf = _mm256_sll_epi16(a, count).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sll_epi16&expand=5263) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw))] +pub unsafe fn _mm_mask_sll_epi16(src: __m128i, k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_sll_epi16(a, count).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sll_epi16&expand=5264) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw))] +pub unsafe fn _mm_maskz_sll_epi16(k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_sll_epi16(a, count).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_slli_epi16&expand=5301) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllw, imm8 = 5))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_slli_epi16(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpslliw(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_slli_epi16&expand=5299) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllw, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_slli_epi16(src: __m512i, k: __mmask32, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpslliw(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_slli_epi16&expand=5300) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllw, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_slli_epi16(k: __mmask32, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpslliw(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_slli_epi16&expand=5296) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm256_mask_slli_epi16(src: __m256i, k: __mmask16, a: __m256i, imm8: u32) -> __m256i { + macro_rules! call { + ($imm8:expr) => { + _mm256_slli_epi16(a, $imm8).as_i16x16() + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_slli_epi16&expand=5297) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm256_maskz_slli_epi16(k: __mmask16, a: __m256i, imm8: u32) -> __m256i { + macro_rules! call { + ($imm8:expr) => { + _mm256_slli_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_slli_epi16&expand=5293) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_mask_slli_epi16(src: __m128i, k: __mmask8, a: __m128i, imm8: u32) -> __m128i { + macro_rules! call { + ($imm8:expr) => { + _mm_slli_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_slli_epi16&expand=5294) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllw, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_maskz_slli_epi16(k: __mmask8, a: __m128i, imm8: u32) -> __m128i { + macro_rules! call { + ($imm8:expr) => { + _mm_slli_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sllv_epi16&expand=5333) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm512_sllv_epi16(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsllvw(a.as_i16x32(), count.as_i16x32())) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sllv_epi16&expand=5331) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm512_mask_sllv_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_sllv_epi16(a, count).as_i16x32(); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sllv_epi16&expand=5332) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm512_maskz_sllv_epi16(k: __mmask32, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_sllv_epi16(a, count).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_sllv_epi16&expand=5330) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm256_sllv_epi16(a: __m256i, count: __m256i) -> __m256i { + transmute(vpsllvw256(a.as_i16x16(), count.as_i16x16())) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_sllv_epi16&expand=5328) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm256_mask_sllv_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + count: __m256i, +) -> __m256i { + let shf = _mm256_sllv_epi16(a, count).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_sllv_epi16&expand=5329) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm256_maskz_sllv_epi16(k: __mmask16, a: __m256i, count: __m256i) -> __m256i { + let shf = _mm256_sllv_epi16(a, count).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sllv_epi16&expand=5327) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm_sllv_epi16(a: __m128i, count: __m128i) -> __m128i { + transmute(vpsllvw128(a.as_i16x8(), count.as_i16x8())) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sllv_epi16&expand=5325) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm_mask_sllv_epi16( + src: __m128i, + k: __mmask8, + a: __m128i, + count: __m128i, +) -> __m128i { + let shf = _mm_sllv_epi16(a, count).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sllv_epi16&expand=5326) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsllvw))] +pub unsafe fn _mm_maskz_sllv_epi16(k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_sllv_epi16(a, count).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srl_epi16&expand=5483) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlw))] +pub unsafe fn _mm512_srl_epi16(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrlw(a.as_i16x32(), count.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srl_epi16&expand=5481) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlw))] +pub unsafe fn _mm512_mask_srl_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_srl_epi16(a, count).as_i16x32(); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srl_epi16&expand=5482) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlw))] +pub unsafe fn _mm512_maskz_srl_epi16(k: __mmask32, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_srl_epi16(a, count).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_srl_epi16&expand=5478) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw))] +pub unsafe fn _mm256_mask_srl_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + count: __m128i, +) -> __m256i { + let shf = _mm256_srl_epi16(a, count).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_srl_epi16&expand=5479) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw))] +pub unsafe fn _mm256_maskz_srl_epi16(k: __mmask16, a: __m256i, count: __m128i) -> __m256i { + let shf = _mm256_srl_epi16(a, count).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_srl_epi16&expand=5475) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw))] +pub unsafe fn _mm_mask_srl_epi16(src: __m128i, k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_srl_epi16(a, count).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_srl_epi16&expand=5476) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw))] +pub unsafe fn _mm_maskz_srl_epi16(k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_srl_epi16(a, count).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srli_epi16&expand=5513) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlw, imm8 = 5))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srli_epi16(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpsrliw(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srli_epi16&expand=5511) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlw, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srli_epi16(src: __m512i, k: __mmask32, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpsrliw(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srli_epi16&expand=5512) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlw, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srli_epi16(k: __mmask32, a: __m512i, imm8: i32) -> __m512i { + //imm8 should be u32, it seems the document to verify is incorrect + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpsrliw(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_srli_epi16&expand=5508) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm256_mask_srli_epi16(src: __m256i, k: __mmask16, a: __m256i, imm8: i32) -> __m256i { + macro_rules! call { + ($imm8:expr) => { + _mm256_srli_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_srli_epi16&expand=5509) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm256_maskz_srli_epi16(k: __mmask16, a: __m256i, imm8: i32) -> __m256i { + macro_rules! call { + ($imm8:expr) => { + _mm256_srli_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_srli_epi16&expand=5505) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_mask_srli_epi16(src: __m128i, k: __mmask8, a: __m128i, imm8: i32) -> __m128i { + macro_rules! call { + ($imm8:expr) => { + _mm_srli_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_srli_epi16&expand=5506) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlw, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_maskz_srli_epi16(k: __mmask8, a: __m128i, imm8: i32) -> __m128i { + macro_rules! call { + ($imm8:expr) => { + _mm_srli_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srlv_epi16&expand=5545) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm512_srlv_epi16(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsrlvw(a.as_i16x32(), count.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srlv_epi16&expand=5543) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm512_mask_srlv_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srlv_epi16(a, count).as_i16x32(); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srlv_epi16&expand=5544) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm512_maskz_srlv_epi16(k: __mmask32, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srlv_epi16(a, count).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_srlv_epi16&expand=5542) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm256_srlv_epi16(a: __m256i, count: __m256i) -> __m256i { + transmute(vpsrlvw256(a.as_i16x16(), count.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_srlv_epi16&expand=5540) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm256_mask_srlv_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + count: __m256i, +) -> __m256i { + let shf = _mm256_srlv_epi16(a, count).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_srlv_epi16&expand=5541) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm256_maskz_srlv_epi16(k: __mmask16, a: __m256i, count: __m256i) -> __m256i { + let shf = _mm256_srlv_epi16(a, count).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srlv_epi16&expand=5539) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm_srlv_epi16(a: __m128i, count: __m128i) -> __m128i { + transmute(vpsrlvw128(a.as_i16x8(), count.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_srlv_epi16&expand=5537) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm_mask_srlv_epi16( + src: __m128i, + k: __mmask8, + a: __m128i, + count: __m128i, +) -> __m128i { + let shf = _mm_srlv_epi16(a, count).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_srlv_epi16&expand=5538) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsrlvw))] +pub unsafe fn _mm_maskz_srlv_epi16(k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_srlv_epi16(a, count).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sra_epi16&expand=5398) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsraw))] +pub unsafe fn _mm512_sra_epi16(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsraw(a.as_i16x32(), count.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sra_epi16&expand=5396) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsraw))] +pub unsafe fn _mm512_mask_sra_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sra_epi16(a, count).as_i16x32(); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sra_epi16&expand=5397) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsraw))] +pub unsafe fn _mm512_maskz_sra_epi16(k: __mmask32, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sra_epi16(a, count).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_sra_epi16&expand=5393) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw))] +pub unsafe fn _mm256_mask_sra_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + count: __m128i, +) -> __m256i { + let shf = _mm256_sra_epi16(a, count).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_sra_epi16&expand=5394) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw))] +pub unsafe fn _mm256_maskz_sra_epi16(k: __mmask16, a: __m256i, count: __m128i) -> __m256i { + let shf = _mm256_sra_epi16(a, count).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sra_epi16&expand=5390) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw))] +pub unsafe fn _mm_mask_sra_epi16(src: __m128i, k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_sra_epi16(a, count).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sra_epi16&expand=5391) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw))] +pub unsafe fn _mm_maskz_sra_epi16(k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_sra_epi16(a, count).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srai_epi16&expand=5427) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsraw, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srai_epi16(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpsraiw(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srai_epi16&expand=5425) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsraw, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srai_epi16(src: __m512i, k: __mmask32, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpsraiw(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srai_epi16&expand=5426) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsraw, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srai_epi16(k: __mmask32, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i16x32(); + macro_rules! call { + ($imm8:expr) => { + vpsraiw(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_srai_epi16&expand=5422) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm256_mask_srai_epi16(src: __m256i, k: __mmask16, a: __m256i, imm8: u32) -> __m256i { + macro_rules! call { + ($imm8:expr) => { + _mm256_srai_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_srai_epi16&expand=5423) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm256_maskz_srai_epi16(k: __mmask16, a: __m256i, imm8: u32) -> __m256i { + macro_rules! call { + ($imm8:expr) => { + _mm256_srai_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_srai_epi16&expand=5419) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_mask_srai_epi16(src: __m128i, k: __mmask8, a: __m128i, imm8: u32) -> __m128i { + macro_rules! call { + ($imm8:expr) => { + _mm_srai_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_srai_epi16&expand=5420) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsraw, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_maskz_srai_epi16(k: __mmask8, a: __m128i, imm8: u32) -> __m128i { + macro_rules! call { + ($imm8:expr) => { + _mm_srai_epi16(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srav_epi16&expand=5456) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm512_srav_epi16(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsravw(a.as_i16x32(), count.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srav_epi16&expand=5454) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm512_mask_srav_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srav_epi16(a, count).as_i16x32(); + transmute(simd_select_bitmask(k, shf, src.as_i16x32())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srav_epi16&expand=5455) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm512_maskz_srav_epi16(k: __mmask32, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srav_epi16(a, count).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_srav_epi16&expand=5453) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm256_srav_epi16(a: __m256i, count: __m256i) -> __m256i { + transmute(vpsravw256(a.as_i16x16(), count.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_srav_epi16&expand=5451) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm256_mask_srav_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + count: __m256i, +) -> __m256i { + let shf = _mm256_srav_epi16(a, count).as_i16x16(); + transmute(simd_select_bitmask(k, shf, src.as_i16x16())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_srav_epi16&expand=5452) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm256_maskz_srav_epi16(k: __mmask16, a: __m256i, count: __m256i) -> __m256i { + let shf = _mm256_srav_epi16(a, count).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srav_epi16&expand=5450) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm_srav_epi16(a: __m128i, count: __m128i) -> __m128i { + transmute(vpsravw128(a.as_i16x8(), count.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_srav_epi16&expand=5448) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm_mask_srav_epi16( + src: __m128i, + k: __mmask8, + a: __m128i, + count: __m128i, +) -> __m128i { + let shf = _mm_srav_epi16(a, count).as_i16x8(); + transmute(simd_select_bitmask(k, shf, src.as_i16x8())) +} + +/// Shift packed 16-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_srav_epi16&expand=5449) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpsravw))] +pub unsafe fn _mm_maskz_srav_epi16(k: __mmask8, a: __m128i, count: __m128i) -> __m128i { + let shf = _mm_srav_epi16(a, count).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_epi16&expand=4226) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2w or vpermt2w +pub unsafe fn _mm512_permutex2var_epi16(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { + transmute(vpermi2w(a.as_i16x32(), idx.as_i16x32(), b.as_i16x32())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_epi16&expand=4223) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpermt2w))] +pub unsafe fn _mm512_mask_permutex2var_epi16( + a: __m512i, + k: __mmask32, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi16(a, idx, b).as_i16x32(); + transmute(simd_select_bitmask(k, permute, a.as_i16x32())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_epi16&expand=4225) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2w or vpermt2w +pub unsafe fn _mm512_maskz_permutex2var_epi16( + k: __mmask32, + a: __m512i, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi16(a, idx, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_epi16&expand=4224) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpermi2w))] +pub unsafe fn _mm512_mask2_permutex2var_epi16( + a: __m512i, + idx: __m512i, + k: __mmask32, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi16(a, idx, b).as_i16x32(); + transmute(simd_select_bitmask(k, permute, idx.as_i16x32())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_permutex2var_epi16&expand=4222) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2w or vpermt2w +pub unsafe fn _mm256_permutex2var_epi16(a: __m256i, idx: __m256i, b: __m256i) -> __m256i { + transmute(vpermi2w256(a.as_i16x16(), idx.as_i16x16(), b.as_i16x16())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_permutex2var_epi16&expand=4219) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermt2w))] +pub unsafe fn _mm256_mask_permutex2var_epi16( + a: __m256i, + k: __mmask16, + idx: __m256i, + b: __m256i, +) -> __m256i { + let permute = _mm256_permutex2var_epi16(a, idx, b).as_i16x16(); + transmute(simd_select_bitmask(k, permute, a.as_i16x16())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_permutex2var_epi16&expand=4221) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2w or vpermt2w +pub unsafe fn _mm256_maskz_permutex2var_epi16( + k: __mmask16, + a: __m256i, + idx: __m256i, + b: __m256i, +) -> __m256i { + let permute = _mm256_permutex2var_epi16(a, idx, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask2_permutex2var_epi16&expand=4220) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermi2w))] +pub unsafe fn _mm256_mask2_permutex2var_epi16( + a: __m256i, + idx: __m256i, + k: __mmask16, + b: __m256i, +) -> __m256i { + let permute = _mm256_permutex2var_epi16(a, idx, b).as_i16x16(); + transmute(simd_select_bitmask(k, permute, idx.as_i16x16())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_permutex2var_epi16&expand=4218) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2w or vpermt2w +pub unsafe fn _mm_permutex2var_epi16(a: __m128i, idx: __m128i, b: __m128i) -> __m128i { + transmute(vpermi2w128(a.as_i16x8(), idx.as_i16x8(), b.as_i16x8())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_permutex2var_epi16&expand=4215) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermt2w))] +pub unsafe fn _mm_mask_permutex2var_epi16( + a: __m128i, + k: __mmask8, + idx: __m128i, + b: __m128i, +) -> __m128i { + let permute = _mm_permutex2var_epi16(a, idx, b).as_i16x8(); + transmute(simd_select_bitmask(k, permute, a.as_i16x8())) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_permutex2var_epi16&expand=4217) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2w or vpermt2w +pub unsafe fn _mm_maskz_permutex2var_epi16( + k: __mmask8, + a: __m128i, + idx: __m128i, + b: __m128i, +) -> __m128i { + let permute = _mm_permutex2var_epi16(a, idx, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 16-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask2_permutex2var_epi16&expand=4216) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermi2w))] +pub unsafe fn _mm_mask2_permutex2var_epi16( + a: __m128i, + idx: __m128i, + k: __mmask8, + b: __m128i, +) -> __m128i { + let permute = _mm_permutex2var_epi16(a, idx, b).as_i16x8(); + transmute(simd_select_bitmask(k, permute, idx.as_i16x8())) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_epi16&expand=4295) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm512_permutexvar_epi16(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermw(a.as_i16x32(), idx.as_i16x32())) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_epi16&expand=4293) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm512_mask_permutexvar_epi16( + src: __m512i, + k: __mmask32, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutexvar_epi16(idx, a).as_i16x32(); + transmute(simd_select_bitmask(k, permute, src.as_i16x32())) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_epi16&expand=4294) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm512_maskz_permutexvar_epi16(k: __mmask32, idx: __m512i, a: __m512i) -> __m512i { + let permute = _mm512_permutexvar_epi16(idx, a).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_permutexvar_epi16&expand=4292) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm256_permutexvar_epi16(idx: __m256i, a: __m256i) -> __m256i { + transmute(vpermw256(a.as_i16x16(), idx.as_i16x16())) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_permutexvar_epi16&expand=4290) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm256_mask_permutexvar_epi16( + src: __m256i, + k: __mmask16, + idx: __m256i, + a: __m256i, +) -> __m256i { + let permute = _mm256_permutexvar_epi16(idx, a).as_i16x16(); + transmute(simd_select_bitmask(k, permute, src.as_i16x16())) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_permutexvar_epi16&expand=4291) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm256_maskz_permutexvar_epi16(k: __mmask16, idx: __m256i, a: __m256i) -> __m256i { + let permute = _mm256_permutexvar_epi16(idx, a).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_permutexvar_epi16&expand=4289) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm_permutexvar_epi16(idx: __m128i, a: __m128i) -> __m128i { + transmute(vpermw128(a.as_i16x8(), idx.as_i16x8())) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_permutexvar_epi16&expand=4287) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm_mask_permutexvar_epi16( + src: __m128i, + k: __mmask8, + idx: __m128i, + a: __m128i, +) -> __m128i { + let permute = _mm_permutexvar_epi16(idx, a).as_i16x8(); + transmute(simd_select_bitmask(k, permute, src.as_i16x8())) +} + +/// Shuffle 16-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_permutexvar_epi16&expand=4288) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpermw))] +pub unsafe fn _mm_maskz_permutexvar_epi16(k: __mmask8, idx: __m128i, a: __m128i) -> __m128i { + let permute = _mm_permutexvar_epi16(idx, a).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Blend packed 16-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_epi16&expand=430) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovdqu16))] //should be vpblendmw +pub unsafe fn _mm512_mask_blend_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + transmute(simd_select_bitmask(k, b.as_i16x32(), a.as_i16x32())) +} + +/// Blend packed 16-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_blend_epi16&expand=429) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu16))] //should be vpblendmw +pub unsafe fn _mm256_mask_blend_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + transmute(simd_select_bitmask(k, b.as_i16x16(), a.as_i16x16())) +} + +/// Blend packed 16-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_blend_epi16&expand=427) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu16))] //should be vpblendmw +pub unsafe fn _mm_mask_blend_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + transmute(simd_select_bitmask(k, b.as_i16x8(), a.as_i16x8())) +} + +/// Blend packed 8-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_epi8&expand=441) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovdqu8))] //should be vpblendmb +pub unsafe fn _mm512_mask_blend_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + transmute(simd_select_bitmask(k, b.as_i8x64(), a.as_i8x64())) +} + +/// Blend packed 8-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_blend_epi8&expand=440) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu8))] //should be vpblendmb +pub unsafe fn _mm256_mask_blend_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + transmute(simd_select_bitmask(k, b.as_i8x32(), a.as_i8x32())) +} + +/// Blend packed 8-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_blend_epi8&expand=439) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu8))] //should be vpblendmb +pub unsafe fn _mm_mask_blend_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + transmute(simd_select_bitmask(k, b.as_i8x16(), a.as_i8x16())) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastw_epi16&expand=587) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm512_broadcastw_epi16(a: __m128i) -> __m512i { + let a = _mm512_castsi128_si512(a).as_i16x32(); + let ret: i16x32 = simd_shuffle32( + a, + a, + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + ); + transmute(ret) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastw_epi16&expand=588) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm512_mask_broadcastw_epi16(src: __m512i, k: __mmask32, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastw_epi16(a).as_i16x32(); + transmute(simd_select_bitmask(k, broadcast, src.as_i16x32())) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastw_epi16&expand=589) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm512_maskz_broadcastw_epi16(k: __mmask32, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastw_epi16(a).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_broadcastw_epi16&expand=585) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm256_mask_broadcastw_epi16(src: __m256i, k: __mmask16, a: __m128i) -> __m256i { + let broadcast = _mm256_broadcastw_epi16(a).as_i16x16(); + transmute(simd_select_bitmask(k, broadcast, src.as_i16x16())) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_broadcastw_epi16&expand=586) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm256_maskz_broadcastw_epi16(k: __mmask16, a: __m128i) -> __m256i { + let broadcast = _mm256_broadcastw_epi16(a).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_broadcastw_epi16&expand=582) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm_mask_broadcastw_epi16(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + let broadcast = _mm_broadcastw_epi16(a).as_i16x8(); + transmute(simd_select_bitmask(k, broadcast, src.as_i16x8())) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_broadcastw_epi16&expand=583) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm_maskz_broadcastw_epi16(k: __mmask8, a: __m128i) -> __m128i { + let broadcast = _mm_broadcastw_epi16(a).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the low packed 8-bit integer from a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastb_epi8&expand=536) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm512_broadcastb_epi8(a: __m128i) -> __m512i { + let a = _mm512_castsi128_si512(a).as_i8x64(); + let ret: i8x64 = simd_shuffle64( + a, + a, + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ], + ); + transmute(ret) +} + +/// Broadcast the low packed 8-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastb_epi8&expand=537) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm512_mask_broadcastb_epi8(src: __m512i, k: __mmask64, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastb_epi8(a).as_i8x64(); + transmute(simd_select_bitmask(k, broadcast, src.as_i8x64())) +} + +/// Broadcast the low packed 8-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastb_epi8&expand=538) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm512_maskz_broadcastb_epi8(k: __mmask64, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastb_epi8(a).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the low packed 8-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_broadcastb_epi8&expand=534) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm256_mask_broadcastb_epi8(src: __m256i, k: __mmask32, a: __m128i) -> __m256i { + let broadcast = _mm256_broadcastb_epi8(a).as_i8x32(); + transmute(simd_select_bitmask(k, broadcast, src.as_i8x32())) +} + +/// Broadcast the low packed 8-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_broadcastb_epi8&expand=535) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm256_maskz_broadcastb_epi8(k: __mmask32, a: __m128i) -> __m256i { + let broadcast = _mm256_broadcastb_epi8(a).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the low packed 8-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_broadcastb_epi8&expand=531) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm_mask_broadcastb_epi8(src: __m128i, k: __mmask16, a: __m128i) -> __m128i { + let broadcast = _mm_broadcastb_epi8(a).as_i8x16(); + transmute(simd_select_bitmask(k, broadcast, src.as_i8x16())) +} + +/// Broadcast the low packed 8-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_broadcastb_epi8&expand=532) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm_maskz_broadcastb_epi8(k: __mmask16, a: __m128i) -> __m128i { + let broadcast = _mm_broadcastb_epi8(a).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Unpack and interleave 16-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi16&expand=6012) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpckhwd))] +pub unsafe fn _mm512_unpackhi_epi16(a: __m512i, b: __m512i) -> __m512i { + let a = a.as_i16x32(); + let b = b.as_i16x32(); + #[rustfmt::skip] + let r: i16x32 = simd_shuffle32( + a, + b, + [ + 4, 32 + 4, 5, 32 + 5, + 6, 32 + 6, 7, 32 + 7, + 12, 32 + 12, 13, 32 + 13, + 14, 32 + 14, 15, 32 + 15, + 20, 32 + 20, 21, 32 + 21, + 22, 32 + 22, 23, 32 + 23, + 28, 32 + 28, 29, 32 + 29, + 30, 32 + 30, 31, 32 + 31, + ], + ); + transmute(r) +} + +/// Unpack and interleave 16-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi16&expand=6010) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpckhwd))] +pub unsafe fn _mm512_mask_unpackhi_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let unpackhi = _mm512_unpackhi_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i16x32())) +} + +/// Unpack and interleave 16-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi16&expand=6011) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpckhwd))] +pub unsafe fn _mm512_maskz_unpackhi_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let unpackhi = _mm512_unpackhi_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, unpackhi, zero)) +} + +/// Unpack and interleave 16-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_unpackhi_epi16&expand=6007) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhwd))] +pub unsafe fn _mm256_mask_unpackhi_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let unpackhi = _mm256_unpackhi_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i16x16())) +} + +/// Unpack and interleave 16-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_unpackhi_epi16&expand=6008) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhwd))] +pub unsafe fn _mm256_maskz_unpackhi_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let unpackhi = _mm256_unpackhi_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, unpackhi, zero)) +} + +/// Unpack and interleave 16-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_unpackhi_epi16&expand=6004) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhwd))] +pub unsafe fn _mm_mask_unpackhi_epi16( + src: __m128i, + k: __mmask8, + a: __m128i, + b: __m128i, +) -> __m128i { + let unpackhi = _mm_unpackhi_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i16x8())) +} + +/// Unpack and interleave 16-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_unpackhi_epi16&expand=6005) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhwd))] +pub unsafe fn _mm_maskz_unpackhi_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let unpackhi = _mm_unpackhi_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, unpackhi, zero)) +} + +/// Unpack and interleave 8-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi8&expand=6039) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpckhbw))] +pub unsafe fn _mm512_unpackhi_epi8(a: __m512i, b: __m512i) -> __m512i { + let a = a.as_i8x64(); + let b = b.as_i8x64(); + #[rustfmt::skip] + let r: i8x64 = simd_shuffle64( + a, + b, + [ + 8, 64+8, 9, 64+9, + 10, 64+10, 11, 64+11, + 12, 64+12, 13, 64+13, + 14, 64+14, 15, 64+15, + 24, 64+24, 25, 64+25, + 26, 64+26, 27, 64+27, + 28, 64+28, 29, 64+29, + 30, 64+30, 31, 64+31, + 40, 64+40, 41, 64+41, + 42, 64+42, 43, 64+43, + 44, 64+44, 45, 64+45, + 46, 64+46, 47, 64+47, + 56, 64+56, 57, 64+57, + 58, 64+58, 59, 64+59, + 60, 64+60, 61, 64+61, + 62, 64+62, 63, 64+63, + ], + ); + transmute(r) +} + +/// Unpack and interleave 8-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi8&expand=6037) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpckhbw))] +pub unsafe fn _mm512_mask_unpackhi_epi8( + src: __m512i, + k: __mmask64, + a: __m512i, + b: __m512i, +) -> __m512i { + let unpackhi = _mm512_unpackhi_epi8(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i8x64())) +} + +/// Unpack and interleave 8-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi8&expand=6038) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpckhbw))] +pub unsafe fn _mm512_maskz_unpackhi_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let unpackhi = _mm512_unpackhi_epi8(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, unpackhi, zero)) +} + +/// Unpack and interleave 8-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_unpackhi_epi8&expand=6034) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhbw))] +pub unsafe fn _mm256_mask_unpackhi_epi8( + src: __m256i, + k: __mmask32, + a: __m256i, + b: __m256i, +) -> __m256i { + let unpackhi = _mm256_unpackhi_epi8(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i8x32())) +} + +/// Unpack and interleave 8-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_unpackhi_epi8&expand=6035) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhbw))] +pub unsafe fn _mm256_maskz_unpackhi_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let unpackhi = _mm256_unpackhi_epi8(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, unpackhi, zero)) +} + +/// Unpack and interleave 8-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_unpackhi_epi8&expand=6031) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhbw))] +pub unsafe fn _mm_mask_unpackhi_epi8( + src: __m128i, + k: __mmask16, + a: __m128i, + b: __m128i, +) -> __m128i { + let unpackhi = _mm_unpackhi_epi8(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i8x16())) +} + +/// Unpack and interleave 8-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_unpackhi_epi8&expand=6032) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpckhbw))] +pub unsafe fn _mm_maskz_unpackhi_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let unpackhi = _mm_unpackhi_epi8(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, unpackhi, zero)) +} + +/// Unpack and interleave 16-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_epi16&expand=6069) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpcklwd))] +pub unsafe fn _mm512_unpacklo_epi16(a: __m512i, b: __m512i) -> __m512i { + let a = a.as_i16x32(); + let b = b.as_i16x32(); + #[rustfmt::skip] + let r: i16x32 = simd_shuffle32( + a, + b, + [ + 0, 32+0, 1, 32+1, + 2, 32+2, 3, 32+3, + 8, 32+8, 9, 32+9, + 10, 32+10, 11, 32+11, + 16, 32+16, 17, 32+17, + 18, 32+18, 19, 32+19, + 24, 32+24, 25, 32+25, + 26, 32+26, 27, 32+27 + ], + ); + transmute(r) +} + +/// Unpack and interleave 16-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_epi16&expand=6067) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpcklwd))] +pub unsafe fn _mm512_mask_unpacklo_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, +) -> __m512i { + let unpacklo = _mm512_unpacklo_epi16(a, b).as_i16x32(); + transmute(simd_select_bitmask(k, unpacklo, src.as_i16x32())) +} + +/// Unpack and interleave 16-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_epi16&expand=6068) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpcklwd))] +pub unsafe fn _mm512_maskz_unpacklo_epi16(k: __mmask32, a: __m512i, b: __m512i) -> __m512i { + let unpacklo = _mm512_unpacklo_epi16(a, b).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, unpacklo, zero)) +} + +/// Unpack and interleave 16-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_unpacklo_epi16&expand=6064) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklwd))] +pub unsafe fn _mm256_mask_unpacklo_epi16( + src: __m256i, + k: __mmask16, + a: __m256i, + b: __m256i, +) -> __m256i { + let unpacklo = _mm256_unpacklo_epi16(a, b).as_i16x16(); + transmute(simd_select_bitmask(k, unpacklo, src.as_i16x16())) +} + +/// Unpack and interleave 16-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_unpacklo_epi16&expand=6065) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklwd))] +pub unsafe fn _mm256_maskz_unpacklo_epi16(k: __mmask16, a: __m256i, b: __m256i) -> __m256i { + let unpacklo = _mm256_unpacklo_epi16(a, b).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, unpacklo, zero)) +} + +/// Unpack and interleave 16-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_unpacklo_epi16&expand=6061) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklwd))] +pub unsafe fn _mm_mask_unpacklo_epi16( + src: __m128i, + k: __mmask8, + a: __m128i, + b: __m128i, +) -> __m128i { + let unpacklo = _mm_unpacklo_epi16(a, b).as_i16x8(); + transmute(simd_select_bitmask(k, unpacklo, src.as_i16x8())) +} + +/// Unpack and interleave 16-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_unpacklo_epi16&expand=6062) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklwd))] +pub unsafe fn _mm_maskz_unpacklo_epi16(k: __mmask8, a: __m128i, b: __m128i) -> __m128i { + let unpacklo = _mm_unpacklo_epi16(a, b).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, unpacklo, zero)) +} + +/// Unpack and interleave 8-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_epi8&expand=6096) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpcklbw))] +pub unsafe fn _mm512_unpacklo_epi8(a: __m512i, b: __m512i) -> __m512i { + let a = a.as_i8x64(); + let b = b.as_i8x64(); + #[rustfmt::skip] + let r: i8x64 = simd_shuffle64( + a, + b, + [ + 0, 64+0, 1, 64+1, + 2, 64+2, 3, 64+3, + 4, 64+4, 5, 64+5, + 6, 64+6, 7, 64+7, + 16, 64+16, 17, 64+17, + 18, 64+18, 19, 64+19, + 20, 64+20, 21, 64+21, + 22, 64+22, 23, 64+23, + 32, 64+32, 33, 64+33, + 34, 64+34, 35, 64+35, + 36, 64+36, 37, 64+37, + 38, 64+38, 39, 64+39, + 48, 64+48, 49, 64+49, + 50, 64+50, 51, 64+51, + 52, 64+52, 53, 64+53, + 54, 64+54, 55, 64+55, + ], + ); + transmute(r) +} + +/// Unpack and interleave 8-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_epi8&expand=6094) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpcklbw))] +pub unsafe fn _mm512_mask_unpacklo_epi8( + src: __m512i, + k: __mmask64, + a: __m512i, + b: __m512i, +) -> __m512i { + let unpacklo = _mm512_unpacklo_epi8(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, unpacklo, src.as_i8x64())) +} + +/// Unpack and interleave 8-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_epi8&expand=6095) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpunpcklbw))] +pub unsafe fn _mm512_maskz_unpacklo_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let unpacklo = _mm512_unpacklo_epi8(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, unpacklo, zero)) +} + +/// Unpack and interleave 8-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_unpacklo_epi8&expand=6091) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklbw))] +pub unsafe fn _mm256_mask_unpacklo_epi8( + src: __m256i, + k: __mmask32, + a: __m256i, + b: __m256i, +) -> __m256i { + let unpacklo = _mm256_unpacklo_epi8(a, b).as_i8x32(); + transmute(simd_select_bitmask(k, unpacklo, src.as_i8x32())) +} + +/// Unpack and interleave 8-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_unpacklo_epi8&expand=6092) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklbw))] +pub unsafe fn _mm256_maskz_unpacklo_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let unpacklo = _mm256_unpacklo_epi8(a, b).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, unpacklo, zero)) +} + +/// Unpack and interleave 8-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_unpacklo_epi8&expand=6088) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklbw))] +pub unsafe fn _mm_mask_unpacklo_epi8( + src: __m128i, + k: __mmask16, + a: __m128i, + b: __m128i, +) -> __m128i { + let unpacklo = _mm_unpacklo_epi8(a, b).as_i8x16(); + transmute(simd_select_bitmask(k, unpacklo, src.as_i8x16())) +} + +/// Unpack and interleave 8-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_unpacklo_epi8&expand=6089) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpunpcklbw))] +pub unsafe fn _mm_maskz_unpacklo_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let unpacklo = _mm_unpacklo_epi8(a, b).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, unpacklo, zero)) +} + +/// Move packed 16-bit integers from a into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi16&expand=3795) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovdqu16))] +pub unsafe fn _mm512_mask_mov_epi16(src: __m512i, k: __mmask32, a: __m512i) -> __m512i { + let mov = a.as_i16x32(); + transmute(simd_select_bitmask(k, mov, src.as_i16x32())) +} + +/// Move packed 16-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi16&expand=3796) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovdqu16))] +pub unsafe fn _mm512_maskz_mov_epi16(k: __mmask32, a: __m512i) -> __m512i { + let mov = a.as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed 16-bit integers from a into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_mov_epi16&expand=3793) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu16))] +pub unsafe fn _mm256_mask_mov_epi16(src: __m256i, k: __mmask16, a: __m256i) -> __m256i { + let mov = a.as_i16x16(); + transmute(simd_select_bitmask(k, mov, src.as_i16x16())) +} + +/// Move packed 16-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_mov_epi16&expand=3794) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu16))] +pub unsafe fn _mm256_maskz_mov_epi16(k: __mmask16, a: __m256i) -> __m256i { + let mov = a.as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed 16-bit integers from a into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mov_epi16&expand=3791) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu16))] +pub unsafe fn _mm_mask_mov_epi16(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + let mov = a.as_i16x8(); + transmute(simd_select_bitmask(k, mov, src.as_i16x8())) +} + +/// Move packed 16-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mov_epi16&expand=3792) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu16))] +pub unsafe fn _mm_maskz_mov_epi16(k: __mmask8, a: __m128i) -> __m128i { + let mov = a.as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed 8-bit integers from a into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi8&expand=3813) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovdqu8))] +pub unsafe fn _mm512_mask_mov_epi8(src: __m512i, k: __mmask64, a: __m512i) -> __m512i { + let mov = a.as_i8x64(); + transmute(simd_select_bitmask(k, mov, src.as_i8x64())) +} + +/// Move packed 8-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi8&expand=3814) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vmovdqu8))] +pub unsafe fn _mm512_maskz_mov_epi8(k: __mmask64, a: __m512i) -> __m512i { + let mov = a.as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed 8-bit integers from a into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_mov_epi8&expand=3811) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu8))] +pub unsafe fn _mm256_mask_mov_epi8(src: __m256i, k: __mmask32, a: __m256i) -> __m256i { + let mov = a.as_i8x32(); + transmute(simd_select_bitmask(k, mov, src.as_i8x32())) +} + +/// Move packed 8-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_mov_epi8&expand=3812) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu8))] +pub unsafe fn _mm256_maskz_mov_epi8(k: __mmask32, a: __m256i) -> __m256i { + let mov = a.as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed 8-bit integers from a into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mov_epi8&expand=3809) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu8))] +pub unsafe fn _mm_mask_mov_epi8(src: __m128i, k: __mmask16, a: __m128i) -> __m128i { + let mov = a.as_i8x16(); + transmute(simd_select_bitmask(k, mov, src.as_i8x16())) +} + +/// Move packed 8-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mov_epi8&expand=3810) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vmovdqu8))] +pub unsafe fn _mm_maskz_mov_epi8(k: __mmask16, a: __m128i) -> __m128i { + let mov = a.as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Broadcast 16-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi16&expand=4942) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm512_mask_set1_epi16(src: __m512i, k: __mmask32, a: i16) -> __m512i { + let r = _mm512_set1_epi16(a).as_i16x32(); + transmute(simd_select_bitmask(k, r, src.as_i16x32())) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi16&expand=4943) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm512_maskz_set1_epi16(k: __mmask32, a: i16) -> __m512i { + let r = _mm512_set1_epi16(a).as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Broadcast 16-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_set1_epi16&expand=4939) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm256_mask_set1_epi16(src: __m256i, k: __mmask16, a: i16) -> __m256i { + let r = _mm256_set1_epi16(a).as_i16x16(); + transmute(simd_select_bitmask(k, r, src.as_i16x16())) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_set1_epi16&expand=4940) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm256_maskz_set1_epi16(k: __mmask16, a: i16) -> __m256i { + let r = _mm256_set1_epi16(a).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Broadcast 16-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_set1_epi16&expand=4936) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm_mask_set1_epi16(src: __m128i, k: __mmask8, a: i16) -> __m128i { + let r = _mm_set1_epi16(a).as_i16x8(); + transmute(simd_select_bitmask(k, r, src.as_i16x8())) +} + +/// Broadcast the low packed 16-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_set1_epi16&expand=4937) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastw))] +pub unsafe fn _mm_maskz_set1_epi16(k: __mmask8, a: i16) -> __m128i { + let r = _mm_set1_epi16(a).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Broadcast 8-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi8&expand=4970) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm512_mask_set1_epi8(src: __m512i, k: __mmask64, a: i8) -> __m512i { + let r = _mm512_set1_epi8(a).as_i8x64(); + transmute(simd_select_bitmask(k, r, src.as_i8x64())) +} + +/// Broadcast 8-bit integer a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi8&expand=4971) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm512_maskz_set1_epi8(k: __mmask64, a: i8) -> __m512i { + let r = _mm512_set1_epi8(a).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Broadcast 8-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_set1_epi8&expand=4967) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm256_mask_set1_epi8(src: __m256i, k: __mmask32, a: i8) -> __m256i { + let r = _mm256_set1_epi8(a).as_i8x32(); + transmute(simd_select_bitmask(k, r, src.as_i8x32())) +} + +/// Broadcast 8-bit integer a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_set1_epi8&expand=4968) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm256_maskz_set1_epi8(k: __mmask32, a: i8) -> __m256i { + let r = _mm256_set1_epi8(a).as_i8x32(); + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Broadcast 8-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_set1_epi8&expand=4964) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm_mask_set1_epi8(src: __m128i, k: __mmask16, a: i8) -> __m128i { + let r = _mm_set1_epi8(a).as_i8x16(); + transmute(simd_select_bitmask(k, r, src.as_i8x16())) +} + +/// Broadcast 8-bit integer a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_set1_epi8&expand=4965) +#[inline] +#[target_feature(enable = "avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcastb))] +pub unsafe fn _mm_maskz_set1_epi8(k: __mmask16, a: i8) -> __m128i { + let r = _mm_set1_epi8(a).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Shuffle 16-bit integers in the low 64 bits of 128-bit lanes of a using the control in imm8. Store the results in the low 64 bits of 128-bit lanes of dst, with the high 64 bits of 128-bit lanes being copied from from a to dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shufflelo_epi16&expand=5221) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshuflw, imm8 = 0))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_shufflelo_epi16(a: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i16x32(); + macro_rules! shuffle_done { + ($x01: expr, $x23: expr, $x45: expr, $x67: expr) => { + #[rustfmt::skip] + simd_shuffle32(a, a, [ + 0+$x01, 0+$x23, 0+$x45, 0+$x67, 4, 5, 6, 7, 8+$x01, 8+$x23, 8+$x45, 8+$x67, 12, 13, 14, 15, + 16+$x01, 16+$x23, 16+$x45, 16+$x67, 20, 21, 22, 23, 24+$x01, 24+$x23, 24+$x45, 24+$x67, 28, 29, 30, 31, + ]) + }; + } + macro_rules! shuffle_x67 { + ($x01:expr, $x23:expr, $x45:expr) => { + match (imm8 >> 6) & 0b11 { + 0b00 => shuffle_done!($x01, $x23, $x45, 0), + 0b01 => shuffle_done!($x01, $x23, $x45, 1), + 0b10 => shuffle_done!($x01, $x23, $x45, 2), + _ => shuffle_done!($x01, $x23, $x45, 3), + } + }; + } + macro_rules! shuffle_x45 { + ($x01:expr, $x23:expr) => { + match (imm8 >> 4) & 0b11 { + 0b00 => shuffle_x67!($x01, $x23, 0), + 0b01 => shuffle_x67!($x01, $x23, 1), + 0b10 => shuffle_x67!($x01, $x23, 2), + _ => shuffle_x67!($x01, $x23, 3), + } + }; + } + macro_rules! shuffle_x23 { + ($x01:expr) => { + match (imm8 >> 2) & 0b11 { + 0b00 => shuffle_x45!($x01, 0), + 0b01 => shuffle_x45!($x01, 1), + 0b10 => shuffle_x45!($x01, 2), + _ => shuffle_x45!($x01, 3), + } + }; + } + let r: i16x32 = match imm8 & 0b11 { + 0b00 => shuffle_x23!(0), + 0b01 => shuffle_x23!(1), + 0b10 => shuffle_x23!(2), + _ => shuffle_x23!(3), + }; + transmute(r) +} + +/// Shuffle 16-bit integers in the low 64 bits of 128-bit lanes of a using the control in imm8. Store the results in the low 64 bits of 128-bit lanes of dst, with the high 64 bits of 128-bit lanes being copied from from a to dst, using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shufflelo_epi16&expand=5219) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshuflw, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_shufflelo_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i16x32(); + macro_rules! shuffle_done { + ($x01: expr, $x23: expr, $x45: expr, $x67: expr) => { + #[rustfmt::skip] + simd_shuffle32(a, a, [ + 0+$x01, 0+$x23, 0+$x45, 0+$x67, 4, 5, 6, 7, 8+$x01, 8+$x23, 8+$x45, 8+$x67, 12, 13, 14, 15, + 16+$x01, 16+$x23, 16+$x45, 16+$x67, 20, 21, 22, 23, 24+$x01, 24+$x23, 24+$x45, 24+$x67, 28, 29, 30, 31, + ]) + }; + } + macro_rules! shuffle_x67 { + ($x01:expr, $x23:expr, $x45:expr) => { + match (imm8 >> 6) & 0b11 { + 0b00 => shuffle_done!($x01, $x23, $x45, 0), + 0b01 => shuffle_done!($x01, $x23, $x45, 1), + 0b10 => shuffle_done!($x01, $x23, $x45, 2), + _ => shuffle_done!($x01, $x23, $x45, 3), + } + }; + } + macro_rules! shuffle_x45 { + ($x01:expr, $x23:expr) => { + match (imm8 >> 4) & 0b11 { + 0b00 => shuffle_x67!($x01, $x23, 0), + 0b01 => shuffle_x67!($x01, $x23, 1), + 0b10 => shuffle_x67!($x01, $x23, 2), + _ => shuffle_x67!($x01, $x23, 3), + } + }; + } + macro_rules! shuffle_x23 { + ($x01:expr) => { + match (imm8 >> 2) & 0b11 { + 0b00 => shuffle_x45!($x01, 0), + 0b01 => shuffle_x45!($x01, 1), + 0b10 => shuffle_x45!($x01, 2), + _ => shuffle_x45!($x01, 3), + } + }; + } + let r: i16x32 = match imm8 & 0b11 { + 0b00 => shuffle_x23!(0), + 0b01 => shuffle_x23!(1), + 0b10 => shuffle_x23!(2), + _ => shuffle_x23!(3), + }; + transmute(simd_select_bitmask(k, r, src.as_i16x32())) +} + +/// Shuffle 16-bit integers in the low 64 bits of 128-bit lanes of a using the control in imm8. Store the results in the low 64 bits of 128-bit lanes of dst, with the high 64 bits of 128-bit lanes being copied from from a to dst, using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shufflelo_epi16&expand=5220) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshuflw, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_shufflelo_epi16(k: __mmask32, a: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i16x32(); + macro_rules! shuffle_done { + ($x01: expr, $x23: expr, $x45: expr, $x67: expr) => { + #[rustfmt::skip] + simd_shuffle32(a, a, [ + 0+$x01, 0+$x23, 0+$x45, 0+$x67, 4, 5, 6, 7, 8+$x01, 8+$x23, 8+$x45, 8+$x67, 12, 13, 14, 15, + 16+$x01, 16+$x23, 16+$x45, 16+$x67, 20, 21, 22, 23, 24+$x01, 24+$x23, 24+$x45, 24+$x67, 28, 29, 30, 31, + ]) + }; + } + macro_rules! shuffle_x67 { + ($x01:expr, $x23:expr, $x45:expr) => { + match (imm8 >> 6) & 0b11 { + 0b00 => shuffle_done!($x01, $x23, $x45, 0), + 0b01 => shuffle_done!($x01, $x23, $x45, 1), + 0b10 => shuffle_done!($x01, $x23, $x45, 2), + _ => shuffle_done!($x01, $x23, $x45, 3), + } + }; + } + macro_rules! shuffle_x45 { + ($x01:expr, $x23:expr) => { + match (imm8 >> 4) & 0b11 { + 0b00 => shuffle_x67!($x01, $x23, 0), + 0b01 => shuffle_x67!($x01, $x23, 1), + 0b10 => shuffle_x67!($x01, $x23, 2), + _ => shuffle_x67!($x01, $x23, 3), + } + }; + } + macro_rules! shuffle_x23 { + ($x01:expr) => { + match (imm8 >> 2) & 0b11 { + 0b00 => shuffle_x45!($x01, 0), + 0b01 => shuffle_x45!($x01, 1), + 0b10 => shuffle_x45!($x01, 2), + _ => shuffle_x45!($x01, 3), + } + }; + } + let r: i16x32 = match imm8 & 0b11 { + 0b00 => shuffle_x23!(0), + 0b01 => shuffle_x23!(1), + 0b10 => shuffle_x23!(2), + _ => shuffle_x23!(3), + }; + transmute(simd_select_bitmask( + k, + r, + _mm512_setzero_si512().as_i16x32(), + )) +} + +/// Shuffle 16-bit integers in the high 64 bits of 128-bit lanes of a using the control in imm8. Store the results in the high 64 bits of 128-bit lanes of dst, with the low 64 bits of 128-bit lanes being copied from from a to dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shufflehi_epi16&expand=5212) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshufhw, imm8 = 0))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_shufflehi_epi16(a: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i16x32(); + macro_rules! shuffle_done { + ($x01: expr, $x23: expr, $x45: expr, $x67: expr) => { + #[rustfmt::skip] + simd_shuffle32(a, a, [ + 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67, 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67, + 16, 17, 18, 19, 20+$x01, 20+$x23, 20+$x45, 20+$x67, 24, 25, 26, 27, 28+$x01, 28+$x23, 28+$x45, 28+$x67, + ]) + }; + } + macro_rules! shuffle_x67 { + ($x01:expr, $x23:expr, $x45:expr) => { + match (imm8 >> 6) & 0b11 { + 0b00 => shuffle_done!($x01, $x23, $x45, 0), + 0b01 => shuffle_done!($x01, $x23, $x45, 1), + 0b10 => shuffle_done!($x01, $x23, $x45, 2), + _ => shuffle_done!($x01, $x23, $x45, 3), + } + }; + } + macro_rules! shuffle_x45 { + ($x01:expr, $x23:expr) => { + match (imm8 >> 4) & 0b11 { + 0b00 => shuffle_x67!($x01, $x23, 0), + 0b01 => shuffle_x67!($x01, $x23, 1), + 0b10 => shuffle_x67!($x01, $x23, 2), + _ => shuffle_x67!($x01, $x23, 3), + } + }; + } + macro_rules! shuffle_x23 { + ($x01:expr) => { + match (imm8 >> 2) & 0b11 { + 0b00 => shuffle_x45!($x01, 0), + 0b01 => shuffle_x45!($x01, 1), + 0b10 => shuffle_x45!($x01, 2), + _ => shuffle_x45!($x01, 3), + } + }; + } + let r: i16x32 = match imm8 & 0b11 { + 0b00 => shuffle_x23!(0), + 0b01 => shuffle_x23!(1), + 0b10 => shuffle_x23!(2), + _ => shuffle_x23!(3), + }; + transmute(r) +} + +/// Shuffle 16-bit integers in the high 64 bits of 128-bit lanes of a using the control in imm8. Store the results in the high 64 bits of 128-bit lanes of dst, with the low 64 bits of 128-bit lanes being copied from from a to dst, using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shufflehi_epi16&expand=5210) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshufhw, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_shufflehi_epi16( + src: __m512i, + k: __mmask32, + a: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i16x32(); + macro_rules! shuffle_done { + ($x01: expr, $x23: expr, $x45: expr, $x67: expr) => { + #[rustfmt::skip] + simd_shuffle32(a, a, [ + 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67, 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67, + 16, 17, 18, 19, 20+$x01, 20+$x23, 20+$x45, 20+$x67, 24, 25, 26, 27, 28+$x01, 28+$x23, 28+$x45, 28+$x67, + ]) + }; + } + macro_rules! shuffle_x67 { + ($x01:expr, $x23:expr, $x45:expr) => { + match (imm8 >> 6) & 0b11 { + 0b00 => shuffle_done!($x01, $x23, $x45, 0), + 0b01 => shuffle_done!($x01, $x23, $x45, 1), + 0b10 => shuffle_done!($x01, $x23, $x45, 2), + _ => shuffle_done!($x01, $x23, $x45, 3), + } + }; + } + macro_rules! shuffle_x45 { + ($x01:expr, $x23:expr) => { + match (imm8 >> 4) & 0b11 { + 0b00 => shuffle_x67!($x01, $x23, 0), + 0b01 => shuffle_x67!($x01, $x23, 1), + 0b10 => shuffle_x67!($x01, $x23, 2), + _ => shuffle_x67!($x01, $x23, 3), + } + }; + } + macro_rules! shuffle_x23 { + ($x01:expr) => { + match (imm8 >> 2) & 0b11 { + 0b00 => shuffle_x45!($x01, 0), + 0b01 => shuffle_x45!($x01, 1), + 0b10 => shuffle_x45!($x01, 2), + _ => shuffle_x45!($x01, 3), + } + }; + } + let r: i16x32 = match imm8 & 0b11 { + 0b00 => shuffle_x23!(0), + 0b01 => shuffle_x23!(1), + 0b10 => shuffle_x23!(2), + _ => shuffle_x23!(3), + }; + transmute(simd_select_bitmask(k, r, src.as_i16x32())) +} + +/// Shuffle 16-bit integers in the high 64 bits of 128-bit lanes of a using the control in imm8. Store the results in the high 64 bits of 128-bit lanes of dst, with the low 64 bits of 128-bit lanes being copied from from a to dst, using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shufflehi_epi16&expand=5211) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshufhw, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_shufflehi_epi16(k: __mmask32, a: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i16x32(); + macro_rules! shuffle_done { + ($x01: expr, $x23: expr, $x45: expr, $x67: expr) => { + #[rustfmt::skip] + simd_shuffle32(a, a, [ + 0, 1, 2, 3, 4+$x01, 4+$x23, 4+$x45, 4+$x67, 8, 9, 10, 11, 12+$x01, 12+$x23, 12+$x45, 12+$x67, + 16, 17, 18, 19, 20+$x01, 20+$x23, 20+$x45, 20+$x67, 24, 25, 26, 27, 28+$x01, 28+$x23, 28+$x45, 28+$x67, + ]) + }; + } + macro_rules! shuffle_x67 { + ($x01:expr, $x23:expr, $x45:expr) => { + match (imm8 >> 6) & 0b11 { + 0b00 => shuffle_done!($x01, $x23, $x45, 0), + 0b01 => shuffle_done!($x01, $x23, $x45, 1), + 0b10 => shuffle_done!($x01, $x23, $x45, 2), + _ => shuffle_done!($x01, $x23, $x45, 3), + } + }; + } + macro_rules! shuffle_x45 { + ($x01:expr, $x23:expr) => { + match (imm8 >> 4) & 0b11 { + 0b00 => shuffle_x67!($x01, $x23, 0), + 0b01 => shuffle_x67!($x01, $x23, 1), + 0b10 => shuffle_x67!($x01, $x23, 2), + _ => shuffle_x67!($x01, $x23, 3), + } + }; + } + macro_rules! shuffle_x23 { + ($x01:expr) => { + match (imm8 >> 2) & 0b11 { + 0b00 => shuffle_x45!($x01, 0), + 0b01 => shuffle_x45!($x01, 1), + 0b10 => shuffle_x45!($x01, 2), + _ => shuffle_x45!($x01, 3), + } + }; + } + let r: i16x32 = match imm8 & 0b11 { + 0b00 => shuffle_x23!(0), + 0b01 => shuffle_x23!(1), + 0b10 => shuffle_x23!(2), + _ => shuffle_x23!(3), + }; + transmute(simd_select_bitmask( + k, + r, + _mm512_setzero_si512().as_i16x32(), + )) +} + +/// Shuffle packed 8-bit integers in a according to shuffle control mask in the corresponding 8-bit element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_epi8&expand=5159) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshufb))] +pub unsafe fn _mm512_shuffle_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpshufb(a.as_i8x64(), b.as_i8x64())) +} + +/// Shuffle 8-bit integers in a within 128-bit lanes using the control in the corresponding 8-bit element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_epi8&expand=5157) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshufb))] +pub unsafe fn _mm512_mask_shuffle_epi8( + src: __m512i, + k: __mmask64, + a: __m512i, + b: __m512i, +) -> __m512i { + let shuffle = _mm512_shuffle_epi8(a, b).as_i8x64(); + transmute(simd_select_bitmask(k, shuffle, src.as_i8x64())) +} + +/// Shuffle packed 8-bit integers in a according to shuffle control mask in the corresponding 8-bit element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_epi8&expand=5158) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpshufb))] +pub unsafe fn _mm512_maskz_shuffle_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let shuffle = _mm512_shuffle_epi8(a, b).as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Compute the bitwise AND of packed 16-bit integers in a and b, producing intermediate 16-bit values, and set the corresponding bit in result mask k if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi16_mask&expand=5884) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestmw))] +pub unsafe fn _mm512_test_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpneq_epi16_mask(and, zero) +} + +/// Compute the bitwise AND of packed 16-bit integers in a and b, producing intermediate 16-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi16_mask&expand=5883) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestmw))] +pub unsafe fn _mm512_mask_test_epi16_mask(k: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpneq_epi16_mask(k, and, zero) +} + +/// Compute the bitwise AND of packed 8-bit integers in a and b, producing intermediate 8-bit values, and set the corresponding bit in result mask k if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi8_mask&expand=5902) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestmb))] +pub unsafe fn _mm512_test_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpneq_epi8_mask(and, zero) +} + +/// Compute the bitwise AND of packed 8-bit integers in a and b, producing intermediate 8-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi8_mask&expand=5901) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestmb))] +pub unsafe fn _mm512_mask_test_epi8_mask(k: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpneq_epi8_mask(k, and, zero) +} + +/// Compute the bitwise NAND of packed 16-bit integers in a and b, producing intermediate 16-bit values, and set the corresponding bit in result mask k if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi16_mask&expand=5915) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestnmw))] +pub unsafe fn _mm512_testn_epi16_mask(a: __m512i, b: __m512i) -> __mmask32 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpeq_epi16_mask(and, zero) +} + +/// Compute the bitwise NAND of packed 16-bit integers in a and b, producing intermediate 16-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi16&expand=5914) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestnmw))] +pub unsafe fn _mm512_mask_testn_epi16_mask(k: __mmask32, a: __m512i, b: __m512i) -> __mmask32 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpeq_epi16_mask(k, and, zero) +} + +/// Compute the bitwise NAND of packed 8-bit integers in a and b, producing intermediate 8-bit values, and set the corresponding bit in result mask k if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi8_mask&expand=5933) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestnmb))] +pub unsafe fn _mm512_testn_epi8_mask(a: __m512i, b: __m512i) -> __mmask64 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpeq_epi8_mask(and, zero) +} + +/// Compute the bitwise NAND of packed 8-bit integers in a and b, producing intermediate 8-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi8_mask&expand=5932) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vptestnmb))] +pub unsafe fn _mm512_mask_testn_epi8_mask(k: __mmask64, a: __m512i, b: __m512i) -> __mmask64 { + let and = _mm512_and_si512(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpeq_epi8_mask(k, and, zero) +} + +/// Store 64-bit mask from a into memory. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_store_mask64&expand=5578) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] //should be kmovq +pub unsafe fn _store_mask64(mem_addr: *mut u64, a: __mmask64) { + ptr::write(mem_addr as *mut __mmask64, a); +} + +/// Store 32-bit mask from a into memory. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_store_mask32&expand=5577) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] //should be kmovd +pub unsafe fn _store_mask32(mem_addr: *mut u32, a: __mmask32) { + ptr::write(mem_addr as *mut __mmask32, a); +} + +/// Load 64-bit mask from memory into k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_load_mask64&expand=3318) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] //should be kmovq +pub unsafe fn _load_mask64(mem_addr: *const u64) -> __mmask64 { + ptr::read(mem_addr as *const __mmask64) +} + +/// Load 32-bit mask from memory into k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_load_mask32&expand=3317) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] //should be kmovd +pub unsafe fn _load_mask32(mem_addr: *const u32) -> __mmask32 { + ptr::read(mem_addr as *const __mmask32) +} + +/// Compute the absolute differences of packed unsigned 8-bit integers in a and b, then horizontally sum each consecutive 8 differences to produce eight unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low 16 bits of 64-bit elements in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sad_epu8&expand=4855) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpsadbw))] +pub unsafe fn _mm512_sad_epu8(a: __m512i, b: __m512i) -> __m512i { + transmute(vpsadbw(a.as_u8x64(), b.as_u8x64())) +} + +/// Compute the sum of absolute differences (SADs) of quadruplets of unsigned 8-bit integers in a compared to those in b, and store the 16-bit results in dst. Four SADs are performed on four 8-bit quadruplets for each 64-bit lane. The first two SADs use the lower 8-bit quadruplet of the lane from a, and the last two SADs use the uppper 8-bit quadruplet of the lane from a. Quadruplets from b are selected from within 128-bit lanes according to the control in imm8, and each SAD in each 64-bit lane uses the selected quadruplet at 8-bit offsets. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_dbsad_epu8&expand=2114) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vdbpsadbw, imm8 = 0))] +pub unsafe fn _mm512_dbsad_epu8(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + let a = a.as_u8x64(); + let b = b.as_u8x64(); + macro_rules! call { + ($imm8:expr) => { + vdbpsadbw(a, b, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Compute the sum of absolute differences (SADs) of quadruplets of unsigned 8-bit integers in a compared to those in b, and store the 16-bit results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). Four SADs are performed on four 8-bit quadruplets for each 64-bit lane. The first two SADs use the lower 8-bit quadruplet of the lane from a, and the last two SADs use the uppper 8-bit quadruplet of the lane from a. Quadruplets from b are selected from within 128-bit lanes according to the control in imm8, and each SAD in each 64-bit lane uses the selected quadruplet at 8-bit offsets. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_dbsad_epu8&expand=2115) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(4)] +#[cfg_attr(test, assert_instr(vdbpsadbw, imm8 = 0))] +pub unsafe fn _mm512_mask_dbsad_epu8( + src: __m512i, + k: __mmask32, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let a = a.as_u8x64(); + let b = b.as_u8x64(); + macro_rules! call { + ($imm8:expr) => { + vdbpsadbw(a, b, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, r, src.as_u16x32())) +} + +/// Compute the sum of absolute differences (SADs) of quadruplets of unsigned 8-bit integers in a compared to those in b, and store the 16-bit results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). Four SADs are performed on four 8-bit quadruplets for each 64-bit lane. The first two SADs use the lower 8-bit quadruplet of the lane from a, and the last two SADs use the uppper 8-bit quadruplet of the lane from a. Quadruplets from b are selected from within 128-bit lanes according to the control in imm8, and each SAD in each 64-bit lane uses the selected quadruplet at 8-bit offsets. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_dbsad_epu8&expand=2116) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vdbpsadbw, imm8 = 0))] +pub unsafe fn _mm512_maskz_dbsad_epu8(k: __mmask32, a: __m512i, b: __m512i, imm8: i32) -> __m512i { + let a = a.as_u8x64(); + let b = b.as_u8x64(); + macro_rules! call { + ($imm8:expr) => { + vdbpsadbw(a, b, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask( + k, + r, + _mm512_setzero_si512().as_u16x32(), + )) +} + +/// Set each bit of mask register k based on the most significant bit of the corresponding packed 16-bit integer in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movepi16_mask&expand=3873) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] // should be vpmovw2m but msvc does not generate it +pub unsafe fn _mm512_movepi16_mask(a: __m512i) -> __mmask32 { + let filter = _mm512_set1_epi16(1 << 15); + let a = _mm512_and_si512(a, filter); + _mm512_cmpeq_epi16_mask(a, filter) +} + +/// Set each bit of mask register k based on the most significant bit of the corresponding packed 8-bit integer in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movepi8_mask&expand=3883) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] // should be vpmovb2m but msvc does not generate it +pub unsafe fn _mm512_movepi8_mask(a: __m512i) -> __mmask64 { + let filter = _mm512_set1_epi8(1 << 7); + let a = _mm512_and_si512(a, filter); + _mm512_cmpeq_epi8_mask(a, filter) +} + +/// Set each packed 16-bit integer in dst to all ones or all zeros based on the value of the corresponding bit in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movm_epi16&expand=3886) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovm2w))] +pub unsafe fn _mm512_movm_epi16(k: __mmask32) -> __m512i { + let one = _mm512_set1_epi16( + 1 << 15 + | 1 << 14 + | 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + ) + .as_i16x32(); + let zero = _mm512_setzero_si512().as_i16x32(); + transmute(simd_select_bitmask(k, one, zero)) +} + +/// Set each packed 8-bit integer in dst to all ones or all zeros based on the value of the corresponding bit in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movm_epi8&expand=3895) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovm2b))] +pub unsafe fn _mm512_movm_epi8(k: __mmask64) -> __m512i { + let one = + _mm512_set1_epi8(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0) + .as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask(k, one, zero)) +} + +/// Add 32-bit masks in a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kadd_mask32&expand=3207) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kaddd +pub unsafe fn _kadd_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { + transmute(a + b) +} + +/// Add 64-bit masks in a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kadd_mask64&expand=3208) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kaddq +pub unsafe fn _kadd_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { + transmute(a + b) +} + +/// Compute the bitwise AND of 32-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kand_mask32&expand=3213) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandd +pub unsafe fn _kand_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { + transmute(a & b) +} + +/// Compute the bitwise AND of 64-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kand_mask64&expand=3214) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandq +pub unsafe fn _kand_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { + transmute(a & b) +} + +/// Compute the bitwise NOT of 32-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_knot_mask32&expand=3234) +#[inline] +#[target_feature(enable = "avx512bw")] +pub unsafe fn _knot_mask32(a: __mmask32) -> __mmask32 { + transmute(a ^ 0b11111111_11111111_11111111_11111111) +} + +/// Compute the bitwise NOT of 64-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_knot_mask64&expand=3235) +#[inline] +#[target_feature(enable = "avx512bw")] +pub unsafe fn _knot_mask64(a: __mmask64) -> __mmask64 { + transmute(a ^ 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111) +} + +/// Compute the bitwise NOT of 32-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kandn_mask32&expand=3219) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandnd +pub unsafe fn _kandn_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { + transmute(_knot_mask32(a) & b) +} + +/// Compute the bitwise NOT of 64-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kandn_mask64&expand=3220) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandnq +pub unsafe fn _kandn_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { + transmute(_knot_mask64(a) & b) +} + +/// Compute the bitwise OR of 32-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kor_mask32&expand=3240) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(or))] // generate normal and code instead of kord +pub unsafe fn _kor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { + transmute(a | b) +} + +/// Compute the bitwise OR of 64-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kor_mask64&expand=3241) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(or))] // generate normal and code instead of korq +pub unsafe fn _kor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { + transmute(a | b) +} + +/// Compute the bitwise XOR of 32-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxor_mask32&expand=3292) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxord +pub unsafe fn _kxor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { + transmute(a ^ b) +} + +/// Compute the bitwise XOR of 64-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxor_mask64&expand=3293) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxorq +pub unsafe fn _kxor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { + transmute(a ^ b) +} + +/// Compute the bitwise XNOR of 32-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxnor_mask32&expand=3286) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxnord +pub unsafe fn _kxnor_mask32(a: __mmask32, b: __mmask32) -> __mmask32 { + transmute(_knot_mask32(a ^ b)) +} + +/// Compute the bitwise XNOR of 64-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_kxnor_mask64&expand=3287) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kxnorq +pub unsafe fn _kxnor_mask64(a: __mmask64, b: __mmask64) -> __mmask64 { + transmute(_knot_mask64(a ^ b)) +} + +/// Convert packed 16-bit integers in a to packed 8-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi8&expand=1407) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovwb))] +pub unsafe fn _mm512_cvtepi16_epi8(a: __m512i) -> __m256i { + let a = a.as_i16x32(); + transmute::(simd_cast(a)) +} + +/// Convert packed 16-bit integers in a to packed 8-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi8&expand=1408) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovwb))] +pub unsafe fn _mm512_mask_cvtepi16_epi8(src: __m256i, k: __mmask32, a: __m512i) -> __m256i { + let convert = _mm512_cvtepi16_epi8(a).as_i8x32(); + transmute(simd_select_bitmask(k, convert, src.as_i8x32())) +} + +/// Convert packed 16-bit integers in a to packed 8-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi8&expand=1409) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovwb))] +pub unsafe fn _mm512_maskz_cvtepi16_epi8(k: __mmask32, a: __m512i) -> __m256i { + let convert = _mm512_cvtepi16_epi8(a).as_i8x32(); + transmute(simd_select_bitmask( + k, + convert, + _mm256_setzero_si256().as_i8x32(), + )) +} + +/// Convert packed signed 16-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi16_epi8&expand=1807) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovswb))] +pub unsafe fn _mm512_cvtsepi16_epi8(a: __m512i) -> __m256i { + transmute(vpmovswb( + a.as_i16x32(), + _mm256_setzero_si256().as_i8x32(), + 0b11111111_11111111_11111111_11111111, + )) +} + +/// Convert packed signed 16-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi16_epi8&expand=1808) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovswb))] +pub unsafe fn _mm512_mask_cvtsepi16_epi8(src: __m256i, k: __mmask32, a: __m512i) -> __m256i { + transmute(vpmovswb(a.as_i16x32(), src.as_i8x32(), k)) +} + +/// Convert packed signed 16-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi16_epi8&expand=1809) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovswb))] +pub unsafe fn _mm512_maskz_cvtsepi16_epi8(k: __mmask32, a: __m512i) -> __m256i { + transmute(vpmovswb( + a.as_i16x32(), + _mm256_setzero_si256().as_i8x32(), + k, + )) +} + +/// Convert packed unsigned 16-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi16_epi8&expand=2042) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovuswb))] +pub unsafe fn _mm512_cvtusepi16_epi8(a: __m512i) -> __m256i { + transmute(vpmovuswb( + a.as_u16x32(), + _mm256_setzero_si256().as_u8x32(), + 0b11111111_11111111_11111111_11111111, + )) +} + +/// Convert packed unsigned 16-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi16_epi8&expand=2043) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovuswb))] +pub unsafe fn _mm512_mask_cvtusepi16_epi8(src: __m256i, k: __mmask32, a: __m512i) -> __m256i { + transmute(vpmovuswb(a.as_u16x32(), src.as_u8x32(), k)) +} + +/// Convert packed unsigned 16-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi16_epi8&expand=2044) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovuswb))] +pub unsafe fn _mm512_maskz_cvtusepi16_epi8(k: __mmask32, a: __m512i) -> __m256i { + transmute(vpmovuswb( + a.as_u16x32(), + _mm256_setzero_si256().as_u8x32(), + k, + )) +} + +/// Sign extend packed 8-bit integers in a to packed 16-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi16&expand=1526) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovsxbw))] +pub unsafe fn _mm512_cvtepi8_epi16(a: __m256i) -> __m512i { + let a = a.as_i8x32(); + transmute::(simd_cast(a)) +} + +/// Sign extend packed 8-bit integers in a to packed 16-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi16&expand=1527) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovsxbw))] +pub unsafe fn _mm512_mask_cvtepi8_epi16(src: __m512i, k: __mmask32, a: __m256i) -> __m512i { + let convert = _mm512_cvtepi8_epi16(a).as_i16x32(); + transmute(simd_select_bitmask(k, convert, src.as_i16x32())) +} + +/// Sign extend packed 8-bit integers in a to packed 16-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi16&expand=1528) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovsxbw))] +pub unsafe fn _mm512_maskz_cvtepi8_epi16(k: __mmask32, a: __m256i) -> __m512i { + let convert = _mm512_cvtepi8_epi16(a).as_i16x32(); + transmute(simd_select_bitmask( + k, + convert, + _mm512_setzero_si512().as_i16x32(), + )) +} + +/// Zero extend packed unsigned 8-bit integers in a to packed 16-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi16&expand=1612) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovzxbw))] +pub unsafe fn _mm512_cvtepu8_epi16(a: __m256i) -> __m512i { + let a = a.as_u8x32(); + transmute::(simd_cast(a)) +} + +/// Zero extend packed unsigned 8-bit integers in a to packed 16-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi16&expand=1613) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovzxbw))] +pub unsafe fn _mm512_mask_cvtepu8_epi16(src: __m512i, k: __mmask32, a: __m256i) -> __m512i { + let convert = _mm512_cvtepu8_epi16(a).as_i16x32(); + transmute(simd_select_bitmask(k, convert, src.as_i16x32())) +} + +/// Zero extend packed unsigned 8-bit integers in a to packed 16-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi16&expand=1614) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpmovzxbw))] +pub unsafe fn _mm512_maskz_cvtepu8_epi16(k: __mmask32, a: __m256i) -> __m512i { + let convert = _mm512_cvtepu8_epi16(a).as_i16x32(); + transmute(simd_select_bitmask( + k, + convert, + _mm512_setzero_si512().as_i16x32(), + )) +} + +/// Shift 128-bit lanes in a left by imm8 bytes while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_bslli_epi128&expand=591) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(1)] +#[cfg_attr(test, assert_instr(vpslldq, imm8 = 3))] +pub unsafe fn _mm512_bslli_epi128(a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + #[rustfmt::skip] + macro_rules! call { + ($imm8:expr) => { + simd_shuffle64 ( + zero, + a, + [ + 64 - $imm8, 65 - $imm8, 66 - $imm8, 67 - $imm8, 68 - $imm8, 69 - $imm8, 70 - $imm8, 71 - $imm8, + 72 - $imm8, 73 - $imm8, 74 - $imm8, 75 - $imm8, 76 - $imm8, 77 - $imm8, 78 - $imm8, 79 - $imm8, + 80 - ($imm8+16), 81 - ($imm8+16), 82 - ($imm8+16), 83 - ($imm8+16), 84 - ($imm8+16), 85 - ($imm8+16), 86 - ($imm8+16), 87 - ($imm8+16), + 88 - ($imm8+16), 89 - ($imm8+16), 90 - ($imm8+16), 91 - ($imm8+16), 92 - ($imm8+16), 93 - ($imm8+16), 94 - ($imm8+16), 95 - ($imm8+16), + 96 - ($imm8+32), 97 - ($imm8+32), 98 - ($imm8+32), 99 - ($imm8+32), 100 - ($imm8+32), 101 - ($imm8+32), 102 - ($imm8+32), 103 - ($imm8+32), + 104 - ($imm8+32), 105 - ($imm8+32), 106 - ($imm8+32), 107 - ($imm8+32), 108 - ($imm8+32), 109 - ($imm8+32), 110 - ($imm8+32), 111 - ($imm8+32), + 112 - ($imm8+48), 113 - ($imm8+48), 114 - ($imm8+48), 115 - ($imm8+48), 116 - ($imm8+48), 117 - ($imm8+48), 118 - ($imm8+48), 119 - ($imm8+48), + 120 - ($imm8+48), 121 - ($imm8+48), 122 - ($imm8+48), 123 - ($imm8+48), 124 - ($imm8+48), 125 - ($imm8+48), 126 - ($imm8+48), 127 - ($imm8+48), + ], + ) + }; + } + let r: i8x64 = match imm8 { + 0 => call!(0), + 1 => call!(1), + 2 => call!(2), + 3 => call!(3), + 4 => call!(4), + 5 => call!(5), + 6 => call!(6), + 7 => call!(7), + 8 => call!(8), + 9 => call!(9), + 10 => call!(10), + 11 => call!(11), + 12 => call!(12), + 13 => call!(13), + 14 => call!(14), + 15 => call!(15), + _ => call!(16), + }; + transmute(r) +} + +/// Shift 128-bit lanes in a right by imm8 bytes while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_bsrli_epi128&expand=594) +#[inline] +#[target_feature(enable = "avx512bw")] +#[rustc_args_required_const(1)] +#[cfg_attr(test, assert_instr(vpsrldq, imm8 = 3))] +pub unsafe fn _mm512_bsrli_epi128(a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i8x64(); + let zero = _mm512_setzero_si512().as_i8x64(); + #[rustfmt::skip] + macro_rules! call { + ($imm8:expr) => { + simd_shuffle64 ( + a, + zero, + [ + 0 + ($imm8+48), 1 + ($imm8+48), 2 + ($imm8+48), 3 + ($imm8+48), 4 + ($imm8+48), 5 + ($imm8+48), 6 + ($imm8+48), 7 + ($imm8+48), + 8 + ($imm8+48), 9 + ($imm8+48), 10 + ($imm8+48), 11 + ($imm8+48), 12 + ($imm8+48), 13 + ($imm8+48), 14 + ($imm8+48), 15 + ($imm8+48), + 16 + ($imm8+32), 17 + ($imm8+32), 18 + ($imm8+32), 19 + ($imm8+32), 20 + ($imm8+32), 21 + ($imm8+32), 22 + ($imm8+32), 23 + ($imm8+32), + 24 + ($imm8+32), 25 + ($imm8+32), 26 + ($imm8+32), 27 + ($imm8+32), 28 + ($imm8+32), 29 + ($imm8+32), 30 + ($imm8+32), 31 + ($imm8+32), + 32 + ($imm8+16), 33 + ($imm8+16), 34 + ($imm8+16), 35 + ($imm8+16), 36 + ($imm8+16), 37 + ($imm8+16), 38 + ($imm8+16), 39 + ($imm8+16), + 40 + ($imm8+16), 41 + ($imm8+16), 42 + ($imm8+16), 43 + ($imm8+16), 44 + ($imm8+16), 45 + ($imm8+16), 46 + ($imm8+16), 47 + ($imm8+16), + 48 + $imm8, 49 + $imm8, 50 + $imm8, 51 + $imm8, 52 + $imm8, 53 + $imm8, 54 + $imm8, 55 + $imm8, + 56 + $imm8, 57 + $imm8, 58 + $imm8, 59 + $imm8, 60 + $imm8, 61 + $imm8, 62 + $imm8, 63 + $imm8, + ], + ) + }; + } + let r: i8x64 = match imm8 { + 0 => call!(0), + 1 => call!(1), + 2 => call!(2), + 3 => call!(3), + 4 => call!(4), + 5 => call!(5), + 6 => call!(6), + 7 => call!(7), + 8 => call!(8), + 9 => call!(9), + 10 => call!(10), + 11 => call!(11), + 12 => call!(12), + 13 => call!(13), + 14 => call!(14), + 15 => call!(15), + _ => call!(16), + }; + transmute(r) +} + +/// Concatenate pairs of 16-byte blocks in a and b into a 32-byte temporary result, shift the result right by imm8 bytes, and store the low 16 bytes in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi8&expand=263) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpalignr, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_alignr_epi8(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + // If palignr is shifting the pair of vectors more than the size of two + // lanes, emit zero. + if imm8 > 32 { + return _mm512_set1_epi8(0); + } + // If palignr is shifting the pair of input vectors more than one lane, + // but less than two lanes, convert to shifting in zeroes. + let (a, b, imm8) = if imm8 > 16 { + (_mm512_set1_epi8(0), a, imm8 - 16) + } else { + (a, b, imm8) + }; + let a = a.as_i8x64(); + let b = b.as_i8x64(); + #[rustfmt::skip] + macro_rules! shuffle { + ($imm8:expr) => { + simd_shuffle64( + b, + a, + [ + 0 + ($imm8+48), 1 + ($imm8+48), 2 + ($imm8+48), 3 + ($imm8+48), 4 + ($imm8+48), 5 + ($imm8+48), 6 + ($imm8+48), 7 + ($imm8+48), + 8 + ($imm8+48), 9 + ($imm8+48), 10 + ($imm8+48), 11 + ($imm8+48), 12 + ($imm8+48), 13 + ($imm8+48), 14 + ($imm8+48), 15 + ($imm8+48), + 16 + ($imm8+32), 17 + ($imm8+32), 18 + ($imm8+32), 19 + ($imm8+32), 20 + ($imm8+32), 21 + ($imm8+32), 22 + ($imm8+32), 23 + ($imm8+32), + 24 + ($imm8+32), 25 + ($imm8+32), 26 + ($imm8+32), 27 + ($imm8+32), 28 + ($imm8+32), 29 + ($imm8+32), 30 + ($imm8+32), 31 + ($imm8+32), + 32 + ($imm8+16), 33 + ($imm8+16), 34 + ($imm8+16), 35 + ($imm8+16), 36 + ($imm8+16), 37 + ($imm8+16), 38 + ($imm8+16), 39 + ($imm8+16), + 40 + ($imm8+16), 41 + ($imm8+16), 42 + ($imm8+16), 43 + ($imm8+16), 44 + ($imm8+16), 45 + ($imm8+16), 46 + ($imm8+16), 47 + ($imm8+16), + 48 + $imm8, 49 + $imm8, 50 + $imm8, 51 + $imm8, 52 + $imm8, 53 + $imm8, 54 + $imm8, 55 + $imm8, + 56 + $imm8, 57 + $imm8, 58 + $imm8, 59 + $imm8, 60 + $imm8, 61 + $imm8, 62 + $imm8, 63 + $imm8, + ], + ) + }; + } + let r: i8x64 = match imm8 { + 0 => shuffle!(0), + 1 => shuffle!(1), + 2 => shuffle!(2), + 3 => shuffle!(3), + 4 => shuffle!(4), + 5 => shuffle!(5), + 6 => shuffle!(6), + 7 => shuffle!(7), + 8 => shuffle!(8), + 9 => shuffle!(9), + 10 => shuffle!(10), + 11 => shuffle!(11), + 12 => shuffle!(12), + 13 => shuffle!(13), + 14 => shuffle!(14), + 15 => shuffle!(15), + _ => shuffle!(16), + }; + transmute(r) +} + +/// Concatenate pairs of 16-byte blocks in a and b into a 32-byte temporary result, shift the result right by imm8 bytes, and store the low 16 bytes in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi8&expand=264) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpalignr, imm8 = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_alignr_epi8( + src: __m512i, + k: __mmask64, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + // If palignr is shifting the pair of vectors more than the size of two + // lanes, emit zero. + if imm8 > 32 { + return _mm512_set1_epi8(0); + } + // If palignr is shifting the pair of input vectors more than one lane, + // but less than two lanes, convert to shifting in zeroes. + let (a, b, imm8) = if imm8 > 16 { + (_mm512_set1_epi8(0), a, imm8 - 16) + } else { + (a, b, imm8) + }; + let a = a.as_i8x64(); + let b = b.as_i8x64(); + #[rustfmt::skip] + macro_rules! shuffle { + ($imm8:expr) => { + simd_shuffle64( + b, + a, + [ + 0 + ($imm8+48), 1 + ($imm8+48), 2 + ($imm8+48), 3 + ($imm8+48), 4 + ($imm8+48), 5 + ($imm8+48), 6 + ($imm8+48), 7 + ($imm8+48), + 8 + ($imm8+48), 9 + ($imm8+48), 10 + ($imm8+48), 11 + ($imm8+48), 12 + ($imm8+48), 13 + ($imm8+48), 14 + ($imm8+48), 15 + ($imm8+48), + 16 + ($imm8+32), 17 + ($imm8+32), 18 + ($imm8+32), 19 + ($imm8+32), 20 + ($imm8+32), 21 + ($imm8+32), 22 + ($imm8+32), 23 + ($imm8+32), + 24 + ($imm8+32), 25 + ($imm8+32), 26 + ($imm8+32), 27 + ($imm8+32), 28 + ($imm8+32), 29 + ($imm8+32), 30 + ($imm8+32), 31 + ($imm8+32), + 32 + ($imm8+16), 33 + ($imm8+16), 34 + ($imm8+16), 35 + ($imm8+16), 36 + ($imm8+16), 37 + ($imm8+16), 38 + ($imm8+16), 39 + ($imm8+16), + 40 + ($imm8+16), 41 + ($imm8+16), 42 + ($imm8+16), 43 + ($imm8+16), 44 + ($imm8+16), 45 + ($imm8+16), 46 + ($imm8+16), 47 + ($imm8+16), + 48 + $imm8, 49 + $imm8, 50 + $imm8, 51 + $imm8, 52 + $imm8, 53 + $imm8, 54 + $imm8, 55 + $imm8, + 56 + $imm8, 57 + $imm8, 58 + $imm8, 59 + $imm8, 60 + $imm8, 61 + $imm8, 62 + $imm8, 63 + $imm8, + ], + ) + }; + } + let r: i8x64 = match imm8 { + 0 => shuffle!(0), + 1 => shuffle!(1), + 2 => shuffle!(2), + 3 => shuffle!(3), + 4 => shuffle!(4), + 5 => shuffle!(5), + 6 => shuffle!(6), + 7 => shuffle!(7), + 8 => shuffle!(8), + 9 => shuffle!(9), + 10 => shuffle!(10), + 11 => shuffle!(11), + 12 => shuffle!(12), + 13 => shuffle!(13), + 14 => shuffle!(14), + 15 => shuffle!(15), + _ => shuffle!(16), + }; + transmute(simd_select_bitmask(k, r, src.as_i8x64())) +} + +/// Concatenate pairs of 16-byte blocks in a and b into a 32-byte temporary result, shift the result right by imm8 bytes, and store the low 16 bytes in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi8&expand=265) +#[inline] +#[target_feature(enable = "avx512bw")] +#[cfg_attr(test, assert_instr(vpalignr, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_alignr_epi8(k: __mmask64, a: __m512i, b: __m512i, imm8: i32) -> __m512i { + // If palignr is shifting the pair of vectors more than the size of two + // lanes, emit zero. + if imm8 > 32 { + return _mm512_set1_epi8(0); + } + // If palignr is shifting the pair of input vectors more than one lane, + // but less than two lanes, convert to shifting in zeroes. + let (a, b, imm8) = if imm8 > 16 { + (_mm512_set1_epi8(0), a, imm8 - 16) + } else { + (a, b, imm8) + }; + let a = a.as_i8x64(); + let b = b.as_i8x64(); + #[rustfmt::skip] + macro_rules! shuffle { + ($imm8:expr) => { + simd_shuffle64( + b, + a, + [ + 0 + ($imm8+48), 1 + ($imm8+48), 2 + ($imm8+48), 3 + ($imm8+48), 4 + ($imm8+48), 5 + ($imm8+48), 6 + ($imm8+48), 7 + ($imm8+48), + 8 + ($imm8+48), 9 + ($imm8+48), 10 + ($imm8+48), 11 + ($imm8+48), 12 + ($imm8+48), 13 + ($imm8+48), 14 + ($imm8+48), 15 + ($imm8+48), + 16 + ($imm8+32), 17 + ($imm8+32), 18 + ($imm8+32), 19 + ($imm8+32), 20 + ($imm8+32), 21 + ($imm8+32), 22 + ($imm8+32), 23 + ($imm8+32), + 24 + ($imm8+32), 25 + ($imm8+32), 26 + ($imm8+32), 27 + ($imm8+32), 28 + ($imm8+32), 29 + ($imm8+32), 30 + ($imm8+32), 31 + ($imm8+32), + 32 + ($imm8+16), 33 + ($imm8+16), 34 + ($imm8+16), 35 + ($imm8+16), 36 + ($imm8+16), 37 + ($imm8+16), 38 + ($imm8+16), 39 + ($imm8+16), + 40 + ($imm8+16), 41 + ($imm8+16), 42 + ($imm8+16), 43 + ($imm8+16), 44 + ($imm8+16), 45 + ($imm8+16), 46 + ($imm8+16), 47 + ($imm8+16), + 48 + $imm8, 49 + $imm8, 50 + $imm8, 51 + $imm8, 52 + $imm8, 53 + $imm8, 54 + $imm8, 55 + $imm8, + 56 + $imm8, 57 + $imm8, 58 + $imm8, 59 + $imm8, 60 + $imm8, 61 + $imm8, 62 + $imm8, 63 + $imm8, + ], + ) + }; + } + let r: i8x64 = match imm8 { + 0 => shuffle!(0), + 1 => shuffle!(1), + 2 => shuffle!(2), + 3 => shuffle!(3), + 4 => shuffle!(4), + 5 => shuffle!(5), + 6 => shuffle!(6), + 7 => shuffle!(7), + 8 => shuffle!(8), + 9 => shuffle!(9), + 10 => shuffle!(10), + 11 => shuffle!(11), + 12 => shuffle!(12), + 13 => shuffle!(13), + 14 => shuffle!(14), + 15 => shuffle!(15), + _ => shuffle!(16), + }; + transmute(simd_select_bitmask(k, r, _mm512_setzero_si512().as_i8x64())) +} + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.avx512.mask.paddus.w.512"] + fn vpaddusw(a: u16x32, b: u16x32, src: u16x32, mask: u32) -> u16x32; + #[link_name = "llvm.x86.avx512.mask.paddus.w.256"] + fn vpaddusw256(a: u16x16, b: u16x16, src: u16x16, mask: u16) -> u16x16; + #[link_name = "llvm.x86.avx512.mask.paddus.w.128"] + fn vpaddusw128(a: u16x8, b: u16x8, src: u16x8, mask: u8) -> u16x8; + + #[link_name = "llvm.x86.avx512.mask.paddus.b.512"] + fn vpaddusb(a: u8x64, b: u8x64, src: u8x64, mask: u64) -> u8x64; + #[link_name = "llvm.x86.avx512.mask.paddus.b.256"] + fn vpaddusb256(a: u8x32, b: u8x32, src: u8x32, mask: u32) -> u8x32; + #[link_name = "llvm.x86.avx512.mask.paddus.b.128"] + fn vpaddusb128(a: u8x16, b: u8x16, src: u8x16, mask: u16) -> u8x16; + + #[link_name = "llvm.x86.avx512.mask.padds.w.512"] + fn vpaddsw(a: i16x32, b: i16x32, src: i16x32, mask: u32) -> i16x32; + #[link_name = "llvm.x86.avx512.mask.padds.w.256"] + fn vpaddsw256(a: i16x16, b: i16x16, src: i16x16, mask: u16) -> i16x16; + #[link_name = "llvm.x86.avx512.mask.padds.w.128"] + fn vpaddsw128(a: i16x8, b: i16x8, src: i16x8, mask: u8) -> i16x8; + + #[link_name = "llvm.x86.avx512.mask.padds.b.512"] + fn vpaddsb(a: i8x64, b: i8x64, src: i8x64, mask: u64) -> i8x64; + #[link_name = "llvm.x86.avx512.mask.padds.b.256"] + fn vpaddsb256(a: i8x32, b: i8x32, src: i8x32, mask: u32) -> i8x32; + #[link_name = "llvm.x86.avx512.mask.padds.b.128"] + fn vpaddsb128(a: i8x16, b: i8x16, src: i8x16, mask: u16) -> i8x16; + + #[link_name = "llvm.x86.avx512.mask.psubus.w.512"] + fn vpsubusw(a: u16x32, b: u16x32, src: u16x32, mask: u32) -> u16x32; + #[link_name = "llvm.x86.avx512.mask.psubus.w.256"] + fn vpsubusw256(a: u16x16, b: u16x16, src: u16x16, mask: u16) -> u16x16; + #[link_name = "llvm.x86.avx512.mask.psubus.w.128"] + fn vpsubusw128(a: u16x8, b: u16x8, src: u16x8, mask: u8) -> u16x8; + + #[link_name = "llvm.x86.avx512.mask.psubus.b.512"] + fn vpsubusb(a: u8x64, b: u8x64, src: u8x64, mask: u64) -> u8x64; + #[link_name = "llvm.x86.avx512.mask.psubus.b.256"] + fn vpsubusb256(a: u8x32, b: u8x32, src: u8x32, mask: u32) -> u8x32; + #[link_name = "llvm.x86.avx512.mask.psubus.b.128"] + fn vpsubusb128(a: u8x16, b: u8x16, src: u8x16, mask: u16) -> u8x16; + + #[link_name = "llvm.x86.avx512.mask.psubs.w.512"] + fn vpsubsw(a: i16x32, b: i16x32, src: i16x32, mask: u32) -> i16x32; + #[link_name = "llvm.x86.avx512.mask.psubs.w.256"] + fn vpsubsw256(a: i16x16, b: i16x16, src: i16x16, mask: u16) -> i16x16; + #[link_name = "llvm.x86.avx512.mask.psubs.w.128"] + fn vpsubsw128(a: i16x8, b: i16x8, src: i16x8, mask: u8) -> i16x8; + + #[link_name = "llvm.x86.avx512.mask.psubs.b.512"] + fn vpsubsb(a: i8x64, b: i8x64, src: i8x64, mask: u64) -> i8x64; + #[link_name = "llvm.x86.avx512.mask.psubs.b.256"] + fn vpsubsb256(a: i8x32, b: i8x32, src: i8x32, mask: u32) -> i8x32; + #[link_name = "llvm.x86.avx512.mask.psubs.b.128"] + fn vpsubsb128(a: i8x16, b: i8x16, src: i8x16, mask: u16) -> i8x16; + + #[link_name = "llvm.x86.avx512.pmulhu.w.512"] + fn vpmulhuw(a: u16x32, b: u16x32) -> u16x32; + #[link_name = "llvm.x86.avx512.pmulh.w.512"] + fn vpmulhw(a: i16x32, b: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.pmul.hr.sw.512"] + fn vpmulhrsw(a: i16x32, b: i16x32) -> i16x32; + + #[link_name = "llvm.x86.avx512.mask.ucmp.w.512"] + fn vpcmpuw(a: u16x32, b: u16x32, op: i32, mask: u32) -> u32; + #[link_name = "llvm.x86.avx512.mask.ucmp.b.512"] + fn vpcmpub(a: u8x64, b: u8x64, op: i32, mask: u64) -> u64; + #[link_name = "llvm.x86.avx512.mask.cmp.w.512"] + fn vpcmpw(a: i16x32, b: i16x32, op: i32, mask: u32) -> u32; + #[link_name = "llvm.x86.avx512.mask.cmp.b.512"] + fn vpcmpb(a: i8x64, b: i8x64, op: i32, mask: u64) -> u64; + + #[link_name = "llvm.x86.avx512.mask.pmaxu.w.512"] + fn vpmaxuw(a: u16x32, b: u16x32) -> u16x32; + #[link_name = "llvm.x86.avx512.mask.pmaxu.b.512"] + fn vpmaxub(a: u8x64, b: u8x64) -> u8x64; + #[link_name = "llvm.x86.avx512.mask.pmaxs.w.512"] + fn vpmaxsw(a: i16x32, b: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.mask.pmaxs.b.512"] + fn vpmaxsb(a: i8x64, b: i8x64) -> i8x64; + + #[link_name = "llvm.x86.avx512.mask.pminu.w.512"] + fn vpminuw(a: u16x32, b: u16x32) -> u16x32; + #[link_name = "llvm.x86.avx512.mask.pminu.b.512"] + fn vpminub(a: u8x64, b: u8x64) -> u8x64; + #[link_name = "llvm.x86.avx512.mask.pmins.w.512"] + fn vpminsw(a: i16x32, b: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.mask.pmins.b.512"] + fn vpminsb(a: i8x64, b: i8x64) -> i8x64; + + #[link_name = "llvm.x86.avx512.pmaddw.d.512"] + fn vpmaddwd(a: i16x32, b: i16x32) -> i32x16; + #[link_name = "llvm.x86.avx512.pmaddubs.w.512"] + fn vpmaddubsw(a: i8x64, b: i8x64) -> i16x32; + + #[link_name = "llvm.x86.avx512.packssdw.512"] + fn vpackssdw(a: i32x16, b: i32x16) -> i16x32; + #[link_name = "llvm.x86.avx512.packsswb.512"] + fn vpacksswb(a: i16x32, b: i16x32) -> i8x64; + #[link_name = "llvm.x86.avx512.packusdw.512"] + fn vpackusdw(a: i32x16, b: i32x16) -> u16x32; + #[link_name = "llvm.x86.avx512.packuswb.512"] + fn vpackuswb(a: i16x32, b: i16x32) -> u8x64; + + #[link_name = "llvm.x86.avx512.pavg.w.512"] + fn vpavgw(a: u16x32, b: u16x32) -> u16x32; + #[link_name = "llvm.x86.avx512.pavg.b.512"] + fn vpavgb(a: u8x64, b: u8x64) -> u8x64; + + #[link_name = "llvm.x86.avx512.psll.w.512"] + fn vpsllw(a: i16x32, count: i16x8) -> i16x32; + #[link_name = "llvm.x86.avx512.pslli.w.512"] + fn vpslliw(a: i16x32, imm8: u32) -> i16x32; + + #[link_name = "llvm.x86.avx512.psllv.w.512"] + fn vpsllvw(a: i16x32, b: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.psllv.w.256"] + fn vpsllvw256(a: i16x16, b: i16x16) -> i16x16; + #[link_name = "llvm.x86.avx512.psllv.w.128"] + fn vpsllvw128(a: i16x8, b: i16x8) -> i16x8; + + #[link_name = "llvm.x86.avx512.psrl.w.512"] + fn vpsrlw(a: i16x32, count: i16x8) -> i16x32; + #[link_name = "llvm.x86.avx512.psrli.w.512"] + fn vpsrliw(a: i16x32, imm8: u32) -> i16x32; + + #[link_name = "llvm.x86.avx512.psrlv.w.512"] + fn vpsrlvw(a: i16x32, b: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.psrlv.w.256"] + fn vpsrlvw256(a: i16x16, b: i16x16) -> i16x16; + #[link_name = "llvm.x86.avx512.psrlv.w.128"] + fn vpsrlvw128(a: i16x8, b: i16x8) -> i16x8; + + #[link_name = "llvm.x86.avx512.psra.w.512"] + fn vpsraw(a: i16x32, count: i16x8) -> i16x32; + #[link_name = "llvm.x86.avx512.psrai.w.512"] + fn vpsraiw(a: i16x32, imm8: u32) -> i16x32; + + #[link_name = "llvm.x86.avx512.psrav.w.512"] + fn vpsravw(a: i16x32, count: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.psrav.w.256"] + fn vpsravw256(a: i16x16, count: i16x16) -> i16x16; + #[link_name = "llvm.x86.avx512.psrav.w.128"] + fn vpsravw128(a: i16x8, count: i16x8) -> i16x8; + + #[link_name = "llvm.x86.avx512.vpermi2var.hi.512"] + fn vpermi2w(a: i16x32, idx: i16x32, b: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.vpermi2var.hi.256"] + fn vpermi2w256(a: i16x16, idx: i16x16, b: i16x16) -> i16x16; + #[link_name = "llvm.x86.avx512.vpermi2var.hi.128"] + fn vpermi2w128(a: i16x8, idx: i16x8, b: i16x8) -> i16x8; + + #[link_name = "llvm.x86.avx512.permvar.hi.512"] + fn vpermw(a: i16x32, idx: i16x32) -> i16x32; + #[link_name = "llvm.x86.avx512.permvar.hi.256"] + fn vpermw256(a: i16x16, idx: i16x16) -> i16x16; + #[link_name = "llvm.x86.avx512.permvar.hi.128"] + fn vpermw128(a: i16x8, idx: i16x8) -> i16x8; + + #[link_name = "llvm.x86.avx512.pshuf.b.512"] + fn vpshufb(a: i8x64, b: i8x64) -> i8x64; + + #[link_name = "llvm.x86.avx512.psad.bw.512"] + fn vpsadbw(a: u8x64, b: u8x64) -> u64x8; + #[link_name = "llvm.x86.avx512.dbpsadbw.512"] + fn vdbpsadbw(a: u8x64, b: u8x64, imm8: i32) -> u16x32; + + #[link_name = "llvm.x86.avx512.mask.pmovs.wb.512"] + fn vpmovswb(a: i16x32, src: i8x32, mask: u32) -> i8x32; + #[link_name = "llvm.x86.avx512.mask.pmovus.wb.512"] + fn vpmovuswb(a: u16x32, src: u8x32, mask: u32) -> u8x32; +} + +#[cfg(test)] +mod tests { + + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + use crate::hint::black_box; + use crate::mem::{self}; + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_abs_epi16() { + let a = _mm512_set1_epi16(-1); + let r = _mm512_abs_epi16(a); + let e = _mm512_set1_epi16(1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_abs_epi16() { + let a = _mm512_set1_epi16(-1); + let r = _mm512_mask_abs_epi16(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_abs_epi16(a, 0b00000000_11111111_00000000_11111111, a); + #[rustfmt::skip] + let e = _mm512_set_epi16(-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); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_abs_epi16() { + let a = _mm512_set1_epi16(-1); + let r = _mm512_maskz_abs_epi16(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_abs_epi16(0b00000000_11111111_00000000_11111111, a); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_abs_epi16() { + let a = _mm256_set1_epi16(-1); + let r = _mm256_mask_abs_epi16(a, 0, a); + assert_eq_m256i(r, a); + let r = _mm256_mask_abs_epi16(a, 0b00000000_11111111, a); + let e = _mm256_set_epi16(-1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_abs_epi16() { + let a = _mm256_set1_epi16(-1); + let r = _mm256_maskz_abs_epi16(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_abs_epi16(0b00000000_11111111, a); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_abs_epi16() { + let a = _mm_set1_epi16(-1); + let r = _mm_mask_abs_epi16(a, 0, a); + assert_eq_m128i(r, a); + let r = _mm_mask_abs_epi16(a, 0b00001111, a); + let e = _mm_set_epi16(-1, -1, -1, -1, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_abs_epi16() { + let a = _mm_set1_epi16(-1); + let r = _mm_maskz_abs_epi16(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_abs_epi16(0b00001111, a); + let e = _mm_set_epi16(0, 0, 0, 0, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_abs_epi8() { + let a = _mm512_set1_epi8(-1); + let r = _mm512_abs_epi8(a); + let e = _mm512_set1_epi8(1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_abs_epi8() { + let a = _mm512_set1_epi8(-1); + let r = _mm512_mask_abs_epi8(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_abs_epi8( + a, + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(-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); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_abs_epi8() { + let a = _mm512_set1_epi8(-1); + let r = _mm512_maskz_abs_epi8(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_abs_epi8( + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_abs_epi8() { + let a = _mm256_set1_epi8(-1); + let r = _mm256_mask_abs_epi8(a, 0, a); + assert_eq_m256i(r, a); + let r = _mm256_mask_abs_epi8(a, 0b00000000_11111111_00000000_11111111, a); + #[rustfmt::skip] + let e = _mm256_set_epi8(-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); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_abs_epi8() { + let a = _mm256_set1_epi8(-1); + let r = _mm256_maskz_abs_epi8(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_abs_epi8(0b00000000_11111111_00000000_11111111, a); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_abs_epi8() { + let a = _mm_set1_epi8(-1); + let r = _mm_mask_abs_epi8(a, 0, a); + assert_eq_m128i(r, a); + let r = _mm_mask_abs_epi8(a, 0b00000000_11111111, a); + let e = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_abs_epi8() { + let a = _mm_set1_epi8(-1); + let r = _mm_maskz_abs_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_abs_epi8(0b00000000_11111111, a); + #[rustfmt::skip] + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_add_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(2); + let r = _mm512_add_epi16(a, b); + let e = _mm512_set1_epi16(3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_add_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(2); + let r = _mm512_mask_add_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_add_epi16(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_add_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(2); + let r = _mm512_maskz_add_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_add_epi16(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_add_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(2); + let r = _mm256_mask_add_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_add_epi16(a, 0b00000000_11111111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_add_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(2); + let r = _mm256_maskz_add_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_add_epi16(0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_add_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(2); + let r = _mm_mask_add_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_add_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 3, 3, 3, 3); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_add_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(2); + let r = _mm_maskz_add_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_add_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 3, 3, 3, 3); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_add_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(2); + let r = _mm512_add_epi8(a, b); + let e = _mm512_set1_epi8(3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_add_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(2); + let r = _mm512_mask_add_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_add_epi8( + a, + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_add_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(2); + let r = _mm512_maskz_add_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_add_epi8( + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_add_epi8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(2); + let r = _mm256_mask_add_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_add_epi8(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_add_epi8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(2); + let r = _mm256_maskz_add_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_add_epi8(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_add_epi8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(2); + let r = _mm_mask_add_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_add_epi8(a, 0b00000000_11111111, a, b); + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_add_epi8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(2); + let r = _mm_maskz_add_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_add_epi8(0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_adds_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(u16::MAX as i16); + let r = _mm512_adds_epu16(a, b); + let e = _mm512_set1_epi16(u16::MAX as i16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_adds_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(u16::MAX as i16); + let r = _mm512_mask_adds_epu16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_adds_epu16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_adds_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(u16::MAX as i16); + let r = _mm512_maskz_adds_epu16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_adds_epu16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_adds_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(u16::MAX as i16); + let r = _mm256_mask_adds_epu16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_adds_epu16(a, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_adds_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(u16::MAX as i16); + let r = _mm256_maskz_adds_epu16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_adds_epu16(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_adds_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(u16::MAX as i16); + let r = _mm_mask_adds_epu16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_adds_epu16(a, 0b00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi16(1, 1, 1, 1, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_adds_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(u16::MAX as i16); + let r = _mm_maskz_adds_epu16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_adds_epu16(0b00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi16(0, 0, 0, 0, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16, u16::MAX as i16); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_adds_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(u8::MAX as i8); + let r = _mm512_adds_epu8(a, b); + let e = _mm512_set1_epi8(u8::MAX as i8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_adds_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(u8::MAX as i8); + let r = _mm512_mask_adds_epu8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_adds_epu8( + a, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(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, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_adds_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(u8::MAX as i8); + let r = _mm512_maskz_adds_epu8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_adds_epu8( + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_adds_epu8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(u8::MAX as i8); + let r = _mm256_mask_adds_epu8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_adds_epu8(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(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, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_adds_epu8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(u8::MAX as i8); + let r = _mm256_maskz_adds_epu8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_adds_epu8(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_adds_epu8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(u8::MAX as i8); + let r = _mm_mask_adds_epu8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_adds_epu8(a, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_adds_epu8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(u8::MAX as i8); + let r = _mm_maskz_adds_epu8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_adds_epu8(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8, u8::MAX as i8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_adds_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(i16::MAX); + let r = _mm512_adds_epi16(a, b); + let e = _mm512_set1_epi16(i16::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_adds_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(i16::MAX); + let r = _mm512_mask_adds_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_adds_epi16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_adds_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(i16::MAX); + let r = _mm512_maskz_adds_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_adds_epi16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_adds_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(i16::MAX); + let r = _mm256_mask_adds_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_adds_epi16(a, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_adds_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(i16::MAX); + let r = _mm256_maskz_adds_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_adds_epi16(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_adds_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(i16::MAX); + let r = _mm_mask_adds_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_adds_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_adds_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(i16::MAX); + let r = _mm_maskz_adds_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_adds_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_adds_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(i8::MAX); + let r = _mm512_adds_epi8(a, b); + let e = _mm512_set1_epi8(i8::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_adds_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(i8::MAX); + let r = _mm512_mask_adds_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_adds_epi8( + a, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(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, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_adds_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(i8::MAX); + let r = _mm512_maskz_adds_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_adds_epi8( + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_adds_epi8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(i8::MAX); + let r = _mm256_mask_adds_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_adds_epi8(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(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, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_adds_epi8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(i8::MAX); + let r = _mm256_maskz_adds_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_adds_epi8(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_adds_epi8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(i8::MAX); + let r = _mm_mask_adds_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_adds_epi8(a, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_adds_epi8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(i8::MAX); + let r = _mm_maskz_adds_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_adds_epi8(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_sub_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(2); + let r = _mm512_sub_epi16(a, b); + let e = _mm512_set1_epi16(-1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_sub_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(2); + let r = _mm512_mask_sub_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_sub_epi16(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_sub_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(2); + let r = _mm512_maskz_sub_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sub_epi16(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_sub_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(2); + let r = _mm256_mask_sub_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_sub_epi16(a, 0b00000000_11111111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_sub_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(2); + let r = _mm256_maskz_sub_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_sub_epi16(0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_sub_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(2); + let r = _mm_mask_sub_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_sub_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, -1, -1, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_sub_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(2); + let r = _mm_maskz_sub_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_sub_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, -1, -1, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_sub_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(2); + let r = _mm512_sub_epi8(a, b); + let e = _mm512_set1_epi8(-1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_sub_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(2); + let r = _mm512_mask_sub_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_sub_epi8( + a, + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(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); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_sub_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(2); + let r = _mm512_maskz_sub_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sub_epi8( + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_sub_epi8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(2); + let r = _mm256_mask_sub_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_sub_epi8(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(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); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_sub_epi8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(2); + let r = _mm256_maskz_sub_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_sub_epi8(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_sub_epi8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(2); + let r = _mm_mask_sub_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_sub_epi8(a, 0b00000000_11111111, a, b); + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_sub_epi8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(2); + let r = _mm_maskz_sub_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_sub_epi8(0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_subs_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(u16::MAX as i16); + let r = _mm512_subs_epu16(a, b); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_subs_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(u16::MAX as i16); + let r = _mm512_mask_subs_epu16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_subs_epu16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_subs_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(u16::MAX as i16); + let r = _mm512_maskz_subs_epu16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_subs_epu16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_subs_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(u16::MAX as i16); + let r = _mm256_mask_subs_epu16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_subs_epu16(a, 0b00000000_00001111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_subs_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(u16::MAX as i16); + let r = _mm256_maskz_subs_epu16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_subs_epu16(0b00000000_00001111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_subs_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(u16::MAX as i16); + let r = _mm_mask_subs_epu16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_subs_epu16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_subs_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(u16::MAX as i16); + let r = _mm_maskz_subs_epu16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_subs_epu16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_subs_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(u8::MAX as i8); + let r = _mm512_subs_epu8(a, b); + let e = _mm512_set1_epi8(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_subs_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(u8::MAX as i8); + let r = _mm512_mask_subs_epu8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_subs_epu8( + a, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(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, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_subs_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(u8::MAX as i8); + let r = _mm512_maskz_subs_epu8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_subs_epu8( + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_subs_epu8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(u8::MAX as i8); + let r = _mm256_mask_subs_epu8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_subs_epu8(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(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, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_subs_epu8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(u8::MAX as i8); + let r = _mm256_maskz_subs_epu8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_subs_epu8(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_subs_epu8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(u8::MAX as i8); + let r = _mm_mask_subs_epu8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_subs_epu8(a, 0b00000000_00001111, a, b); + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_subs_epu8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(u8::MAX as i8); + let r = _mm_maskz_subs_epu8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_subs_epu8(0b00000000_00001111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_subs_epi16() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(i16::MAX); + let r = _mm512_subs_epi16(a, b); + let e = _mm512_set1_epi16(i16::MIN); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_subs_epi16() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(i16::MAX); + let r = _mm512_mask_subs_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_subs_epi16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(-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, i16::MIN, i16::MIN, i16::MIN, i16::MIN); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_subs_epi16() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(i16::MAX); + let r = _mm512_maskz_subs_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_subs_epi16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i16::MIN, i16::MIN, i16::MIN, i16::MIN); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_subs_epi16() { + let a = _mm256_set1_epi16(-1); + let b = _mm256_set1_epi16(i16::MAX); + let r = _mm256_mask_subs_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_subs_epi16(a, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, i16::MIN, i16::MIN, i16::MIN, i16::MIN); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_subs_epi16() { + let a = _mm256_set1_epi16(-1); + let b = _mm256_set1_epi16(i16::MAX); + let r = _mm256_maskz_subs_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_subs_epi16(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i16::MIN, i16::MIN, i16::MIN, i16::MIN); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_subs_epi16() { + let a = _mm_set1_epi16(-1); + let b = _mm_set1_epi16(i16::MAX); + let r = _mm_mask_subs_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_subs_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(-1, -1, -1, -1, i16::MIN, i16::MIN, i16::MIN, i16::MIN); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_subs_epi16() { + let a = _mm_set1_epi16(-1); + let b = _mm_set1_epi16(i16::MAX); + let r = _mm_maskz_subs_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_subs_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, i16::MIN, i16::MIN, i16::MIN, i16::MIN); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_subs_epi8() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(i8::MAX); + let r = _mm512_subs_epi8(a, b); + let e = _mm512_set1_epi8(i8::MIN); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_subs_epi8() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(i8::MAX); + let r = _mm512_mask_subs_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_subs_epi8( + a, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(-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, i8::MIN, i8::MIN, i8::MIN, i8::MIN); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_subs_epi8() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(i8::MAX); + let r = _mm512_maskz_subs_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_subs_epi8( + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MIN, i8::MIN, i8::MIN, i8::MIN); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_subs_epi8() { + let a = _mm256_set1_epi8(-1); + let b = _mm256_set1_epi8(i8::MAX); + let r = _mm256_mask_subs_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_subs_epi8(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(-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, i8::MIN, i8::MIN, i8::MIN, i8::MIN); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_subs_epi8() { + let a = _mm256_set1_epi8(-1); + let b = _mm256_set1_epi8(i8::MAX); + let r = _mm256_maskz_subs_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_subs_epi8(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MIN, i8::MIN, i8::MIN, i8::MIN); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_subs_epi8() { + let a = _mm_set1_epi8(-1); + let b = _mm_set1_epi8(i8::MAX); + let r = _mm_mask_subs_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_subs_epi8(a, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, i8::MIN, i8::MIN, i8::MIN, i8::MIN); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_subs_epi8() { + let a = _mm_set1_epi8(-1); + let b = _mm_set1_epi8(i8::MAX); + let r = _mm_maskz_subs_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_subs_epi8(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MIN, i8::MIN, i8::MIN, i8::MIN); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mulhi_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mulhi_epu16(a, b); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_mulhi_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mask_mulhi_epu16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mulhi_epu16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_mulhi_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_mulhi_epu16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mulhi_epu16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_mulhi_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_mask_mulhi_epu16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_mulhi_epu16(a, 0b00000000_00001111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_mulhi_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_mulhi_epu16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_mulhi_epu16(0b00000000_00001111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_mulhi_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_mask_mulhi_epu16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_mulhi_epu16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_mulhi_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_mulhi_epu16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_mulhi_epu16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mulhi_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mulhi_epi16(a, b); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_mulhi_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mask_mulhi_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mulhi_epi16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_mulhi_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_mulhi_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mulhi_epi16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_mulhi_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_mask_mulhi_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_mulhi_epi16(a, 0b00000000_00001111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_mulhi_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_mulhi_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_mulhi_epi16(0b00000000_00001111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_mulhi_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_mask_mulhi_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_mulhi_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_mulhi_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_mulhi_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_mulhi_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mulhrs_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mulhrs_epi16(a, b); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_mulhrs_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mask_mulhrs_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mulhrs_epi16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_mulhrs_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_mulhrs_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mulhrs_epi16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_mulhrs_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_mask_mulhrs_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_mulhrs_epi16(a, 0b00000000_00001111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_mulhrs_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_mulhrs_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_mulhrs_epi16(0b00000000_00001111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_mulhrs_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_mask_mulhrs_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_mulhrs_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_mulhrs_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_mulhrs_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_mulhrs_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mullo_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mullo_epi16(a, b); + let e = _mm512_set1_epi16(1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_mullo_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mask_mullo_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mullo_epi16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_mullo_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_mullo_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mullo_epi16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 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, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_mullo_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_mask_mullo_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_mullo_epi16(a, 0b00000000_00001111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_mullo_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_mullo_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_mullo_epi16(0b00000000_00001111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_mullo_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_mask_mullo_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_mullo_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_mullo_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_mullo_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_mullo_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_max_epu16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epu16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epu16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epu16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epu16(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epu16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epu16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epu16(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_max_epu16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_max_epu16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_max_epu16(a, 0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_max_epu16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_max_epu16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_max_epu16(0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_max_epu16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_max_epu16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_max_epu16(a, 0b00001111, a, b); + let e = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_max_epu16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_max_epu16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_max_epu16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 4, 5, 6, 7); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_max_epu8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epu8(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epu8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epu8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epu8( + a, + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epu8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epu8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epu8( + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_max_epu8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_max_epu8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_max_epu8(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_max_epu8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_max_epu8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_max_epu8(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_max_epu8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_max_epu8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_max_epu8(a, 0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_max_epu8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_max_epu8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_max_epu8(0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_max_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epi16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epi16(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epi16(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_max_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_max_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_max_epi16(a, 0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_max_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_max_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_max_epi16(0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_max_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_max_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_max_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_max_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_max_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_max_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 4, 5, 6, 7); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_max_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epi8(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epi8( + a, + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epi8( + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_max_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_max_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_max_epi8(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_max_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_max_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_max_epi8(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_max_epi8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_max_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_max_epi8(a, 0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_max_epi8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_max_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_max_epi8(0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_min_epu16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epu16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epu16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epu16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epu16(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epu16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epu16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epu16(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_min_epu16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_min_epu16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_min_epu16(a, 0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_min_epu16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_min_epu16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_min_epu16(0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_min_epu16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_min_epu16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_min_epu16(a, 0b00001111, a, b); + let e = _mm_set_epi16(0, 1, 2, 3, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_min_epu16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_min_epu16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_min_epu16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_min_epu8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epu8(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epu8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epu8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epu8( + a, + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epu8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epu8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epu8( + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_min_epu8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_min_epu8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_min_epu8(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_min_epu8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_min_epu8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_min_epu8(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_min_epu8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_min_epu8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_min_epu8(a, 0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_min_epu8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_min_epu8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_min_epu8(0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_min_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epi16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epi16(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epi16(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_min_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_min_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_min_epi16(a, 0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_min_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm256_set_epi16(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_min_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_min_epi16(0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_min_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_min_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_min_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi16(0, 1, 2, 3, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_min_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm_set_epi16(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_min_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_min_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_min_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epi8(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epi8( + a, + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm512_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epi8( + 0b00000000_11111111_00000000_11111111_00000000_11111111_00000000_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_mask_min_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_mask_min_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_min_epi8(a, 0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm256_maskz_min_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm256_maskz_min_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_min_epi8(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_mask_min_epi8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_mask_min_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_min_epi8(a, 0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f,avx512vl")] + unsafe fn test_mm_maskz_min_epi8() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm_maskz_min_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_min_epi8(0b00000000_11111111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmplt_epu16_mask() { + let a = _mm512_set1_epi16(-2); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmplt_epu16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmplt_epu16_mask() { + let a = _mm512_set1_epi16(-2); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmplt_epu16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmplt_epu8_mask() { + let a = _mm512_set1_epi8(-2); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmplt_epu8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmplt_epu8_mask() { + let a = _mm512_set1_epi8(-2); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmplt_epu8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmplt_epi16_mask() { + let a = _mm512_set1_epi16(-2); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmplt_epi16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmplt_epi16_mask() { + let a = _mm512_set1_epi16(-2); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmplt_epi16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmplt_epi8_mask() { + let a = _mm512_set1_epi8(-2); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmplt_epi8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmplt_epi8_mask() { + let a = _mm512_set1_epi8(-2); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmplt_epi8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpgt_epu16_mask() { + let a = _mm512_set1_epi16(2); + let b = _mm512_set1_epi16(1); + let m = _mm512_cmpgt_epu16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpgt_epu16_mask() { + let a = _mm512_set1_epi16(2); + let b = _mm512_set1_epi16(1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpgt_epu16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpgt_epu8_mask() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(1); + let m = _mm512_cmpgt_epu8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpgt_epu8_mask() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpgt_epu8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpgt_epi16_mask() { + let a = _mm512_set1_epi16(2); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmpgt_epi16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpgt_epi16_mask() { + let a = _mm512_set1_epi16(2); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpgt_epi16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpgt_epi8_mask() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmpgt_epi8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpgt_epi8_mask() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpgt_epi8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmple_epu16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmple_epu16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmple_epu16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmple_epu16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmple_epu8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmple_epu8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmple_epu8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmple_epu8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmple_epi16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmple_epi16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmple_epi16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmple_epi16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmple_epi8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmple_epi8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmple_epi8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmple_epi8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpge_epu16_mask() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let m = _mm512_cmpge_epu16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpge_epu16_mask() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpge_epu16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpge_epu8_mask() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let m = _mm512_cmpge_epu8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpge_epu8_mask() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpge_epu8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpge_epi16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmpge_epi16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpge_epi16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpge_epi16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpge_epi8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmpge_epi8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpge_epi8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpge_epi8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpeq_epu16_mask() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let m = _mm512_cmpeq_epu16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpeq_epu16_mask() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpeq_epu16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpeq_epu8_mask() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let m = _mm512_cmpeq_epu8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpeq_epu8_mask() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpeq_epu8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpeq_epi16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmpeq_epi16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpeq_epi16_mask() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpeq_epi16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpeq_epi8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmpeq_epi8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpeq_epi8_mask() { + let a = _mm512_set1_epi8(-1); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpeq_epi8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpneq_epu16_mask() { + let a = _mm512_set1_epi16(2); + let b = _mm512_set1_epi16(1); + let m = _mm512_cmpneq_epu16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpneq_epu16_mask() { + let a = _mm512_set1_epi16(2); + let b = _mm512_set1_epi16(1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpneq_epu16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpneq_epu8_mask() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(1); + let m = _mm512_cmpneq_epu8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpneq_epu8_mask() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpneq_epu8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpneq_epi16_mask() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(-1); + let m = _mm512_cmpneq_epi16_mask(a, b); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpneq_epi16_mask() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(-1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpneq_epi16_mask(mask, a, b); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmpneq_epi8_mask() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(-1); + let m = _mm512_cmpneq_epi8_mask(a, b); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmpneq_epi8_mask() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(-1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmpneq_epi8_mask(mask, a, b); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmp_epu16_mask() { + let a = _mm512_set1_epi16(0); + let b = _mm512_set1_epi16(1); + let m = _mm512_cmp_epu16_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmp_epu16_mask() { + let a = _mm512_set1_epi16(0); + let b = _mm512_set1_epi16(1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmp_epu16_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmp_epu8_mask() { + let a = _mm512_set1_epi8(0); + let b = _mm512_set1_epi8(1); + let m = _mm512_cmp_epu8_mask(a, b, _MM_CMPINT_LT); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmp_epu8_mask() { + let a = _mm512_set1_epi8(0); + let b = _mm512_set1_epi8(1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmp_epu8_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmp_epi16_mask() { + let a = _mm512_set1_epi16(0); + let b = _mm512_set1_epi16(1); + let m = _mm512_cmp_epi16_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b11111111_11111111_11111111_11111111); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmp_epi16_mask() { + let a = _mm512_set1_epi16(0); + let b = _mm512_set1_epi16(1); + let mask = 0b01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmp_epi16_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b01010101_01010101_01010101_01010101); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cmp_epi8_mask() { + let a = _mm512_set1_epi8(0); + let b = _mm512_set1_epi8(1); + let m = _mm512_cmp_epi8_mask(a, b, _MM_CMPINT_LT); + assert_eq!( + m, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cmp_epi8_mask() { + let a = _mm512_set1_epi8(0); + let b = _mm512_set1_epi8(1); + let mask = 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101; + let r = _mm512_mask_cmp_epi8_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!( + r, + 0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101 + ); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_loadu_epi16() { + #[rustfmt::skip] + let a: [i16; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let r = _mm512_loadu_epi16(&a[0]); + #[rustfmt::skip] + let e = _mm512_set_epi16(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_loadu_epi8() { + #[rustfmt::skip] + let a: [i8; 64] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; + let r = _mm512_loadu_epi8(&a[0]); + #[rustfmt::skip] + let e = _mm512_set_epi8(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_storeu_epi16() { + let a = _mm512_set1_epi16(9); + let mut r = _mm512_undefined_epi32(); + _mm512_storeu_epi16(&mut r as *mut _ as *mut i16, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_storeu_epi8() { + let a = _mm512_set1_epi8(9); + let mut r = _mm512_undefined_epi32(); + _mm512_storeu_epi8(&mut r as *mut _ as *mut i8, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_madd_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_madd_epi16(a, b); + let e = _mm512_set1_epi32(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_madd_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mask_madd_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_madd_epi16(a, 0b00000000_00001111, a, b); + let e = _mm512_set_epi32( + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 2, + 2, + 2, + 2, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_madd_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_madd_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_madd_epi16(0b00000000_00001111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_madd_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_mask_madd_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_madd_epi16(a, 0b00001111, a, b); + let e = _mm256_set_epi32( + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 1 << 16 | 1, + 2, + 2, + 2, + 2, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_madd_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_madd_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_madd_epi16(0b00001111, a, b); + let e = _mm256_set_epi32(0, 0, 0, 0, 2, 2, 2, 2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_madd_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_mask_madd_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_madd_epi16(a, 0b00001111, a, b); + let e = _mm_set_epi32(2, 2, 2, 2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_madd_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_madd_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_madd_epi16(0b00001111, a, b); + let e = _mm_set_epi32(2, 2, 2, 2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maddubs_epi16() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let r = _mm512_maddubs_epi16(a, b); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_maddubs_epi16() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let src = _mm512_set1_epi16(1); + let r = _mm512_mask_maddubs_epi16(src, 0, a, b); + assert_eq_m512i(r, src); + let r = _mm512_mask_add_epi16(src, 0b00000000_00000000_00000000_00000001, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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<<9|2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_maddubs_epi16() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let r = _mm512_maskz_maddubs_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_maddubs_epi16(0b00000000_11111111_00000000_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_maddubs_epi16() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(1); + let src = _mm256_set1_epi16(1); + let r = _mm256_mask_maddubs_epi16(src, 0, a, b); + assert_eq_m256i(r, src); + let r = _mm256_mask_add_epi16(src, 0b00000000_00000001, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 9 | 2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_maddubs_epi16() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(1); + let r = _mm256_maskz_maddubs_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_maddubs_epi16(0b00000000_11111111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_maddubs_epi16() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(1); + let src = _mm_set1_epi16(1); + let r = _mm_mask_maddubs_epi16(src, 0, a, b); + assert_eq_m128i(r, src); + let r = _mm_mask_add_epi16(src, 0b00000001, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 1, 1, 1, 1 << 9 | 2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_maddubs_epi16() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(1); + let r = _mm_maskz_maddubs_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_maddubs_epi16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 2, 2, 2, 2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_packs_epi32() { + let a = _mm512_set1_epi32(i32::MAX); + let b = _mm512_set1_epi32(1); + let r = _mm512_packs_epi32(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX, 1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX, + 1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX, 1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_packs_epi32() { + let a = _mm512_set1_epi32(i32::MAX); + let b = _mm512_set1_epi32(1 << 16 | 1); + let r = _mm512_mask_packs_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_packs_epi32(b, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_packs_epi32() { + let a = _mm512_set1_epi32(i32::MAX); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_packs_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_packs_epi32(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_packs_epi32() { + let a = _mm256_set1_epi32(i32::MAX); + let b = _mm256_set1_epi32(1 << 16 | 1); + let r = _mm256_mask_packs_epi32(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_packs_epi32(b, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_packs_epi32() { + let a = _mm256_set1_epi32(i32::MAX); + let b = _mm256_set1_epi32(1); + let r = _mm256_maskz_packs_epi32(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_packs_epi32(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_packs_epi32() { + let a = _mm_set1_epi32(i32::MAX); + let b = _mm_set1_epi32(1 << 16 | 1); + let r = _mm_mask_packs_epi32(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_packs_epi32(b, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_packs_epi32() { + let a = _mm_set1_epi32(i32::MAX); + let b = _mm_set1_epi32(1); + let r = _mm_maskz_packs_epi32(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_packs_epi32(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, i16::MAX, i16::MAX, i16::MAX, i16::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_packs_epi16() { + let a = _mm512_set1_epi16(i16::MAX); + let b = _mm512_set1_epi16(1); + let r = _mm512_packs_epi16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, + 1, 1, 1, 1, 1, 1, 1, 1, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, + 1, 1, 1, 1, 1, 1, 1, 1, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, + 1, 1, 1, 1, 1, 1, 1, 1, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_packs_epi16() { + let a = _mm512_set1_epi16(i16::MAX); + let b = _mm512_set1_epi16(1 << 8 | 1); + let r = _mm512_mask_packs_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_packs_epi16( + b, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(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, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_packs_epi16() { + let a = _mm512_set1_epi16(i16::MAX); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_packs_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_packs_epi16( + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_packs_epi16() { + let a = _mm256_set1_epi16(i16::MAX); + let b = _mm256_set1_epi16(1 << 8 | 1); + let r = _mm256_mask_packs_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_packs_epi16(b, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(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, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_packs_epi16() { + let a = _mm256_set1_epi16(i16::MAX); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_packs_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_packs_epi16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_packs_epi16() { + let a = _mm_set1_epi16(i16::MAX); + let b = _mm_set1_epi16(1 << 8 | 1); + let r = _mm_mask_packs_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_packs_epi16(b, 0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_packs_epi16() { + let a = _mm_set1_epi16(i16::MAX); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_packs_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_packs_epi16(0b00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, i8::MAX, i8::MAX, i8::MAX, i8::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_packus_epi32() { + let a = _mm512_set1_epi32(-1); + let b = _mm512_set1_epi32(1); + let r = _mm512_packus_epi32(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_packus_epi32() { + let a = _mm512_set1_epi32(-1); + let b = _mm512_set1_epi32(1 << 16 | 1); + let r = _mm512_mask_packus_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_packus_epi32(b, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_packus_epi32() { + let a = _mm512_set1_epi32(-1); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_packus_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_packus_epi32(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_packus_epi32() { + let a = _mm256_set1_epi32(-1); + let b = _mm256_set1_epi32(1 << 16 | 1); + let r = _mm256_mask_packus_epi32(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_packus_epi32(b, 0b00000000_00001111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_packus_epi32() { + let a = _mm256_set1_epi32(-1); + let b = _mm256_set1_epi32(1); + let r = _mm256_maskz_packus_epi32(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_packus_epi32(0b00000000_00001111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_packus_epi32() { + let a = _mm_set1_epi32(-1); + let b = _mm_set1_epi32(1 << 16 | 1); + let r = _mm_mask_packus_epi32(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_packus_epi32(b, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_packus_epi32() { + let a = _mm_set1_epi32(-1); + let b = _mm_set1_epi32(1); + let r = _mm_maskz_packus_epi32(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_packus_epi32(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_packus_epi16() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(1); + let r = _mm512_packus_epi16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_packus_epi16() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(1 << 8 | 1); + let r = _mm512_mask_packus_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_packus_epi16( + b, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(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, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_packus_epi16() { + let a = _mm512_set1_epi16(-1); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_packus_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_packus_epi16( + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_packus_epi16() { + let a = _mm256_set1_epi16(-1); + let b = _mm256_set1_epi16(1 << 8 | 1); + let r = _mm256_mask_packus_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_packus_epi16(b, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(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, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_packus_epi16() { + let a = _mm256_set1_epi16(-1); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_packus_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_packus_epi16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_packus_epi16() { + let a = _mm_set1_epi16(-1); + let b = _mm_set1_epi16(1 << 8 | 1); + let r = _mm_mask_packus_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_packus_epi16(b, 0b00000000_00001111, a, b); + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_packus_epi16() { + let a = _mm_set1_epi16(-1); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_packus_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_packus_epi16(0b00000000_00001111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_avg_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_avg_epu16(a, b); + let e = _mm512_set1_epi16(1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_avg_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_mask_avg_epu16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_avg_epu16(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(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); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_avg_epu16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(1); + let r = _mm512_maskz_avg_epu16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_avg_epu16(0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(0, 0, 0, 0, 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, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_avg_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_mask_avg_epu16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_avg_epu16(a, 0b00000000_00001111, a, b); + let e = _mm256_set_epi16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_avg_epu16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(1); + let r = _mm256_maskz_avg_epu16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_avg_epu16(0b00000000_00001111, a, b); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_avg_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_mask_avg_epu16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_avg_epu16(a, 0b00001111, a, b); + let e = _mm_set_epi16(1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_avg_epu16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(1); + let r = _mm_maskz_avg_epu16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_avg_epu16(0b00001111, a, b); + let e = _mm_set_epi16(0, 0, 0, 0, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_avg_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let r = _mm512_avg_epu8(a, b); + let e = _mm512_set1_epi8(1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_avg_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let r = _mm512_mask_avg_epu8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_avg_epu8( + a, + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(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); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_avg_epu8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(1); + let r = _mm512_maskz_avg_epu8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_avg_epu8( + 0b00000000_000000000_00000000_00000000_00000000_0000000_00000000_00001111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 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, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_avg_epu8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(1); + let r = _mm256_mask_avg_epu8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_avg_epu8(a, 0b00000000_00000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(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); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_avg_epu8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(1); + let r = _mm256_maskz_avg_epu8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_avg_epu8(0b00000000_0000000_00000000_00001111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(0, 0, 0, 0, 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, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_avg_epu8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(1); + let r = _mm_mask_avg_epu8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_avg_epu8(a, 0b00000000_00001111, a, b); + let e = _mm_set_epi8(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_avg_epu8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(1); + let r = _mm_maskz_avg_epu8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_avg_epu8(0b00000000_00001111, a, b); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_sll_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm512_sll_epi16(a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_sll_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm512_mask_sll_epi16(a, 0, a, count); + assert_eq_m512i(r, a); + let r = _mm512_mask_sll_epi16(a, 0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_sll_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm512_maskz_sll_epi16(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sll_epi16(0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_sll_epi16() { + let a = _mm256_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm256_mask_sll_epi16(a, 0, a, count); + assert_eq_m256i(r, a); + let r = _mm256_mask_sll_epi16(a, 0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_sll_epi16() { + let a = _mm256_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm256_maskz_sll_epi16(0, a, count); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_sll_epi16(0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_sll_epi16() { + let a = _mm_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm_mask_sll_epi16(a, 0, a, count); + assert_eq_m128i(r, a); + let r = _mm_mask_sll_epi16(a, 0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_sll_epi16() { + let a = _mm_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm_maskz_sll_epi16(0, a, count); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_sll_epi16(0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_slli_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let r = _mm512_slli_epi16(a, 1); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_slli_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let r = _mm512_mask_slli_epi16(a, 0, a, 1); + assert_eq_m512i(r, a); + let r = _mm512_mask_slli_epi16(a, 0b11111111_11111111_11111111_11111111, a, 1); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_slli_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let r = _mm512_maskz_slli_epi16(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_slli_epi16(0b11111111_11111111_11111111_11111111, a, 1); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_slli_epi16() { + let a = _mm256_set1_epi16(1 << 15); + let r = _mm256_mask_slli_epi16(a, 0, a, 1); + assert_eq_m256i(r, a); + let r = _mm256_mask_slli_epi16(a, 0b11111111_11111111, a, 1); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_slli_epi16() { + let a = _mm256_set1_epi16(1 << 15); + let r = _mm256_maskz_slli_epi16(0, a, 1); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_slli_epi16(0b11111111_11111111, a, 1); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_slli_epi16() { + let a = _mm_set1_epi16(1 << 15); + let r = _mm_mask_slli_epi16(a, 0, a, 1); + assert_eq_m128i(r, a); + let r = _mm_mask_slli_epi16(a, 0b11111111, a, 1); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_slli_epi16() { + let a = _mm_set1_epi16(1 << 15); + let r = _mm_maskz_slli_epi16(0, a, 1); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_slli_epi16(0b11111111, a, 1); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_sllv_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let count = _mm512_set1_epi16(2); + let r = _mm512_sllv_epi16(a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_sllv_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let count = _mm512_set1_epi16(2); + let r = _mm512_mask_sllv_epi16(a, 0, a, count); + assert_eq_m512i(r, a); + let r = _mm512_mask_sllv_epi16(a, 0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_sllv_epi16() { + let a = _mm512_set1_epi16(1 << 15); + let count = _mm512_set1_epi16(2); + let r = _mm512_maskz_sllv_epi16(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sllv_epi16(0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_sllv_epi16() { + let a = _mm256_set1_epi16(1 << 15); + let count = _mm256_set1_epi16(2); + let r = _mm256_sllv_epi16(a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_sllv_epi16() { + let a = _mm256_set1_epi16(1 << 15); + let count = _mm256_set1_epi16(2); + let r = _mm256_mask_sllv_epi16(a, 0, a, count); + assert_eq_m256i(r, a); + let r = _mm256_mask_sllv_epi16(a, 0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_sllv_epi16() { + let a = _mm256_set1_epi16(1 << 15); + let count = _mm256_set1_epi16(2); + let r = _mm256_maskz_sllv_epi16(0, a, count); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_sllv_epi16(0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_sllv_epi16() { + let a = _mm_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm_sllv_epi16(a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_sllv_epi16() { + let a = _mm_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm_mask_sllv_epi16(a, 0, a, count); + assert_eq_m128i(r, a); + let r = _mm_mask_sllv_epi16(a, 0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_sllv_epi16() { + let a = _mm_set1_epi16(1 << 15); + let count = _mm_set1_epi16(2); + let r = _mm_maskz_sllv_epi16(0, a, count); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_sllv_epi16(0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_srl_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm512_srl_epi16(a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_srl_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm512_mask_srl_epi16(a, 0, a, count); + assert_eq_m512i(r, a); + let r = _mm512_mask_srl_epi16(a, 0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_srl_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm512_maskz_srl_epi16(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_srl_epi16(0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_srl_epi16() { + let a = _mm256_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm256_mask_srl_epi16(a, 0, a, count); + assert_eq_m256i(r, a); + let r = _mm256_mask_srl_epi16(a, 0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_srl_epi16() { + let a = _mm256_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm256_maskz_srl_epi16(0, a, count); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_srl_epi16(0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_srl_epi16() { + let a = _mm_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm_mask_srl_epi16(a, 0, a, count); + assert_eq_m128i(r, a); + let r = _mm_mask_srl_epi16(a, 0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_srl_epi16() { + let a = _mm_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm_maskz_srl_epi16(0, a, count); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_srl_epi16(0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_srli_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let r = _mm512_srli_epi16(a, 2); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_srli_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let r = _mm512_mask_srli_epi16(a, 0, a, 2); + assert_eq_m512i(r, a); + let r = _mm512_mask_srli_epi16(a, 0b11111111_11111111_11111111_11111111, a, 2); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_srli_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let r = _mm512_maskz_srli_epi16(0, a, 2); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_srli_epi16(0b11111111_11111111_11111111_11111111, a, 2); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_srli_epi16() { + let a = _mm256_set1_epi16(1 << 1); + let r = _mm256_mask_srli_epi16(a, 0, a, 2); + assert_eq_m256i(r, a); + let r = _mm256_mask_srli_epi16(a, 0b11111111_11111111, a, 2); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_srli_epi16() { + let a = _mm256_set1_epi16(1 << 1); + let r = _mm256_maskz_srli_epi16(0, a, 2); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_srli_epi16(0b11111111_11111111, a, 2); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_srli_epi16() { + let a = _mm_set1_epi16(1 << 1); + let r = _mm_mask_srli_epi16(a, 0, a, 2); + assert_eq_m128i(r, a); + let r = _mm_mask_srli_epi16(a, 0b11111111, a, 2); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_srli_epi16() { + let a = _mm_set1_epi16(1 << 1); + let r = _mm_maskz_srli_epi16(0, a, 2); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_srli_epi16(0b11111111, a, 2); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_srlv_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let count = _mm512_set1_epi16(2); + let r = _mm512_srlv_epi16(a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_srlv_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let count = _mm512_set1_epi16(2); + let r = _mm512_mask_srlv_epi16(a, 0, a, count); + assert_eq_m512i(r, a); + let r = _mm512_mask_srlv_epi16(a, 0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_srlv_epi16() { + let a = _mm512_set1_epi16(1 << 1); + let count = _mm512_set1_epi16(2); + let r = _mm512_maskz_srlv_epi16(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_srlv_epi16(0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_srlv_epi16() { + let a = _mm256_set1_epi16(1 << 1); + let count = _mm256_set1_epi16(2); + let r = _mm256_srlv_epi16(a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_srlv_epi16() { + let a = _mm256_set1_epi16(1 << 1); + let count = _mm256_set1_epi16(2); + let r = _mm256_mask_srlv_epi16(a, 0, a, count); + assert_eq_m256i(r, a); + let r = _mm256_mask_srlv_epi16(a, 0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_srlv_epi16() { + let a = _mm256_set1_epi16(1 << 1); + let count = _mm256_set1_epi16(2); + let r = _mm256_maskz_srlv_epi16(0, a, count); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_srlv_epi16(0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_srlv_epi16() { + let a = _mm_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm_srlv_epi16(a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_srlv_epi16() { + let a = _mm_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm_mask_srlv_epi16(a, 0, a, count); + assert_eq_m128i(r, a); + let r = _mm_mask_srlv_epi16(a, 0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_srlv_epi16() { + let a = _mm_set1_epi16(1 << 1); + let count = _mm_set1_epi16(2); + let r = _mm_maskz_srlv_epi16(0, a, count); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_srlv_epi16(0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_sra_epi16() { + let a = _mm512_set1_epi16(8); + let count = _mm_set1_epi16(1); + let r = _mm512_sra_epi16(a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_sra_epi16() { + let a = _mm512_set1_epi16(8); + let count = _mm_set1_epi16(1); + let r = _mm512_mask_sra_epi16(a, 0, a, count); + assert_eq_m512i(r, a); + let r = _mm512_mask_sra_epi16(a, 0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_sra_epi16() { + let a = _mm512_set1_epi16(8); + let count = _mm_set1_epi16(1); + let r = _mm512_maskz_sra_epi16(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sra_epi16(0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_sra_epi16() { + let a = _mm256_set1_epi16(8); + let count = _mm_set1_epi16(1); + let r = _mm256_mask_sra_epi16(a, 0, a, count); + assert_eq_m256i(r, a); + let r = _mm256_mask_sra_epi16(a, 0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_sra_epi16() { + let a = _mm256_set1_epi16(8); + let count = _mm_set1_epi16(1); + let r = _mm256_maskz_sra_epi16(0, a, count); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_sra_epi16(0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_sra_epi16() { + let a = _mm_set1_epi16(8); + let count = _mm_set1_epi16(1); + let r = _mm_mask_sra_epi16(a, 0, a, count); + assert_eq_m128i(r, a); + let r = _mm_mask_sra_epi16(a, 0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_sra_epi16() { + let a = _mm_set1_epi16(8); + let count = _mm_set1_epi16(1); + let r = _mm_maskz_sra_epi16(0, a, count); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_sra_epi16(0b11111111, a, count); + let e = _mm_set1_epi16(0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_srai_epi16() { + let a = _mm512_set1_epi16(8); + let r = _mm512_srai_epi16(a, 2); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_srai_epi16() { + let a = _mm512_set1_epi16(8); + let r = _mm512_mask_srai_epi16(a, 0, a, 2); + assert_eq_m512i(r, a); + let r = _mm512_mask_srai_epi16(a, 0b11111111_11111111_11111111_11111111, a, 2); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_srai_epi16() { + let a = _mm512_set1_epi16(8); + let r = _mm512_maskz_srai_epi16(0, a, 2); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_srai_epi16(0b11111111_11111111_11111111_11111111, a, 2); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_srai_epi16() { + let a = _mm256_set1_epi16(8); + let r = _mm256_mask_srai_epi16(a, 0, a, 2); + assert_eq_m256i(r, a); + let r = _mm256_mask_srai_epi16(a, 0b11111111_11111111, a, 2); + let e = _mm256_set1_epi16(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_srai_epi16() { + let a = _mm256_set1_epi16(8); + let r = _mm256_maskz_srai_epi16(0, a, 2); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_srai_epi16(0b11111111_11111111, a, 2); + let e = _mm256_set1_epi16(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_srai_epi16() { + let a = _mm_set1_epi16(8); + let r = _mm_mask_srai_epi16(a, 0, a, 2); + assert_eq_m128i(r, a); + let r = _mm_mask_srai_epi16(a, 0b11111111, a, 2); + let e = _mm_set1_epi16(2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_srai_epi16() { + let a = _mm_set1_epi16(8); + let r = _mm_maskz_srai_epi16(0, a, 2); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_srai_epi16(0b11111111, a, 2); + let e = _mm_set1_epi16(2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_srav_epi16() { + let a = _mm512_set1_epi16(8); + let count = _mm512_set1_epi16(2); + let r = _mm512_srav_epi16(a, count); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_srav_epi16() { + let a = _mm512_set1_epi16(8); + let count = _mm512_set1_epi16(2); + let r = _mm512_mask_srav_epi16(a, 0, a, count); + assert_eq_m512i(r, a); + let r = _mm512_mask_srav_epi16(a, 0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_srav_epi16() { + let a = _mm512_set1_epi16(8); + let count = _mm512_set1_epi16(2); + let r = _mm512_maskz_srav_epi16(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_srav_epi16(0b11111111_11111111_11111111_11111111, a, count); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_srav_epi16() { + let a = _mm256_set1_epi16(8); + let count = _mm256_set1_epi16(2); + let r = _mm256_srav_epi16(a, count); + let e = _mm256_set1_epi16(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_srav_epi16() { + let a = _mm256_set1_epi16(8); + let count = _mm256_set1_epi16(2); + let r = _mm256_mask_srav_epi16(a, 0, a, count); + assert_eq_m256i(r, a); + let r = _mm256_mask_srav_epi16(a, 0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_srav_epi16() { + let a = _mm256_set1_epi16(8); + let count = _mm256_set1_epi16(2); + let r = _mm256_maskz_srav_epi16(0, a, count); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_srav_epi16(0b11111111_11111111, a, count); + let e = _mm256_set1_epi16(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_srav_epi16() { + let a = _mm_set1_epi16(8); + let count = _mm_set1_epi16(2); + let r = _mm_srav_epi16(a, count); + let e = _mm_set1_epi16(2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_srav_epi16() { + let a = _mm_set1_epi16(8); + let count = _mm_set1_epi16(2); + let r = _mm_mask_srav_epi16(a, 0, a, count); + assert_eq_m128i(r, a); + let r = _mm_mask_srav_epi16(a, 0b11111111, a, count); + let e = _mm_set1_epi16(2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_srav_epi16() { + let a = _mm_set1_epi16(8); + let count = _mm_set1_epi16(2); + let r = _mm_maskz_srav_epi16(0, a, count); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_srav_epi16(0b11111111, a, count); + let e = _mm_set1_epi16(2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_permutex2var_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + #[rustfmt::skip] + let idx = _mm512_set_epi16(1, 1<<5, 2, 1<<5, 3, 1<<5, 4, 1<<5, 5, 1<<5, 6, 1<<5, 7, 1<<5, 8, 1<<5, + 9, 1<<5, 10, 1<<5, 11, 1<<5, 12, 1<<5, 13, 1<<5, 14, 1<<5, 15, 1<<5, 16, 1<<5); + let b = _mm512_set1_epi16(100); + let r = _mm512_permutex2var_epi16(a, idx, b); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 30, 100, 29, 100, 28, 100, 27, 100, 26, 100, 25, 100, 24, 100, 23, 100, + 22, 100, 21, 100, 20, 100, 19, 100, 18, 100, 17, 100, 16, 100, 15, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_permutex2var_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + #[rustfmt::skip] + let idx = _mm512_set_epi16(1, 1<<5, 2, 1<<5, 3, 1<<5, 4, 1<<5, 5, 1<<5, 6, 1<<5, 7, 1<<5, 8, 1<<5, + 9, 1<<5, 10, 1<<5, 11, 1<<5, 12, 1<<5, 13, 1<<5, 14, 1<<5, 15, 1<<5, 16, 1<<5); + let b = _mm512_set1_epi16(100); + let r = _mm512_mask_permutex2var_epi16(a, 0, idx, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex2var_epi16(a, 0b11111111_11111111_11111111_11111111, idx, b); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 30, 100, 29, 100, 28, 100, 27, 100, 26, 100, 25, 100, 24, 100, 23, 100, + 22, 100, 21, 100, 20, 100, 19, 100, 18, 100, 17, 100, 16, 100, 15, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_permutex2var_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + #[rustfmt::skip] + let idx = _mm512_set_epi16(1, 1<<5, 2, 1<<5, 3, 1<<5, 4, 1<<5, 5, 1<<5, 6, 1<<5, 7, 1<<5, 8, 1<<5, + 9, 1<<5, 10, 1<<5, 11, 1<<5, 12, 1<<5, 13, 1<<5, 14, 1<<5, 15, 1<<5, 16, 1<<5); + let b = _mm512_set1_epi16(100); + let r = _mm512_maskz_permutex2var_epi16(0, a, idx, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex2var_epi16(0b11111111_11111111_11111111_11111111, a, idx, b); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 30, 100, 29, 100, 28, 100, 27, 100, 26, 100, 25, 100, 24, 100, 23, 100, + 22, 100, 21, 100, 20, 100, 19, 100, 18, 100, 17, 100, 16, 100, 15, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask2_permutex2var_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + #[rustfmt::skip] + let idx = _mm512_set_epi16(1, 1<<5, 2, 1<<5, 3, 1<<5, 4, 1<<5, 5, 1<<5, 6, 1<<5, 7, 1<<5, 8, 1<<5, + 9, 1<<5, 10, 1<<5, 11, 1<<5, 12, 1<<5, 13, 1<<5, 14, 1<<5, 15, 1<<5, 16, 1<<5); + let b = _mm512_set1_epi16(100); + let r = _mm512_mask2_permutex2var_epi16(a, idx, 0, b); + assert_eq_m512i(r, idx); + let r = _mm512_mask2_permutex2var_epi16(a, idx, 0b11111111_11111111_11111111_11111111, b); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 30, 100, 29, 100, 28, 100, 27, 100, 26, 100, 25, 100, 24, 100, 23, 100, + 22, 100, 21, 100, 20, 100, 19, 100, 18, 100, 17, 100, 16, 100, 15, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_permutex2var_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let idx = _mm256_set_epi16(1, 1<<4, 2, 1<<4, 3, 1<<4, 4, 1<<4, 5, 1<<4, 6, 1<<4, 7, 1<<4, 8, 1<<4); + let b = _mm256_set1_epi16(100); + let r = _mm256_permutex2var_epi16(a, idx, b); + let e = _mm256_set_epi16( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_permutex2var_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let idx = _mm256_set_epi16(1, 1<<4, 2, 1<<4, 3, 1<<4, 4, 1<<4, 5, 1<<4, 6, 1<<4, 7, 1<<4, 8, 1<<4); + let b = _mm256_set1_epi16(100); + let r = _mm256_mask_permutex2var_epi16(a, 0, idx, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_permutex2var_epi16(a, 0b11111111_11111111, idx, b); + let e = _mm256_set_epi16( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_permutex2var_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let idx = _mm256_set_epi16(1, 1<<4, 2, 1<<4, 3, 1<<4, 4, 1<<4, 5, 1<<4, 6, 1<<4, 7, 1<<4, 8, 1<<4); + let b = _mm256_set1_epi16(100); + let r = _mm256_maskz_permutex2var_epi16(0, a, idx, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_permutex2var_epi16(0b11111111_11111111, a, idx, b); + let e = _mm256_set_epi16( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask2_permutex2var_epi16() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let idx = _mm256_set_epi16(1, 1<<4, 2, 1<<4, 3, 1<<4, 4, 1<<4, 5, 1<<4, 6, 1<<4, 7, 1<<4, 8, 1<<4); + let b = _mm256_set1_epi16(100); + let r = _mm256_mask2_permutex2var_epi16(a, idx, 0, b); + assert_eq_m256i(r, idx); + let r = _mm256_mask2_permutex2var_epi16(a, idx, 0b11111111_11111111, b); + #[rustfmt::skip] + let e = _mm256_set_epi16( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_permutex2var_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm_set_epi16(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm_set1_epi16(100); + let r = _mm_permutex2var_epi16(a, idx, b); + let e = _mm_set_epi16(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_permutex2var_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm_set_epi16(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm_set1_epi16(100); + let r = _mm_mask_permutex2var_epi16(a, 0, idx, b); + assert_eq_m128i(r, a); + let r = _mm_mask_permutex2var_epi16(a, 0b11111111, idx, b); + let e = _mm_set_epi16(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_permutex2var_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm_set_epi16(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm_set1_epi16(100); + let r = _mm_maskz_permutex2var_epi16(0, a, idx, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_permutex2var_epi16(0b11111111, a, idx, b); + let e = _mm_set_epi16(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask2_permutex2var_epi16() { + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm_set_epi16(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm_set1_epi16(100); + let r = _mm_mask2_permutex2var_epi16(a, idx, 0, b); + assert_eq_m128i(r, idx); + let r = _mm_mask2_permutex2var_epi16(a, idx, 0b11111111, b); + let e = _mm_set_epi16(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_permutexvar_epi16() { + let idx = _mm512_set1_epi16(1); + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + let r = _mm512_permutexvar_epi16(idx, a); + let e = _mm512_set1_epi16(30); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_permutexvar_epi16() { + let idx = _mm512_set1_epi16(1); + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + let r = _mm512_mask_permutexvar_epi16(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutexvar_epi16(a, 0b11111111_11111111_11111111_11111111, idx, a); + let e = _mm512_set1_epi16(30); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_permutexvar_epi16() { + let idx = _mm512_set1_epi16(1); + #[rustfmt::skip] + let a = _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + let r = _mm512_maskz_permutexvar_epi16(0, idx, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutexvar_epi16(0b11111111_11111111_11111111_11111111, idx, a); + let e = _mm512_set1_epi16(30); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_permutexvar_epi16() { + let idx = _mm256_set1_epi16(1); + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm256_permutexvar_epi16(idx, a); + let e = _mm256_set1_epi16(14); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_permutexvar_epi16() { + let idx = _mm256_set1_epi16(1); + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm256_mask_permutexvar_epi16(a, 0, idx, a); + assert_eq_m256i(r, a); + let r = _mm256_mask_permutexvar_epi16(a, 0b11111111_11111111, idx, a); + let e = _mm256_set1_epi16(14); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_permutexvar_epi16() { + let idx = _mm256_set1_epi16(1); + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm256_maskz_permutexvar_epi16(0, idx, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_permutexvar_epi16(0b11111111_11111111, idx, a); + let e = _mm256_set1_epi16(14); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_permutexvar_epi16() { + let idx = _mm_set1_epi16(1); + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm_permutexvar_epi16(idx, a); + let e = _mm_set1_epi16(6); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_permutexvar_epi16() { + let idx = _mm_set1_epi16(1); + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm_mask_permutexvar_epi16(a, 0, idx, a); + assert_eq_m128i(r, a); + let r = _mm_mask_permutexvar_epi16(a, 0b11111111, idx, a); + let e = _mm_set1_epi16(6); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_permutexvar_epi16() { + let idx = _mm_set1_epi16(1); + let a = _mm_set_epi16(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm_maskz_permutexvar_epi16(0, idx, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_permutexvar_epi16(0b11111111, idx, a); + let e = _mm_set1_epi16(6); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_blend_epi16() { + let a = _mm512_set1_epi16(1); + let b = _mm512_set1_epi16(2); + let r = _mm512_mask_blend_epi16(0b11111111_00000000_11111111_00000000, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_blend_epi16() { + let a = _mm256_set1_epi16(1); + let b = _mm256_set1_epi16(2); + let r = _mm256_mask_blend_epi16(0b11111111_00000000, a, b); + let e = _mm256_set_epi16(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_blend_epi16() { + let a = _mm_set1_epi16(1); + let b = _mm_set1_epi16(2); + let r = _mm_mask_blend_epi16(0b11110000, a, b); + let e = _mm_set_epi16(2, 2, 2, 2, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_blend_epi8() { + let a = _mm512_set1_epi8(1); + let b = _mm512_set1_epi8(2); + let r = _mm512_mask_blend_epi8( + 0b11111111_00000000_11111111_00000000_11111111_00000000_11111111_00000000, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_blend_epi8() { + let a = _mm256_set1_epi8(1); + let b = _mm256_set1_epi8(2); + let r = _mm256_mask_blend_epi8(0b11111111_00000000_11111111_00000000, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_blend_epi8() { + let a = _mm_set1_epi8(1); + let b = _mm_set1_epi8(2); + let r = _mm_mask_blend_epi8(0b11111111_00000000, a, b); + let e = _mm_set_epi8(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_broadcastw_epi16() { + let a = _mm_set_epi16(17, 18, 19, 20, 21, 22, 23, 24); + let r = _mm512_broadcastw_epi16(a); + let e = _mm512_set1_epi16(24); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_broadcastw_epi16() { + let src = _mm512_set1_epi16(1); + let a = _mm_set_epi16(17, 18, 19, 20, 21, 22, 23, 24); + let r = _mm512_mask_broadcastw_epi16(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_broadcastw_epi16(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(24); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_broadcastw_epi16() { + let a = _mm_set_epi16(17, 18, 19, 20, 21, 22, 23, 24); + let r = _mm512_maskz_broadcastw_epi16(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_broadcastw_epi16(0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(24); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_broadcastw_epi16() { + let src = _mm256_set1_epi16(1); + let a = _mm_set_epi16(17, 18, 19, 20, 21, 22, 23, 24); + let r = _mm256_mask_broadcastw_epi16(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm256_mask_broadcastw_epi16(src, 0b11111111_11111111, a); + let e = _mm256_set1_epi16(24); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_broadcastw_epi16() { + let a = _mm_set_epi16(17, 18, 19, 20, 21, 22, 23, 24); + let r = _mm256_maskz_broadcastw_epi16(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_broadcastw_epi16(0b11111111_11111111, a); + let e = _mm256_set1_epi16(24); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_broadcastw_epi16() { + let src = _mm_set1_epi16(1); + let a = _mm_set_epi16(17, 18, 19, 20, 21, 22, 23, 24); + let r = _mm_mask_broadcastw_epi16(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm_mask_broadcastw_epi16(src, 0b11111111, a); + let e = _mm_set1_epi16(24); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_broadcastw_epi16() { + let a = _mm_set_epi16(17, 18, 19, 20, 21, 22, 23, 24); + let r = _mm_maskz_broadcastw_epi16(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_broadcastw_epi16(0b11111111, a); + let e = _mm_set1_epi16(24); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_broadcastb_epi8() { + let a = _mm_set_epi8( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm512_broadcastb_epi8(a); + let e = _mm512_set1_epi8(32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_broadcastb_epi8() { + let src = _mm512_set1_epi8(1); + let a = _mm_set_epi8( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm512_mask_broadcastb_epi8(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_broadcastb_epi8( + src, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + ); + let e = _mm512_set1_epi8(32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_broadcastb_epi8() { + let a = _mm_set_epi8( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm512_maskz_broadcastb_epi8(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_broadcastb_epi8( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + ); + let e = _mm512_set1_epi8(32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_broadcastb_epi8() { + let src = _mm256_set1_epi8(1); + let a = _mm_set_epi8( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm256_mask_broadcastb_epi8(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm256_mask_broadcastb_epi8(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(32); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_broadcastb_epi8() { + let a = _mm_set_epi8( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm256_maskz_broadcastb_epi8(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_broadcastb_epi8(0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(32); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_broadcastb_epi8() { + let src = _mm_set1_epi8(1); + let a = _mm_set_epi8( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm_mask_broadcastb_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm_mask_broadcastb_epi8(src, 0b11111111_11111111, a); + let e = _mm_set1_epi8(32); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_broadcastb_epi8() { + let a = _mm_set_epi8( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm_maskz_broadcastb_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_broadcastb_epi8(0b11111111_11111111, a); + let e = _mm_set1_epi8(32); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_unpackhi_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm512_set_epi16(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + let r = _mm512_unpackhi_epi16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(33, 1, 34, 2, 35, 3, 36, 4, 41, 9, 42, 10, 43, 11, 44, 12, + 49, 17, 50, 18, 51, 19, 52, 20, 57, 25, 58, 26, 59, 27, 60, 28); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_unpackhi_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm512_set_epi16(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + let r = _mm512_mask_unpackhi_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_unpackhi_epi16(a, 0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(33, 1, 34, 2, 35, 3, 36, 4, 41, 9, 42, 10, 43, 11, 44, 12, + 49, 17, 50, 18, 51, 19, 52, 20, 57, 25, 58, 26, 59, 27, 60, 28); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_unpackhi_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm512_set_epi16(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + let r = _mm512_maskz_unpackhi_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_unpackhi_epi16(0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(33, 1, 34, 2, 35, 3, 36, 4, 41, 9, 42, 10, 43, 11, 44, 12, + 49, 17, 50, 18, 51, 19, 52, 20, 57, 25, 58, 26, 59, 27, 60, 28); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_unpackhi_epi16() { + let a = _mm256_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm256_set_epi16( + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + ); + let r = _mm256_mask_unpackhi_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_unpackhi_epi16(a, 0b11111111_11111111, a, b); + let e = _mm256_set_epi16(33, 1, 34, 2, 35, 3, 36, 4, 41, 9, 42, 10, 43, 11, 44, 12); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_unpackhi_epi16() { + let a = _mm256_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm256_set_epi16( + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + ); + let r = _mm256_maskz_unpackhi_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_unpackhi_epi16(0b11111111_11111111, a, b); + let e = _mm256_set_epi16(33, 1, 34, 2, 35, 3, 36, 4, 41, 9, 42, 10, 43, 11, 44, 12); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_unpackhi_epi16() { + let a = _mm_set_epi16(1, 2, 3, 4, 5, 6, 7, 8); + let b = _mm_set_epi16(33, 34, 35, 36, 37, 38, 39, 40); + let r = _mm_mask_unpackhi_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_unpackhi_epi16(a, 0b11111111, a, b); + let e = _mm_set_epi16(33, 1, 34, 2, 35, 3, 36, 4); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_unpackhi_epi16() { + let a = _mm_set_epi16(1, 2, 3, 4, 5, 6, 7, 8); + let b = _mm_set_epi16(33, 34, 35, 36, 37, 38, 39, 40); + let r = _mm_maskz_unpackhi_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_unpackhi_epi16(0b11111111, a, b); + let e = _mm_set_epi16(33, 1, 34, 2, 35, 3, 36, 4); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_unpackhi_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + #[rustfmt::skip] + let b = _mm512_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0); + let r = _mm512_unpackhi_epi8(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(65, 1, 66, 2, 67, 3, 68, 4, 69, 5, 70, 6, 71, 7, 72, 8, + 81, 17, 82, 18, 83, 19, 84, 20, 85, 21, 86, 22, 87, 23, 88, 24, + 97, 33, 98, 34, 99, 35, 100, 36, 101, 37, 102, 38, 103, 39, 104, 40, + 113, 49, 114, 50, 115, 51, 116, 52, 117, 53, 118, 54, 119, 55, 120, 56); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_unpackhi_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + #[rustfmt::skip] + let b = _mm512_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0); + let r = _mm512_mask_unpackhi_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_unpackhi_epi8( + a, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(65, 1, 66, 2, 67, 3, 68, 4, 69, 5, 70, 6, 71, 7, 72, 8, + 81, 17, 82, 18, 83, 19, 84, 20, 85, 21, 86, 22, 87, 23, 88, 24, + 97, 33, 98, 34, 99, 35, 100, 36, 101, 37, 102, 38, 103, 39, 104, 40, + 113, 49, 114, 50, 115, 51, 116, 52, 117, 53, 118, 54, 119, 55, 120, 56); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_unpackhi_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + #[rustfmt::skip] + let b = _mm512_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0); + let r = _mm512_maskz_unpackhi_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_unpackhi_epi8( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(65, 1, 66, 2, 67, 3, 68, 4, 69, 5, 70, 6, 71, 7, 72, 8, + 81, 17, 82, 18, 83, 19, 84, 20, 85, 21, 86, 22, 87, 23, 88, 24, + 97, 33, 98, 34, 99, 35, 100, 36, 101, 37, 102, 38, 103, 39, 104, 40, + 113, 49, 114, 50, 115, 51, 116, 52, 117, 53, 118, 54, 119, 55, 120, 56); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_unpackhi_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm256_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96); + let r = _mm256_mask_unpackhi_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_unpackhi_epi8(a, 0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(65, 1, 66, 2, 67, 3, 68, 4, 69, 5, 70, 6, 71, 7, 72, 8, + 81, 17, 82, 18, 83, 19, 84, 20, 85, 21, 86, 22, 87, 23, 88, 24); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_unpackhi_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm256_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96); + let r = _mm256_maskz_unpackhi_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_unpackhi_epi8(0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(65, 1, 66, 2, 67, 3, 68, 4, 69, 5, 70, 6, 71, 7, 72, 8, + 81, 17, 82, 18, 83, 19, 84, 20, 85, 21, 86, 22, 87, 23, 88, 24); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_unpackhi_epi8() { + let a = _mm_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm_set_epi8( + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + ); + let r = _mm_mask_unpackhi_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_unpackhi_epi8(a, 0b11111111_11111111, a, b); + let e = _mm_set_epi8(65, 1, 66, 2, 67, 3, 68, 4, 69, 5, 70, 6, 71, 7, 72, 8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_unpackhi_epi8() { + let a = _mm_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm_set_epi8( + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + ); + let r = _mm_maskz_unpackhi_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_unpackhi_epi8(0b11111111_11111111, a, b); + let e = _mm_set_epi8(65, 1, 66, 2, 67, 3, 68, 4, 69, 5, 70, 6, 71, 7, 72, 8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_unpacklo_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm512_set_epi16(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + let r = _mm512_unpacklo_epi16(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(37, 5, 38, 6, 39, 7, 40, 8, 45, 13, 46, 14, 47, 15, 48, 16, + 53, 21, 54, 22, 55, 23, 56, 24, 61, 29, 62, 30, 63, 31, 64, 32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_unpacklo_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm512_set_epi16(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + let r = _mm512_mask_unpacklo_epi16(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_unpacklo_epi16(a, 0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(37, 5, 38, 6, 39, 7, 40, 8, 45, 13, 46, 14, 47, 15, 48, 16, + 53, 21, 54, 22, 55, 23, 56, 24, 61, 29, 62, 30, 63, 31, 64, 32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_unpacklo_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm512_set_epi16(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + let r = _mm512_maskz_unpacklo_epi16(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_unpacklo_epi16(0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm512_set_epi16(37, 5, 38, 6, 39, 7, 40, 8, 45, 13, 46, 14, 47, 15, 48, 16, + 53, 21, 54, 22, 55, 23, 56, 24, 61, 29, 62, 30, 63, 31, 64, 32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_unpacklo_epi16() { + let a = _mm256_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm256_set_epi16( + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + ); + let r = _mm256_mask_unpacklo_epi16(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_unpacklo_epi16(a, 0b11111111_11111111, a, b); + let e = _mm256_set_epi16(37, 5, 38, 6, 39, 7, 40, 8, 45, 13, 46, 14, 47, 15, 48, 16); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_unpacklo_epi16() { + let a = _mm256_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm256_set_epi16( + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + ); + let r = _mm256_maskz_unpacklo_epi16(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_unpacklo_epi16(0b11111111_11111111, a, b); + let e = _mm256_set_epi16(37, 5, 38, 6, 39, 7, 40, 8, 45, 13, 46, 14, 47, 15, 48, 16); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_unpacklo_epi16() { + let a = _mm_set_epi16(1, 2, 3, 4, 5, 6, 7, 8); + let b = _mm_set_epi16(33, 34, 35, 36, 37, 38, 39, 40); + let r = _mm_mask_unpacklo_epi16(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_unpacklo_epi16(a, 0b11111111, a, b); + let e = _mm_set_epi16(37, 5, 38, 6, 39, 7, 40, 8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_unpacklo_epi16() { + let a = _mm_set_epi16(1, 2, 3, 4, 5, 6, 7, 8); + let b = _mm_set_epi16(33, 34, 35, 36, 37, 38, 39, 40); + let r = _mm_maskz_unpacklo_epi16(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_unpacklo_epi16(0b11111111, a, b); + let e = _mm_set_epi16(37, 5, 38, 6, 39, 7, 40, 8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_unpacklo_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + #[rustfmt::skip] + let b = _mm512_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0); + let r = _mm512_unpacklo_epi8(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(73, 9, 74, 10, 75, 11, 76, 12, 77, 13, 78, 14, 79, 15, 80, 16, + 89, 25, 90, 26, 91, 27, 92, 28, 93, 29, 94, 30, 95, 31, 96, 32, + 105, 41, 106, 42, 107, 43, 108, 44, 109, 45, 110, 46, 111, 47, 112, 48, + 121, 57, 122, 58, 123, 59, 124, 60, 125, 61, 126, 62, 127, 63, 0, 64); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_unpacklo_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + #[rustfmt::skip] + let b = _mm512_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0); + let r = _mm512_mask_unpacklo_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_unpacklo_epi8( + a, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(73, 9, 74, 10, 75, 11, 76, 12, 77, 13, 78, 14, 79, 15, 80, 16, + 89, 25, 90, 26, 91, 27, 92, 28, 93, 29, 94, 30, 95, 31, 96, 32, + 105, 41, 106, 42, 107, 43, 108, 44, 109, 45, 110, 46, 111, 47, 112, 48, + 121, 57, 122, 58, 123, 59, 124, 60, 125, 61, 126, 62, 127, 63, 0, 64); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_unpacklo_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64); + #[rustfmt::skip] + let b = _mm512_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0); + let r = _mm512_maskz_unpacklo_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_unpacklo_epi8( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(73, 9, 74, 10, 75, 11, 76, 12, 77, 13, 78, 14, 79, 15, 80, 16, + 89, 25, 90, 26, 91, 27, 92, 28, 93, 29, 94, 30, 95, 31, 96, 32, + 105, 41, 106, 42, 107, 43, 108, 44, 109, 45, 110, 46, 111, 47, 112, 48, + 121, 57, 122, 58, 123, 59, 124, 60, 125, 61, 126, 62, 127, 63, 0, 64); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_unpacklo_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm256_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96); + let r = _mm256_mask_unpacklo_epi8(a, 0, a, b); + assert_eq_m256i(r, a); + let r = _mm256_mask_unpacklo_epi8(a, 0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(73, 9, 74, 10, 75, 11, 76, 12, 77, 13, 78, 14, 79, 15, 80, 16, + 89, 25, 90, 26, 91, 27, 92, 28, 93, 29, 94, 30, 95, 31, 96, 32); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_unpacklo_epi8() { + #[rustfmt::skip] + let a = _mm256_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + #[rustfmt::skip] + let b = _mm256_set_epi8(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96); + let r = _mm256_maskz_unpacklo_epi8(0, a, b); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_unpacklo_epi8(0b11111111_11111111_11111111_11111111, a, b); + #[rustfmt::skip] + let e = _mm256_set_epi8(73, 9, 74, 10, 75, 11, 76, 12, 77, 13, 78, 14, 79, 15, 80, 16, + 89, 25, 90, 26, 91, 27, 92, 28, 93, 29, 94, 30, 95, 31, 96, 32); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_unpacklo_epi8() { + let a = _mm_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm_set_epi8( + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + ); + let r = _mm_mask_unpacklo_epi8(a, 0, a, b); + assert_eq_m128i(r, a); + let r = _mm_mask_unpacklo_epi8(a, 0b11111111_11111111, a, b); + let e = _mm_set_epi8( + 73, 9, 74, 10, 75, 11, 76, 12, 77, 13, 78, 14, 79, 15, 80, 16, + ); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_unpacklo_epi8() { + let a = _mm_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm_set_epi8( + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + ); + let r = _mm_maskz_unpacklo_epi8(0, a, b); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_unpacklo_epi8(0b11111111_11111111, a, b); + let e = _mm_set_epi8( + 73, 9, 74, 10, 75, 11, 76, 12, 77, 13, 78, 14, 79, 15, 80, 16, + ); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_mov_epi16() { + let src = _mm512_set1_epi16(1); + let a = _mm512_set1_epi16(2); + let r = _mm512_mask_mov_epi16(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_mov_epi16(src, 0b11111111_11111111_11111111_11111111, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_mov_epi16() { + let a = _mm512_set1_epi16(2); + let r = _mm512_maskz_mov_epi16(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mov_epi16(0b11111111_11111111_11111111_11111111, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_mov_epi16() { + let src = _mm256_set1_epi16(1); + let a = _mm256_set1_epi16(2); + let r = _mm256_mask_mov_epi16(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm256_mask_mov_epi16(src, 0b11111111_11111111, a); + assert_eq_m256i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_mov_epi16() { + let a = _mm256_set1_epi16(2); + let r = _mm256_maskz_mov_epi16(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_mov_epi16(0b11111111_11111111, a); + assert_eq_m256i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_mov_epi16() { + let src = _mm_set1_epi16(1); + let a = _mm_set1_epi16(2); + let r = _mm_mask_mov_epi16(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm_mask_mov_epi16(src, 0b11111111, a); + assert_eq_m128i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_mov_epi16() { + let a = _mm_set1_epi16(2); + let r = _mm_maskz_mov_epi16(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_mov_epi16(0b11111111, a); + assert_eq_m128i(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_mov_epi8() { + let src = _mm512_set1_epi8(1); + let a = _mm512_set1_epi8(2); + let r = _mm512_mask_mov_epi8(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_mov_epi8( + src, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + ); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_mov_epi8() { + let a = _mm512_set1_epi8(2); + let r = _mm512_maskz_mov_epi8(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mov_epi8( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + ); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_mov_epi8() { + let src = _mm256_set1_epi8(1); + let a = _mm256_set1_epi8(2); + let r = _mm256_mask_mov_epi8(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm256_mask_mov_epi8(src, 0b11111111_11111111_11111111_11111111, a); + assert_eq_m256i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_mov_epi8() { + let a = _mm256_set1_epi8(2); + let r = _mm256_maskz_mov_epi8(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_mov_epi8(0b11111111_11111111_11111111_11111111, a); + assert_eq_m256i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_mov_epi8() { + let src = _mm_set1_epi8(1); + let a = _mm_set1_epi8(2); + let r = _mm_mask_mov_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm_mask_mov_epi8(src, 0b11111111_11111111, a); + assert_eq_m128i(r, a); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_mov_epi8() { + let a = _mm_set1_epi8(2); + let r = _mm_maskz_mov_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_mov_epi8(0b11111111_11111111, a); + assert_eq_m128i(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_set1_epi16() { + let src = _mm512_set1_epi16(2); + let a: i16 = 11; + let r = _mm512_mask_set1_epi16(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_set1_epi16(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(11); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_set1_epi16() { + let a: i16 = 11; + let r = _mm512_maskz_set1_epi16(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_set1_epi16(0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(11); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_set1_epi16() { + let src = _mm256_set1_epi16(2); + let a: i16 = 11; + let r = _mm256_mask_set1_epi16(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm256_mask_set1_epi16(src, 0b11111111_11111111, a); + let e = _mm256_set1_epi16(11); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_set1_epi16() { + let a: i16 = 11; + let r = _mm256_maskz_set1_epi16(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_set1_epi16(0b11111111_11111111, a); + let e = _mm256_set1_epi16(11); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_set1_epi16() { + let src = _mm_set1_epi16(2); + let a: i16 = 11; + let r = _mm_mask_set1_epi16(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm_mask_set1_epi16(src, 0b11111111, a); + let e = _mm_set1_epi16(11); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_set1_epi16() { + let a: i16 = 11; + let r = _mm_maskz_set1_epi16(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_set1_epi16(0b11111111, a); + let e = _mm_set1_epi16(11); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_set1_epi8() { + let src = _mm512_set1_epi8(2); + let a: i8 = 11; + let r = _mm512_mask_set1_epi8(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_set1_epi8( + src, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + ); + let e = _mm512_set1_epi8(11); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_set1_epi8() { + let a: i8 = 11; + let r = _mm512_maskz_set1_epi8(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_set1_epi8( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + ); + let e = _mm512_set1_epi8(11); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_mask_set1_epi8() { + let src = _mm256_set1_epi8(2); + let a: i8 = 11; + let r = _mm256_mask_set1_epi8(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm256_mask_set1_epi8(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(11); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_set1_epi8() { + let a: i8 = 11; + let r = _mm256_maskz_set1_epi8(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_set1_epi8(0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(11); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_mask_set1_epi8() { + let src = _mm_set1_epi8(2); + let a: i8 = 11; + let r = _mm_mask_set1_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm_mask_set1_epi8(src, 0b11111111_11111111, a); + let e = _mm_set1_epi8(11); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw,avx512vl")] + unsafe fn test_mm_maskz_set1_epi8() { + let a: i8 = 11; + let r = _mm_maskz_set1_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_set1_epi8(0b11111111_11111111, a); + let e = _mm_set1_epi8(11); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_shufflelo_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 0, 1, 2, 3, 7, 6, 6, 4, 8, 9, 10, 11, 15, 14, 14, 12, + 16, 17, 18, 19, 23, 22, 22, 20, 24, 25, 26, 27, 31, 30, 30, 28, + ); + let r = _mm512_shufflelo_epi16(a, 0b00_01_01_11); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_shufflelo_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + let r = _mm512_mask_shufflelo_epi16(a, 0, a, 0b00_01_01_11); + assert_eq_m512i(r, a); + let r = + _mm512_mask_shufflelo_epi16(a, 0b11111111_11111111_11111111_11111111, a, 0b00_01_01_11); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 0, 1, 2, 3, 7, 6, 6, 4, 8, 9, 10, 11, 15, 14, 14, 12, + 16, 17, 18, 19, 23, 22, 22, 20, 24, 25, 26, 27, 31, 30, 30, 28, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_shufflelo_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + let r = _mm512_maskz_shufflelo_epi16(0, a, 0b00_01_01_11); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = + _mm512_maskz_shufflelo_epi16(0b11111111_11111111_11111111_11111111, a, 0b00_01_01_11); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 0, 1, 2, 3, 7, 6, 6, 4, 8, 9, 10, 11, 15, 14, 14, 12, + 16, 17, 18, 19, 23, 22, 22, 20, 24, 25, 26, 27, 31, 30, 30, 28, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_shufflehi_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 3, 2, 2, 0, 4, 5, 6, 7, 11, 10, 10, 8, 12, 13, 14, 15, + 19, 18, 18, 16, 20, 21, 22, 23, 27, 26, 26, 24, 28, 29, 30, 31, + ); + let r = _mm512_shufflehi_epi16(a, 0b00_01_01_11); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_shufflehi_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + let r = _mm512_mask_shufflehi_epi16(a, 0, a, 0b00_01_01_11); + assert_eq_m512i(r, a); + let r = + _mm512_mask_shufflehi_epi16(a, 0b11111111_11111111_11111111_11111111, a, 0b00_01_01_11); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 3, 2, 2, 0, 4, 5, 6, 7, 11, 10, 10, 8, 12, 13, 14, 15, + 19, 18, 18, 16, 20, 21, 22, 23, 27, 26, 26, 24, 28, 29, 30, 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_shufflehi_epi16() { + #[rustfmt::skip] + let a = _mm512_set_epi16( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + let r = _mm512_maskz_shufflehi_epi16(0, a, 0b00_01_01_11); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = + _mm512_maskz_shufflehi_epi16(0b11111111_11111111_11111111_11111111, a, 0b00_01_01_11); + #[rustfmt::skip] + let e = _mm512_set_epi16( + 3, 2, 2, 0, 4, 5, 6, 7, 11, 10, 10, 8, 12, 13, 14, 15, + 19, 18, 18, 16, 20, 21, 22, 23, 27, 26, 26, 24, 28, 29, 30, 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_shuffle_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63); + let b = _mm512_set1_epi8(1); + let r = _mm512_shuffle_epi8(a, b); + #[rustfmt::skip] + let e = _mm512_set_epi8(14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_shuffle_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63); + let b = _mm512_set1_epi8(1); + let r = _mm512_mask_shuffle_epi8(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_epi8( + a, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_shuffle_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63); + let b = _mm512_set1_epi8(1); + let r = _mm512_maskz_shuffle_epi8(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_epi8( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8(14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_test_epi16_mask() { + let a = _mm512_set1_epi16(1 << 0); + let b = _mm512_set1_epi16(1 << 0 | 1 << 1); + let r = _mm512_test_epi16_mask(a, b); + let e: __mmask32 = 0b11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_test_epi16_mask() { + let a = _mm512_set1_epi16(1 << 0); + let b = _mm512_set1_epi16(1 << 0 | 1 << 1); + let r = _mm512_mask_test_epi16_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_test_epi16_mask(0b11111111_11111111_11111111_11111111, a, b); + let e: __mmask32 = 0b11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_test_epi8_mask() { + let a = _mm512_set1_epi8(1 << 0); + let b = _mm512_set1_epi8(1 << 0 | 1 << 1); + let r = _mm512_test_epi8_mask(a, b); + let e: __mmask64 = + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_test_epi8_mask() { + let a = _mm512_set1_epi8(1 << 0); + let b = _mm512_set1_epi8(1 << 0 | 1 << 1); + let r = _mm512_mask_test_epi8_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_test_epi8_mask( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + let e: __mmask64 = + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_testn_epi16_mask() { + let a = _mm512_set1_epi16(1 << 0); + let b = _mm512_set1_epi16(1 << 0 | 1 << 1); + let r = _mm512_testn_epi16_mask(a, b); + let e: __mmask32 = 0b00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_testn_epi16_mask() { + let a = _mm512_set1_epi16(1 << 0); + let b = _mm512_set1_epi16(1 << 0 | 1 << 1); + let r = _mm512_mask_testn_epi16_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_testn_epi16_mask(0b11111111_11111111_11111111_11111111, a, b); + let e: __mmask32 = 0b00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_testn_epi8_mask() { + let a = _mm512_set1_epi8(1 << 0); + let b = _mm512_set1_epi8(1 << 0 | 1 << 1); + let r = _mm512_testn_epi8_mask(a, b); + let e: __mmask64 = + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_testn_epi8_mask() { + let a = _mm512_set1_epi8(1 << 0); + let b = _mm512_set1_epi8(1 << 0 | 1 << 1); + let r = _mm512_mask_testn_epi8_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_testn_epi8_mask( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + ); + let e: __mmask64 = + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_store_mask64() { + let a: __mmask64 = + 0b11111111_00000000_11111111_00000000_11111111_00000000_11111111_00000000; + let mut r = 0; + _store_mask64(&mut r as *mut _ as *mut u64, a); + assert_eq!(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_store_mask32() { + let a: __mmask32 = 0b11111111_00000000_11111111_00000000; + let mut r = 0; + _store_mask32(&mut r as *mut _ as *mut u32, a); + assert_eq!(r, a); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_load_mask64() { + let p: __mmask64 = + 0b11111111_00000000_11111111_00000000_11111111_00000000_11111111_00000000; + let r = _load_mask64(&p); + let e: __mmask64 = + 0b11111111_00000000_11111111_00000000_11111111_00000000_11111111_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_load_mask32() { + let p: __mmask32 = 0b11111111_00000000_11111111_00000000; + let r = _load_mask32(&p); + let e: __mmask32 = 0b11111111_00000000_11111111_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_sad_epu8() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(4); + let r = _mm512_sad_epu8(a, b); + let e = _mm512_set1_epi64(16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_dbsad_epu8() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(4); + let r = _mm512_dbsad_epu8(a, b, 0); + let e = _mm512_set1_epi16(8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_dbsad_epu8() { + let src = _mm512_set1_epi16(1); + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(4); + let r = _mm512_mask_dbsad_epu8(src, 0, a, b, 0); + assert_eq_m512i(r, src); + let r = _mm512_mask_dbsad_epu8(src, 0b11111111_11111111_11111111_11111111, a, b, 0); + let e = _mm512_set1_epi16(8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_dbsad_epu8() { + let a = _mm512_set1_epi8(2); + let b = _mm512_set1_epi8(4); + let r = _mm512_maskz_dbsad_epu8(0, a, b, 0); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_dbsad_epu8(0b11111111_11111111_11111111_11111111, a, b, 0); + let e = _mm512_set1_epi16(8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_movepi16_mask() { + let a = _mm512_set1_epi16(1 << 15); + let r = _mm512_movepi16_mask(a); + let e: __mmask32 = 0b11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_movepi8_mask() { + let a = _mm512_set1_epi8(1 << 7); + let r = _mm512_movepi8_mask(a); + let e: __mmask64 = + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_movm_epi16() { + let a: __mmask32 = 0b11111111_11111111_11111111_11111111; + let r = _mm512_movm_epi16(a); + let e = _mm512_set1_epi16( + 1 << 15 + | 1 << 14 + | 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_movm_epi8() { + let a: __mmask64 = + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111; + let r = _mm512_movm_epi8(a); + let e = + _mm512_set1_epi8(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kadd_mask32() { + let a: __mmask32 = 11; + let b: __mmask32 = 22; + let r = _kadd_mask32(a, b); + let e: __mmask32 = 33; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kadd_mask64() { + let a: __mmask64 = 11; + let b: __mmask64 = 22; + let r = _kadd_mask64(a, b); + let e: __mmask64 = 33; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kand_mask32() { + let a: __mmask32 = 0b11001100_00110011_11001100_00110011; + let b: __mmask32 = 0b11001100_00110011_11001100_00110011; + let r = _kand_mask32(a, b); + let e: __mmask32 = 0b11001100_00110011_11001100_00110011; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kand_mask64() { + let a: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let b: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let r = _kand_mask64(a, b); + let e: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_knot_mask32() { + let a: __mmask32 = 0b11001100_00110011_11001100_00110011; + let r = _knot_mask32(a); + let e: __mmask32 = 0b00110011_11001100_00110011_11001100; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_knot_mask64() { + let a: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let r = _knot_mask64(a); + let e: __mmask64 = + 0b00110011_11001100_00110011_11001100_00110011_11001100_00110011_11001100; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kandn_mask32() { + let a: __mmask32 = 0b11001100_00110011_11001100_00110011; + let b: __mmask32 = 0b11001100_00110011_11001100_00110011; + let r = _kandn_mask32(a, b); + let e: __mmask32 = 0b00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kandn_mask64() { + let a: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let b: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let r = _kandn_mask64(a, b); + let e: __mmask64 = + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kor_mask32() { + let a: __mmask32 = 0b00110011_11001100_00110011_11001100; + let b: __mmask32 = 0b11001100_00110011_11001100_00110011; + let r = _kor_mask32(a, b); + let e: __mmask32 = 0b11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kor_mask64() { + let a: __mmask64 = + 0b00110011_11001100_00110011_11001100_00110011_11001100_00110011_11001100; + let b: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let r = _kor_mask64(a, b); + let e: __mmask64 = + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kxor_mask32() { + let a: __mmask32 = 0b00110011_11001100_00110011_11001100; + let b: __mmask32 = 0b11001100_00110011_11001100_00110011; + let r = _kxor_mask32(a, b); + let e: __mmask32 = 0b11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kxor_mask64() { + let a: __mmask64 = + 0b00110011_11001100_00110011_11001100_00110011_11001100_00110011_11001100; + let b: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let r = _kxor_mask64(a, b); + let e: __mmask64 = + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kxnor_mask32() { + let a: __mmask32 = 0b00110011_11001100_00110011_11001100; + let b: __mmask32 = 0b11001100_00110011_11001100_00110011; + let r = _kxnor_mask32(a, b); + let e: __mmask32 = 0b00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_kxnor_mask64() { + let a: __mmask64 = + 0b00110011_11001100_00110011_11001100_00110011_11001100_00110011_11001100; + let b: __mmask64 = + 0b11001100_00110011_11001100_00110011_11001100_00110011_11001100_00110011; + let r = _kxnor_mask64(a, b); + let e: __mmask64 = + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cvtepi16_epi8() { + let a = _mm512_set1_epi16(2); + let r = _mm512_cvtepi16_epi8(a); + let e = _mm256_set1_epi8(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cvtepi16_epi8() { + let src = _mm256_set1_epi8(1); + let a = _mm512_set1_epi16(2); + let r = _mm512_mask_cvtepi16_epi8(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtepi16_epi8(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_cvtepi16_epi8() { + let a = _mm512_set1_epi16(2); + let r = _mm512_maskz_cvtepi16_epi8(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtepi16_epi8(0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cvtsepi16_epi8() { + let a = _mm512_set1_epi16(i16::MAX); + let r = _mm512_cvtsepi16_epi8(a); + let e = _mm256_set1_epi8(i8::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cvtsepi16_epi8() { + let src = _mm256_set1_epi8(1); + let a = _mm512_set1_epi16(i16::MAX); + let r = _mm512_mask_cvtsepi16_epi8(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtsepi16_epi8(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(i8::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_cvtsepi16_epi8() { + let a = _mm512_set1_epi16(i16::MAX); + let r = _mm512_maskz_cvtsepi16_epi8(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtsepi16_epi8(0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(i8::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cvtusepi16_epi8() { + let a = _mm512_set1_epi16(i16::MIN); + let r = _mm512_cvtusepi16_epi8(a); + let e = _mm256_set1_epi8(-1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cvtusepi16_epi8() { + let src = _mm256_set1_epi8(1); + let a = _mm512_set1_epi16(i16::MIN); + let r = _mm512_mask_cvtusepi16_epi8(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtusepi16_epi8(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(-1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_cvtusepi16_epi8() { + let a = _mm512_set1_epi16(i16::MIN); + let r = _mm512_maskz_cvtusepi16_epi8(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtusepi16_epi8(0b11111111_11111111_11111111_11111111, a); + let e = _mm256_set1_epi8(-1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cvtepi8_epi16() { + let a = _mm256_set1_epi8(2); + let r = _mm512_cvtepi8_epi16(a); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cvtepi8_epi16() { + let src = _mm512_set1_epi16(1); + let a = _mm256_set1_epi8(2); + let r = _mm512_mask_cvtepi8_epi16(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepi8_epi16(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_cvtepi8_epi16() { + let a = _mm256_set1_epi8(2); + let r = _mm512_maskz_cvtepi8_epi16(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepi8_epi16(0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_cvtepu8_epi16() { + let a = _mm256_set1_epi8(2); + let r = _mm512_cvtepu8_epi16(a); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_cvtepu8_epi16() { + let src = _mm512_set1_epi16(1); + let a = _mm256_set1_epi8(2); + let r = _mm512_mask_cvtepu8_epi16(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepu8_epi16(src, 0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_cvtepu8_epi16() { + let a = _mm256_set1_epi8(2); + let r = _mm512_maskz_cvtepu8_epi16(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepu8_epi16(0b11111111_11111111_11111111_11111111, a); + let e = _mm512_set1_epi16(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_bslli_epi128() { + #[rustfmt::skip] + let a = _mm512_set_epi8( + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + ); + let r = _mm512_bslli_epi128(a, 9); + #[rustfmt::skip] + let e = _mm512_set_epi8( + 0, 0, 0, 1, 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, 1, 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, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_bsrli_epi128() { + #[rustfmt::skip] + let a = _mm512_set_epi8( + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + ); + let r = _mm512_bsrli_epi128(a, 9); + #[rustfmt::skip] + let e = _mm512_set_epi8( + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_alignr_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8( + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + ); + let b = _mm512_set1_epi8(1); + let r = _mm512_alignr_epi8(a, b, 14); + #[rustfmt::skip] + let e = _mm512_set_epi8( + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_mask_alignr_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8( + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + ); + let b = _mm512_set1_epi8(1); + let r = _mm512_mask_alignr_epi8(a, 0, a, b, 14); + assert_eq_m512i(r, a); + let r = _mm512_mask_alignr_epi8( + a, + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + 14, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8( + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512bw")] + unsafe fn test_mm512_maskz_alignr_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8( + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + ); + let b = _mm512_set1_epi8(1); + let r = _mm512_maskz_alignr_epi8(0, a, b, 14); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_alignr_epi8( + 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111, + a, + b, + 14, + ); + #[rustfmt::skip] + let e = _mm512_set_epi8( + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, + ); + assert_eq_m512i(r, e); + } +} diff --git a/library/stdarch/crates/core_arch/src/x86/avx512cd.rs b/library/stdarch/crates/core_arch/src/x86/avx512cd.rs new file mode 100644 index 0000000000..ac9d3aed35 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/avx512cd.rs @@ -0,0 +1,1170 @@ +use crate::{ + core_arch::{simd::*, simd_llvm::*, x86::*}, + mem::transmute, +}; + +#[cfg(test)] +use stdarch_test::assert_instr; + +/// Broadcast the low 16-bits from input mask k to all 32-bit elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastmw_epi32&expand=553) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpbroadcast))] // should be vpbroadcastmw2d +pub unsafe fn _mm512_broadcastmw_epi32(k: __mmask16) -> __m512i { + _mm512_set1_epi32(k as i32) +} + +/// Broadcast the low 16-bits from input mask k to all 32-bit elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_broadcastmw_epi32&expand=552) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcast))] // should be vpbroadcastmw2d +pub unsafe fn _mm256_broadcastmw_epi32(k: __mmask16) -> __m256i { + _mm256_set1_epi32(k as i32) +} + +/// Broadcast the low 16-bits from input mask k to all 32-bit elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_broadcastmw_epi32&expand=551) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcast))] // should be vpbroadcastmw2d +pub unsafe fn _mm_broadcastmw_epi32(k: __mmask16) -> __m128i { + _mm_set1_epi32(k as i32) +} + +/// Broadcast the low 8-bits from input mask k to all 64-bit elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastmb_epi64&expand=550) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpbroadcast))] // should be vpbroadcastmb2q +pub unsafe fn _mm512_broadcastmb_epi64(k: __mmask8) -> __m512i { + _mm512_set1_epi64(k as i64) +} + +/// Broadcast the low 8-bits from input mask k to all 64-bit elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_broadcastmb_epi64&expand=549) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcast))] // should be vpbroadcastmb2q +pub unsafe fn _mm256_broadcastmb_epi64(k: __mmask8) -> __m256i { + _mm256_set1_epi64x(k as i64) +} + +/// Broadcast the low 8-bits from input mask k to all 64-bit elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_broadcastmb_epi64&expand=548) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpbroadcast))] // should be vpbroadcastmb2q +pub unsafe fn _mm_broadcastmb_epi64(k: __mmask8) -> __m128i { + _mm_set1_epi64x(k as i64) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit. Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_conflict_epi32&expand=1248) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm512_conflict_epi32(a: __m512i) -> __m512i { + transmute(vpconflictd(a.as_i32x16())) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit using writemask k (elements are copied from src when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_conflict_epi32&expand=1249) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm512_mask_conflict_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i { + let conflict = _mm512_conflict_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, conflict, src.as_i32x16())) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit using zeromask k (elements are zeroed out when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_conflict_epi32&expand=1250) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm512_maskz_conflict_epi32(k: __mmask16, a: __m512i) -> __m512i { + let conflict = _mm512_conflict_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, conflict, zero)) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit. Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_conflict_epi32&expand=1245) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm256_conflict_epi32(a: __m256i) -> __m256i { + transmute(vpconflictd256(a.as_i32x8())) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit using writemask k (elements are copied from src when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_conflict_epi32&expand=1246) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm256_mask_conflict_epi32(src: __m256i, k: __mmask8, a: __m256i) -> __m256i { + let conflict = _mm256_conflict_epi32(a).as_i32x8(); + transmute(simd_select_bitmask(k, conflict, src.as_i32x8())) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit using zeromask k (elements are zeroed out when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_conflict_epi32&expand=1247) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm256_maskz_conflict_epi32(k: __mmask8, a: __m256i) -> __m256i { + let conflict = _mm256_conflict_epi32(a).as_i32x8(); + let zero = _mm256_setzero_si256().as_i32x8(); + transmute(simd_select_bitmask(k, conflict, zero)) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit. Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_conflict_epi32&expand=1242) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm_conflict_epi32(a: __m128i) -> __m128i { + transmute(vpconflictd128(a.as_i32x4())) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit using writemask k (elements are copied from src when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_conflict_epi32&expand=1243) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm_mask_conflict_epi32(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + let conflict = _mm_conflict_epi32(a).as_i32x4(); + transmute(simd_select_bitmask(k, conflict, src.as_i32x4())) +} + +/// Test each 32-bit element of a for equality with all other elements in a closer to the least significant bit using zeromask k (elements are zeroed out when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_conflict_epi32&expand=1244) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictd))] +pub unsafe fn _mm_maskz_conflict_epi32(k: __mmask8, a: __m128i) -> __m128i { + let conflict = _mm_conflict_epi32(a).as_i32x4(); + let zero = _mm_setzero_si128().as_i32x4(); + transmute(simd_select_bitmask(k, conflict, zero)) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit. Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_conflict_epi64&expand=1257) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm512_conflict_epi64(a: __m512i) -> __m512i { + transmute(vpconflictq(a.as_i64x8())) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit using writemask k (elements are copied from src when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_conflict_epi64&expand=1258) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm512_mask_conflict_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + let conflict = _mm512_conflict_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, conflict, src.as_i64x8())) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit using zeromask k (elements are zeroed out when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_conflict_epi64&expand=1259) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm512_maskz_conflict_epi64(k: __mmask8, a: __m512i) -> __m512i { + let conflict = _mm512_conflict_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, conflict, zero)) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit. Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_conflict_epi64&expand=1254) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm256_conflict_epi64(a: __m256i) -> __m256i { + transmute(vpconflictq256(a.as_i64x4())) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit using writemask k (elements are copied from src when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_conflict_epi64&expand=1255) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm256_mask_conflict_epi64(src: __m256i, k: __mmask8, a: __m256i) -> __m256i { + let conflict = _mm256_conflict_epi64(a).as_i64x4(); + transmute(simd_select_bitmask(k, conflict, src.as_i64x4())) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit using zeromask k (elements are zeroed out when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_conflict_epi64&expand=1256) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm256_maskz_conflict_epi64(k: __mmask8, a: __m256i) -> __m256i { + let conflict = _mm256_conflict_epi64(a).as_i64x4(); + let zero = _mm256_setzero_si256().as_i64x4(); + transmute(simd_select_bitmask(k, conflict, zero)) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit. Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_conflict_epi64&expand=1251) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm_conflict_epi64(a: __m128i) -> __m128i { + transmute(vpconflictq128(a.as_i64x2())) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit using writemask k (elements are copied from src when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_conflict_epi64&expand=1252) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm_mask_conflict_epi64(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + let conflict = _mm_conflict_epi64(a).as_i64x2(); + transmute(simd_select_bitmask(k, conflict, src.as_i64x2())) +} + +/// Test each 64-bit element of a for equality with all other elements in a closer to the least significant bit using zeromask k (elements are zeroed out when the corresponding mask bit is not set). Each element's comparison forms a zero extended bit vector in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_conflict_epi64&expand=1253) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vpconflictq))] +pub unsafe fn _mm_maskz_conflict_epi64(k: __mmask8, a: __m128i) -> __m128i { + let conflict = _mm_conflict_epi64(a).as_i64x2(); + let zero = _mm_setzero_si128().as_i64x2(); + transmute(simd_select_bitmask(k, conflict, zero)) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_lzcnt_epi32&expand=3491) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm512_lzcnt_epi32(a: __m512i) -> __m512i { + transmute(vplzcntd(a.as_i32x16(), false)) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_lzcnt_epi32&expand=3492) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm512_mask_lzcnt_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i { + let zerocount = _mm512_lzcnt_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, zerocount, src.as_i32x16())) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_lzcnt_epi32&expand=3493) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm512_maskz_lzcnt_epi32(k: __mmask16, a: __m512i) -> __m512i { + let zerocount = _mm512_lzcnt_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, zerocount, zero)) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_lzcnt_epi32&expand=3488) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm256_lzcnt_epi32(a: __m256i) -> __m256i { + transmute(vplzcntd256(a.as_i32x8(), false)) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_lzcnt_epi32&expand=3489) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm256_mask_lzcnt_epi32(src: __m256i, k: __mmask8, a: __m256i) -> __m256i { + let zerocount = _mm256_lzcnt_epi32(a).as_i32x8(); + transmute(simd_select_bitmask(k, zerocount, src.as_i32x8())) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_lzcnt_epi32&expand=3490) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm256_maskz_lzcnt_epi32(k: __mmask8, a: __m256i) -> __m256i { + let zerocount = _mm256_lzcnt_epi32(a).as_i32x8(); + let zero = _mm256_setzero_si256().as_i32x8(); + transmute(simd_select_bitmask(k, zerocount, zero)) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lzcnt_epi32&expand=3485) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm_lzcnt_epi32(a: __m128i) -> __m128i { + transmute(vplzcntd128(a.as_i32x4(), false)) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_lzcnt_epi32&expand=3486) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm_mask_lzcnt_epi32(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + let zerocount = _mm_lzcnt_epi32(a).as_i32x4(); + transmute(simd_select_bitmask(k, zerocount, src.as_i32x4())) +} + +/// Counts the number of leading zero bits in each packed 32-bit integer in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_lzcnt_epi32&expand=3487) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntd))] +pub unsafe fn _mm_maskz_lzcnt_epi32(k: __mmask8, a: __m128i) -> __m128i { + let zerocount = _mm_lzcnt_epi32(a).as_i32x4(); + let zero = _mm_setzero_si128().as_i32x4(); + transmute(simd_select_bitmask(k, zerocount, zero)) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_lzcnt_epi64&expand=3500) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm512_lzcnt_epi64(a: __m512i) -> __m512i { + transmute(vplzcntq(a.as_i64x8(), false)) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_lzcnt_epi64&expand=3501) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm512_mask_lzcnt_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + let zerocount = _mm512_lzcnt_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, zerocount, src.as_i64x8())) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_lzcnt_epi64&expand=3502) +#[inline] +#[target_feature(enable = "avx512cd")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm512_maskz_lzcnt_epi64(k: __mmask8, a: __m512i) -> __m512i { + let zerocount = _mm512_lzcnt_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, zerocount, zero)) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_lzcnt_epi64&expand=3497) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm256_lzcnt_epi64(a: __m256i) -> __m256i { + transmute(vplzcntq256(a.as_i64x4(), false)) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_lzcnt_epi64&expand=3498) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm256_mask_lzcnt_epi64(src: __m256i, k: __mmask8, a: __m256i) -> __m256i { + let zerocount = _mm256_lzcnt_epi64(a).as_i64x4(); + transmute(simd_select_bitmask(k, zerocount, src.as_i64x4())) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_lzcnt_epi64&expand=3499) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm256_maskz_lzcnt_epi64(k: __mmask8, a: __m256i) -> __m256i { + let zerocount = _mm256_lzcnt_epi64(a).as_i64x4(); + let zero = _mm256_setzero_si256().as_i64x4(); + transmute(simd_select_bitmask(k, zerocount, zero)) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lzcnt_epi64&expand=3494) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm_lzcnt_epi64(a: __m128i) -> __m128i { + transmute(vplzcntq128(a.as_i64x2(), false)) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_lzcnt_epi64&expand=3495) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm_mask_lzcnt_epi64(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + let zerocount = _mm_lzcnt_epi64(a).as_i64x2(); + transmute(simd_select_bitmask(k, zerocount, src.as_i64x2())) +} + +/// Counts the number of leading zero bits in each packed 64-bit integer in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_lzcnt_epi64&expand=3496) +#[inline] +#[target_feature(enable = "avx512cd,avx512vl")] +#[cfg_attr(test, assert_instr(vplzcntq))] +pub unsafe fn _mm_maskz_lzcnt_epi64(k: __mmask8, a: __m128i) -> __m128i { + let zerocount = _mm_lzcnt_epi64(a).as_i64x2(); + let zero = _mm_setzero_si128().as_i64x2(); + transmute(simd_select_bitmask(k, zerocount, zero)) +} + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.avx512.conflict.d.512"] + fn vpconflictd(a: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.conflict.d.256"] + fn vpconflictd256(a: i32x8) -> i32x8; + #[link_name = "llvm.x86.avx512.conflict.d.128"] + fn vpconflictd128(a: i32x4) -> i32x4; + + #[link_name = "llvm.x86.avx512.conflict.q.512"] + fn vpconflictq(a: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.conflict.q.256"] + fn vpconflictq256(a: i64x4) -> i64x4; + #[link_name = "llvm.x86.avx512.conflict.q.128"] + fn vpconflictq128(a: i64x2) -> i64x2; + + #[link_name = "llvm.ctlz.v16i32"] + fn vplzcntd(a: i32x16, nonzero: bool) -> i32x16; + #[link_name = "llvm.ctlz.v8i32"] + fn vplzcntd256(a: i32x8, nonzero: bool) -> i32x8; + #[link_name = "llvm.ctlz.v4i32"] + fn vplzcntd128(a: i32x4, nonzero: bool) -> i32x4; + + #[link_name = "llvm.ctlz.v8i64"] + fn vplzcntq(a: i64x8, nonzero: bool) -> i64x8; + #[link_name = "llvm.ctlz.v4i64"] + fn vplzcntq256(a: i64x4, nonzero: bool) -> i64x4; + #[link_name = "llvm.ctlz.v2i64"] + fn vplzcntq128(a: i64x2, nonzero: bool) -> i64x2; +} + +#[cfg(test)] +mod tests { + + use crate::core_arch::x86::*; + use stdarch_test::simd_test; + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_broadcastmw_epi32() { + let a: __mmask16 = 2; + let r = _mm512_broadcastmw_epi32(a); + let e = _mm512_set1_epi32(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_broadcastmw_epi32() { + let a: __mmask16 = 2; + let r = _mm256_broadcastmw_epi32(a); + let e = _mm256_set1_epi32(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_broadcastmw_epi32() { + let a: __mmask16 = 2; + let r = _mm_broadcastmw_epi32(a); + let e = _mm_set1_epi32(2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_broadcastmb_epi64() { + let a: __mmask8 = 2; + let r = _mm512_broadcastmb_epi64(a); + let e = _mm512_set1_epi64(2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_broadcastmb_epi64() { + let a: __mmask8 = 2; + let r = _mm256_broadcastmb_epi64(a); + let e = _mm256_set1_epi64x(2); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_broadcastmb_epi64() { + let a: __mmask8 = 2; + let r = _mm_broadcastmb_epi64(a); + let e = _mm_set1_epi64x(2); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_conflict_epi32() { + let a = _mm512_set1_epi32(1); + let r = _mm512_conflict_epi32(a); + let e = _mm512_set_epi32( + 1 << 14 + | 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 9 | 1 << 8 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 8 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_mask_conflict_epi32() { + let a = _mm512_set1_epi32(1); + let r = _mm512_mask_conflict_epi32(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_conflict_epi32(a, 0b11111111_11111111, a); + let e = _mm512_set_epi32( + 1 << 14 + | 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 9 | 1 << 8 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 8 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_maskz_conflict_epi32() { + let a = _mm512_set1_epi32(1); + let r = _mm512_maskz_conflict_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_conflict_epi32(0b11111111_11111111, a); + let e = _mm512_set_epi32( + 1 << 14 + | 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 13 + | 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 12 + | 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 11 + | 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 10 + | 1 << 9 + | 1 << 8 + | 1 << 7 + | 1 << 6 + | 1 << 5 + | 1 << 4 + | 1 << 3 + | 1 << 2 + | 1 << 1 + | 1 << 0, + 1 << 9 | 1 << 8 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 8 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_conflict_epi32() { + let a = _mm256_set1_epi32(1); + let r = _mm256_conflict_epi32(a); + let e = _mm256_set_epi32( + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_mask_conflict_epi32() { + let a = _mm256_set1_epi32(1); + let r = _mm256_mask_conflict_epi32(a, 0, a); + assert_eq_m256i(r, a); + let r = _mm256_mask_conflict_epi32(a, 0b11111111, a); + let e = _mm256_set_epi32( + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_maskz_conflict_epi32() { + let a = _mm256_set1_epi32(1); + let r = _mm256_maskz_conflict_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_conflict_epi32(0b11111111, a); + let e = _mm256_set_epi32( + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_conflict_epi32() { + let a = _mm_set1_epi32(1); + let r = _mm_conflict_epi32(a); + let e = _mm_set_epi32(1 << 2 | 1 << 1 | 1 << 0, 1 << 1 | 1 << 0, 1 << 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_mask_conflict_epi32() { + let a = _mm_set1_epi32(1); + let r = _mm_mask_conflict_epi32(a, 0, a); + assert_eq_m128i(r, a); + let r = _mm_mask_conflict_epi32(a, 0b00001111, a); + let e = _mm_set_epi32(1 << 2 | 1 << 1 | 1 << 0, 1 << 1 | 1 << 0, 1 << 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_maskz_conflict_epi32() { + let a = _mm_set1_epi32(1); + let r = _mm_maskz_conflict_epi32(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_conflict_epi32(0b00001111, a); + let e = _mm_set_epi32(1 << 2 | 1 << 1 | 1 << 0, 1 << 1 | 1 << 0, 1 << 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_conflict_epi64() { + let a = _mm512_set1_epi64(1); + let r = _mm512_conflict_epi64(a); + let e = _mm512_set_epi64( + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_mask_conflict_epi64() { + let a = _mm512_set1_epi64(1); + let r = _mm512_mask_conflict_epi64(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_conflict_epi64(a, 0b11111111, a); + let e = _mm512_set_epi64( + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_maskz_conflict_epi64() { + let a = _mm512_set1_epi64(1); + let r = _mm512_maskz_conflict_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_conflict_epi64(0b11111111, a); + let e = _mm512_set_epi64( + 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + 1 << 2 | 1 << 1 | 1 << 0, + 1 << 1 | 1 << 0, + 1 << 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_conflict_epi64() { + let a = _mm256_set1_epi64x(1); + let r = _mm256_conflict_epi64(a); + let e = _mm256_set_epi64x(1 << 2 | 1 << 1 | 1 << 0, 1 << 1 | 1 << 0, 1 << 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_mask_conflict_epi64() { + let a = _mm256_set1_epi64x(1); + let r = _mm256_mask_conflict_epi64(a, 0, a); + assert_eq_m256i(r, a); + let r = _mm256_mask_conflict_epi64(a, 0b00001111, a); + let e = _mm256_set_epi64x(1 << 2 | 1 << 1 | 1 << 0, 1 << 1 | 1 << 0, 1 << 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_maskz_conflict_epi64() { + let a = _mm256_set1_epi64x(1); + let r = _mm256_maskz_conflict_epi64(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_conflict_epi64(0b00001111, a); + let e = _mm256_set_epi64x(1 << 2 | 1 << 1 | 1 << 0, 1 << 1 | 1 << 0, 1 << 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_conflict_epi64() { + let a = _mm_set1_epi64x(1); + let r = _mm_conflict_epi64(a); + let e = _mm_set_epi64x(1 << 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_mask_conflict_epi64() { + let a = _mm_set1_epi64x(1); + let r = _mm_mask_conflict_epi64(a, 0, a); + assert_eq_m128i(r, a); + let r = _mm_mask_conflict_epi64(a, 0b00000011, a); + let e = _mm_set_epi64x(1 << 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_maskz_conflict_epi64() { + let a = _mm_set1_epi64x(1); + let r = _mm_maskz_conflict_epi64(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_conflict_epi64(0b00000011, a); + let e = _mm_set_epi64x(1 << 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_lzcnt_epi32() { + let a = _mm512_set1_epi32(1); + let r = _mm512_lzcnt_epi32(a); + let e = _mm512_set1_epi32(31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_mask_lzcnt_epi32() { + let a = _mm512_set1_epi32(1); + let r = _mm512_mask_lzcnt_epi32(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_lzcnt_epi32(a, 0b11111111_11111111, a); + let e = _mm512_set1_epi32(31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_maskz_lzcnt_epi32() { + let a = _mm512_set1_epi32(2); + let r = _mm512_maskz_lzcnt_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_lzcnt_epi32(0b11111111_11111111, a); + let e = _mm512_set1_epi32(30); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_lzcnt_epi32() { + let a = _mm256_set1_epi32(1); + let r = _mm256_lzcnt_epi32(a); + let e = _mm256_set1_epi32(31); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_mask_lzcnt_epi32() { + let a = _mm256_set1_epi32(1); + let r = _mm256_mask_lzcnt_epi32(a, 0, a); + assert_eq_m256i(r, a); + let r = _mm256_mask_lzcnt_epi32(a, 0b11111111, a); + let e = _mm256_set1_epi32(31); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_maskz_lzcnt_epi32() { + let a = _mm256_set1_epi32(1); + let r = _mm256_maskz_lzcnt_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_lzcnt_epi32(0b11111111, a); + let e = _mm256_set1_epi32(31); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_lzcnt_epi32() { + let a = _mm_set1_epi32(1); + let r = _mm_lzcnt_epi32(a); + let e = _mm_set1_epi32(31); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_mask_lzcnt_epi32() { + let a = _mm_set1_epi32(1); + let r = _mm_mask_lzcnt_epi32(a, 0, a); + assert_eq_m128i(r, a); + let r = _mm_mask_lzcnt_epi32(a, 0b00001111, a); + let e = _mm_set1_epi32(31); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_maskz_lzcnt_epi32() { + let a = _mm_set1_epi32(1); + let r = _mm_maskz_lzcnt_epi32(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_lzcnt_epi32(0b00001111, a); + let e = _mm_set1_epi32(31); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_lzcnt_epi64() { + let a = _mm512_set1_epi64(1); + let r = _mm512_lzcnt_epi64(a); + let e = _mm512_set1_epi64(63); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_mask_lzcnt_epi64() { + let a = _mm512_set1_epi64(1); + let r = _mm512_mask_lzcnt_epi64(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_lzcnt_epi64(a, 0b11111111, a); + let e = _mm512_set1_epi64(63); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd")] + unsafe fn test_mm512_maskz_lzcnt_epi64() { + let a = _mm512_set1_epi64(2); + let r = _mm512_maskz_lzcnt_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_lzcnt_epi64(0b11111111, a); + let e = _mm512_set1_epi64(62); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_lzcnt_epi64() { + let a = _mm256_set1_epi64x(1); + let r = _mm256_lzcnt_epi64(a); + let e = _mm256_set1_epi64x(63); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_mask_lzcnt_epi64() { + let a = _mm256_set1_epi64x(1); + let r = _mm256_mask_lzcnt_epi64(a, 0, a); + assert_eq_m256i(r, a); + let r = _mm256_mask_lzcnt_epi64(a, 0b00001111, a); + let e = _mm256_set1_epi64x(63); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm256_maskz_lzcnt_epi64() { + let a = _mm256_set1_epi64x(1); + let r = _mm256_maskz_lzcnt_epi64(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm256_maskz_lzcnt_epi64(0b00001111, a); + let e = _mm256_set1_epi64x(63); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_lzcnt_epi64() { + let a = _mm_set1_epi64x(1); + let r = _mm_lzcnt_epi64(a); + let e = _mm_set1_epi64x(63); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_mask_lzcnt_epi64() { + let a = _mm_set1_epi64x(1); + let r = _mm_mask_lzcnt_epi64(a, 0, a); + assert_eq_m128i(r, a); + let r = _mm_mask_lzcnt_epi64(a, 0b00001111, a); + let e = _mm_set1_epi64x(63); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512cd,avx512vl")] + unsafe fn test_mm_maskz_lzcnt_epi64() { + let a = _mm_set1_epi64x(1); + let r = _mm_maskz_lzcnt_epi64(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm_maskz_lzcnt_epi64(0b00001111, a); + let e = _mm_set1_epi64x(63); + assert_eq_m128i(r, e); + } +} diff --git a/library/stdarch/crates/core_arch/src/x86/avx512f.rs b/library/stdarch/crates/core_arch/src/x86/avx512f.rs index 32724bb292..6a0426bd0b 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512f.rs @@ -135,6 +135,98 @@ pub unsafe fn _mm512_mask_abs_pd(src: __m512d, k: __mmask8, v2: __m512d) -> __m5 transmute(simd_select_bitmask(k, abs, src.as_f64x8())) } +/// Move packed 32-bit integers from a to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mov_epi32&expand=3801) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovdqa32))] +pub unsafe fn _mm512_mask_mov_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i { + let mov = a.as_i32x16(); + transmute(simd_select_bitmask(k, mov, src.as_i32x16())) +} + +/// Move packed 32-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mov_epi32&expand=3802) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovdqa32))] +pub unsafe fn _mm512_maskz_mov_epi32(k: __mmask16, a: __m512i) -> __m512i { + let mov = a.as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed 64-bit integers from a to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mov_epi64&expand=3807) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovdqa64))] +pub unsafe fn _mm512_mask_mov_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + let mov = a.as_i64x8(); + transmute(simd_select_bitmask(k, mov, src.as_i64x8())) +} + +/// Move packed 64-bit integers from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mov_epi64&expand=3808) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovdqa64))] +pub unsafe fn _mm512_maskz_mov_epi64(k: __mmask8, a: __m512i) -> __m512i { + let mov = a.as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed single-precision (32-bit) floating-point elements from a to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mov_ps&expand=3825) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] +pub unsafe fn _mm512_mask_mov_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let mov = a.as_f32x16(); + transmute(simd_select_bitmask(k, mov, src.as_f32x16())) +} + +/// Move packed single-precision (32-bit) floating-point elements from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mov_ps&expand=3826) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] +pub unsafe fn _mm512_maskz_mov_ps(k: __mmask16, a: __m512) -> __m512 { + let mov = a.as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Move packed double-precision (64-bit) floating-point elements from a to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mov_pd&expand=3819) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovapd))] +pub unsafe fn _mm512_mask_mov_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + let mov = a.as_f64x8(); + transmute(simd_select_bitmask(k, mov, src.as_f64x8())) +} + +/// Move packed double-precision (64-bit) floating-point elements from a into dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mov_pd&expand=3820) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovapd))] +pub unsafe fn _mm512_maskz_mov_pd(k: __mmask8, a: __m512d) -> __m512d { + let mov = a.as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mov, zero)) +} + /// Add packed 32-bit integers in a and b, and store the results in dst. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_epi32&expand=100) @@ -1969,1569 +2061,1701 @@ pub unsafe fn _mm512_maskz_getexp_pd(k: __mmask8, a: __m512d) -> __m512d { )) } -/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Round packed single-precision (32-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_ps&expand=2880) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_roundscale_ps&expand=4784) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] -#[rustc_args_required_const(1, 2)] -pub unsafe fn _mm512_getmant_ps( - a: __m512, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, -) -> __m512 { +#[cfg_attr(test, assert_instr(vrndscaleps, imm8 = 0))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_roundscale_ps(a: __m512, imm8: i32) -> __m512 { + let a = a.as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); macro_rules! call { - ($imm4:expr, $imm2:expr) => { - vgetmantps( - a.as_f32x16(), - $imm2 << 2 | $imm4, - _mm512_setzero_ps().as_f32x16(), + ($imm8:expr) => { + vrndscaleps( + a, + $imm8, + zero, 0b11111111_11111111, _MM_FROUND_CUR_DIRECTION, ) }; } - let r = constify_imm4_mantissas!(norm, sign, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Round packed single-precision (32-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_ps&expand=2881) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_roundscale_ps&expand=4782) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] -#[rustc_args_required_const(3, 4)] -pub unsafe fn _mm512_mask_getmant_ps( - src: __m512, - k: __mmask16, - a: __m512, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, -) -> __m512 { +#[cfg_attr(test, assert_instr(vrndscaleps, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_roundscale_ps(src: __m512, k: __mmask16, a: __m512, imm8: i32) -> __m512 { + let a = a.as_f32x16(); + let src = src.as_f32x16(); macro_rules! call { - ($imm4:expr, $imm2:expr) => { - vgetmantps( - a.as_f32x16(), - $imm2 << 2 | $imm4, - src.as_f32x16(), - k, - _MM_FROUND_CUR_DIRECTION, - ) + ($imm8:expr) => { + vrndscaleps(a, $imm8, src, k, _MM_FROUND_CUR_DIRECTION) }; } - let r = constify_imm4_mantissas!(norm, sign, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Round packed single-precision (32-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_ps&expand=2882) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_roundscale_ps&expand=4783) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] -#[rustc_args_required_const(2, 3)] -pub unsafe fn _mm512_maskz_getmant_ps( - k: __mmask16, - a: __m512, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, -) -> __m512 { +#[cfg_attr(test, assert_instr(vrndscaleps, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_roundscale_ps(k: __mmask16, a: __m512, imm8: i32) -> __m512 { + let a = a.as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); macro_rules! call { - ($imm4:expr, $imm2:expr) => { - vgetmantps( - a.as_f32x16(), - $imm2 << 2 | $imm4, - _mm512_setzero_ps().as_f32x16(), - k, - _MM_FROUND_CUR_DIRECTION, - ) + ($imm8:expr) => { + vrndscaleps(a, $imm8, zero, k, _MM_FROUND_CUR_DIRECTION) }; } - let r = constify_imm4_mantissas!(norm, sign, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Round packed double-precision (64-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_pd&expand=2871) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_roundscale_pd&expand=4775) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] -#[rustc_args_required_const(1, 2)] -pub unsafe fn _mm512_getmant_pd( - a: __m512d, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, -) -> __m512d { +#[cfg_attr(test, assert_instr(vrndscalepd, imm8 = 0))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_roundscale_pd(a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); macro_rules! call { - ($imm4:expr, $imm2:expr) => { - vgetmantpd( - a.as_f64x8(), - $imm2 << 2 | $imm4, - _mm512_setzero_pd().as_f64x8(), - 0b11111111, - _MM_FROUND_CUR_DIRECTION, - ) + ($imm8:expr) => { + vrndscalepd(a, $imm8, zero, 0b11111111, _MM_FROUND_CUR_DIRECTION) }; } - let r = constify_imm4_mantissas!(norm, sign, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Round packed double-precision (64-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_pd&expand=2872) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_roundscale_pd&expand=4773) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] -#[rustc_args_required_const(3, 4)] -pub unsafe fn _mm512_mask_getmant_pd( +#[cfg_attr(test, assert_instr(vrndscalepd, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_roundscale_pd( src: __m512d, k: __mmask8, a: __m512d, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, + imm8: i32, ) -> __m512d { + let a = a.as_f64x8(); + let src = src.as_f64x8(); macro_rules! call { - ($imm4:expr, $imm2:expr) => { - vgetmantpd( - a.as_f64x8(), - $imm2 << 2 | $imm4, - src.as_f64x8(), - k, - _MM_FROUND_CUR_DIRECTION, - ) + ($imm8:expr) => { + vrndscalepd(a, $imm8, src, k, _MM_FROUND_CUR_DIRECTION) }; } - let r = constify_imm4_mantissas!(norm, sign, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Round packed double-precision (64-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_pd&expand=2873) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_roundscale_pd&expand=4774) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] -#[rustc_args_required_const(2, 3)] -pub unsafe fn _mm512_maskz_getmant_pd( - k: __mmask8, - a: __m512d, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, -) -> __m512d { +#[cfg_attr(test, assert_instr(vrndscalepd, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_roundscale_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); macro_rules! call { - ($imm4:expr, $imm2:expr) => { - vgetmantpd( - a.as_f64x8(), - $imm2 << 2 | $imm4, - _mm512_setzero_pd().as_f64x8(), - k, - _MM_FROUND_CUR_DIRECTION, - ) + ($imm8:expr) => { + vrndscalepd(a, $imm8, zero, k, _MM_FROUND_CUR_DIRECTION) }; } - let r = constify_imm4_mantissas!(norm, sign, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_ps&expand=145) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_scalef_ps&expand=4883) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_add_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { - macro_rules! call { - ($imm4:expr) => { - vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) - }; - } - let r = constify_imm4_round!(rounding, call); - transmute(r) +#[cfg_attr(test, assert_instr(vscalefps))] +pub unsafe fn _mm512_scalef_ps(a: __m512, b: __m512) -> __m512 { + transmute(vscalefps( + a.as_f32x16(), + b.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_scalef_ps&expand=4881) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefps))] +pub unsafe fn _mm512_mask_scalef_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + transmute(vscalefps( + a.as_f32x16(), + b.as_f32x16(), + src.as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_ps&expand=146) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_scalef_ps&expand=4882) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] +#[cfg_attr(test, assert_instr(vscalefps))] +pub unsafe fn _mm512_maskz_scalef_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + transmute(vscalefps( + a.as_f32x16(), + b.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_scalef_pd&expand=4874) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefpd))] +pub unsafe fn _mm512_scalef_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(vscalefpd( + a.as_f64x8(), + b.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_scalef_pd&expand=4872) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefpd))] +pub unsafe fn _mm512_mask_scalef_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + transmute(vscalefpd( + a.as_f64x8(), + b.as_f64x8(), + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_scalef_pd&expand=4873) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefpd))] +pub unsafe fn _mm512_maskz_scalef_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + transmute(vscalefpd( + a.as_f64x8(), + b.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Fix up packed single-precision (32-bit) floating-point elements in a and b using packed 32-bit integers in c, and store the results in dst. imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fixupimm_ps&expand=2499) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmps, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fixupimm_ps(a: __m512, b: __m512, c: __m512i, imm8: i32) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); + let c = c.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vfixupimmps( + a, + b, + c, + $imm8, + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Fix up packed single-precision (32-bit) floating-point elements in a and b using packed 32-bit integers in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fixupimm_ps&expand=2500) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmps, imm8 = 0))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_add_round_ps( - src: __m512, - k: __mmask16, +pub unsafe fn _mm512_mask_fixupimm_ps( a: __m512, + k: __mmask16, b: __m512, - rounding: i32, + c: __m512i, + imm8: i32, ) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); + let c = c.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm8:expr) => { + vfixupimmps(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) }; } - let addround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, addround, src.as_f32x16())) + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Fix up packed single-precision (32-bit) floating-point elements in a and b using packed 32-bit integers in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). imm8 is used to set the required flags reporting. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_ps&expand=147) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fixupimm_ps&expand=2501) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_add_round_ps( +#[cfg_attr(test, assert_instr(vfixupimmps, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fixupimm_ps( k: __mmask16, a: __m512, b: __m512, - rounding: i32, + c: __m512i, + imm8: i32, ) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); + let c = c.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm8:expr) => { + vfixupimmpsz(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) }; } - let addround = constify_imm4_round!(rounding, call); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, addround, zero)) + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Fix up packed double-precision (64-bit) floating-point elements in a and b using packed 64-bit integers in c, and store the results in dst. imm8 is used to set the required flags reporting. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_pd&expand=142) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fixupimm_pd&expand=2490) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_add_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vfixupimmpd, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fixupimm_pd(a: __m512d, b: __m512d, c: __m512i, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm8:expr) => { + vfixupimmpd(a, b, c, $imm8, 0b11111111, _MM_FROUND_CUR_DIRECTION) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Fix up packed double-precision (64-bit) floating-point elements in a and b using packed 64-bit integers in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). imm8 is used to set the required flags reporting. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_pd&expand=143) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fixupimm_pd&expand=2491) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] +#[cfg_attr(test, assert_instr(vfixupimmpd, imm8 = 0))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_add_round_pd( - src: __m512d, - k: __mmask8, +pub unsafe fn _mm512_mask_fixupimm_pd( a: __m512d, + k: __mmask8, b: __m512d, - rounding: i32, + c: __m512i, + imm8: i32, ) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm8:expr) => { + vfixupimmpd(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) }; } - let addround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, addround, src.as_f64x8())) + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Fix up packed double-precision (64-bit) floating-point elements in a and b using packed 64-bit integers in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). imm8 is used to set the required flags reporting. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_pd&expand=144) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fixupimm_pd&expand=2492) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_add_round_pd( +#[cfg_attr(test, assert_instr(vfixupimmpd, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fixupimm_pd( k: __mmask8, a: __m512d, b: __m512d, - rounding: i32, + c: __m512i, + imm8: i32, ) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm8:expr) => { + vfixupimmpdz(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) }; } - let addround = constify_imm4_round!(rounding, call); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, addround, zero)) + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// Bitwise ternary logic that provides the capability to implement any three-operand binary function; the specific binary function is specified by value in imm8. For each bit in each packed 32-bit integer, the corresponding bit from a, b, and c are used to form a 3 bit index into imm8, and the value at that bit in imm8 is written to the corresponding bit in dst. /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_ps&expand=5739) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ternarylogic_epi32&expand=5867) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_sub_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vpternlogd, imm8 = 114))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_ternarylogic_epi32(a: __m512i, b: __m512i, c: __m512i, imm8: i32) -> __m512i { + let a = a.as_i32x16(); + let b = b.as_i32x16(); + let c = c.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm8:expr) => { + vpternlogd(a, b, c, $imm8) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Bitwise ternary logic that provides the capability to implement any three-operand binary function; the specific binary function is specified by value in imm8. For each bit in each packed 32-bit integer, the corresponding bit from src, a, and b are used to form a 3 bit index into imm8, and the value at that bit in imm8 is written to the corresponding bit in dst using writemask k at 32-bit granularity (32-bit elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_ps&expand=5737) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ternarylogic_epi32&expand=5865) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[cfg_attr(test, assert_instr(vpternlogd, imm8 = 114))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_sub_round_ps( - src: __m512, +pub unsafe fn _mm512_mask_ternarylogic_epi32( + src: __m512i, k: __mmask16, - a: __m512, - b: __m512, - rounding: i32, -) -> __m512 { + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let src = src.as_i32x16(); + let a = a.as_i32x16(); + let b = b.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm8:expr) => { + vpternlogd(src, a, b, $imm8) }; } - let subround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, subround, src.as_f32x16())) + let ternarylogic = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ternarylogic, src)) } -/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Bitwise ternary logic that provides the capability to implement any three-operand binary function; the specific binary function is specified by value in imm8. For each bit in each packed 32-bit integer, the corresponding bit from a, b, and c are used to form a 3 bit index into imm8, and the value at that bit in imm8 is written to the corresponding bit in dst using zeromask k at 32-bit granularity (32-bit elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_ps&expand=5738) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ternarylogic_epi32&expand=5866) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_sub_round_ps( +#[cfg_attr(test, assert_instr(vpternlogd, imm8 = 114))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_ternarylogic_epi32( k: __mmask16, - a: __m512, - b: __m512, - rounding: i32, -) -> __m512 { + a: __m512i, + b: __m512i, + c: __m512i, + imm8: i32, +) -> __m512i { + let a = a.as_i32x16(); + let b = b.as_i32x16(); + let c = c.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm8:expr) => { + vpternlogd(a, b, c, $imm8) }; } - let subround = constify_imm4_round!(rounding, call); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, subround, zero)) + let ternarylogic = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, ternarylogic, zero)) } -/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// Bitwise ternary logic that provides the capability to implement any three-operand binary function; the specific binary function is specified by value in imm8. For each bit in each packed 64-bit integer, the corresponding bit from a, b, and c are used to form a 3 bit index into imm8, and the value at that bit in imm8 is written to the corresponding bit in dst. /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_pd&expand=5736) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ternarylogic_epi64&expand=5876) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_sub_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vpternlogq, imm8 = 114))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_ternarylogic_epi64(a: __m512i, b: __m512i, c: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + let b = b.as_i64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm8:expr) => { + vpternlogq(a, b, c, $imm8) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm8_sae!(imm8, call); transmute(r) } -/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Bitwise ternary logic that provides the capability to implement any three-operand binary function; the specific binary function is specified by value in imm8. For each bit in each packed 64-bit integer, the corresponding bit from src, a, and b are used to form a 3 bit index into imm8, and the value at that bit in imm8 is written to the corresponding bit in dst using writemask k at 64-bit granularity (64-bit elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_pd&expand=5734) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ternarylogic_epi64&expand=5874) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[cfg_attr(test, assert_instr(vpternlogq, imm8 = 114))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_sub_round_pd( - src: __m512d, +pub unsafe fn _mm512_mask_ternarylogic_epi64( + src: __m512i, k: __mmask8, - a: __m512d, - b: __m512d, - rounding: i32, -) -> __m512d { + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let src = src.as_i64x8(); + let a = a.as_i64x8(); + let b = b.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm8:expr) => { + vpternlogq(src, a, b, $imm8) }; } - let subround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, subround, src.as_f64x8())) + let ternarylogic = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ternarylogic, src)) } -/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Bitwise ternary logic that provides the capability to implement any three-operand binary function; the specific binary function is specified by value in imm8. For each bit in each packed 64-bit integer, the corresponding bit from a, b, and c are used to form a 3 bit index into imm8, and the value at that bit in imm8 is written to the corresponding bit in dst using zeromask k at 64-bit granularity (64-bit elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_pd&expand=5735) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ternarylogic_epi64&expand=5875) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_sub_round_pd( +#[cfg_attr(test, assert_instr(vpternlogq, imm8 = 114))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_ternarylogic_epi64( k: __mmask8, - a: __m512d, - b: __m512d, - rounding: i32, -) -> __m512d { + a: __m512i, + b: __m512i, + c: __m512i, + imm8: i32, +) -> __m512i { + let a = a.as_i64x8(); + let b = b.as_i64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm8:expr) => { + vpternlogq(a, b, c, $imm8) }; } - let subround = constify_imm4_round!(rounding, call); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, subround, zero)) + let ternarylogic = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, ternarylogic, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_ps&expand=3940) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_ps&expand=2880) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_mul_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_getmant_ps( + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512 { macro_rules! call { - ($imm4:expr) => { - vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + ) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm4_mantissas!(norm, sign, call); transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_ps&expand=3938) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_ps&expand=2881) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_mul_round_ps( +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_getmant_ps( src: __m512, k: __mmask16, a: __m512, - b: __m512, - rounding: i32, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, ) -> __m512 { macro_rules! call { - ($imm4:expr) => { - vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + src.as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + ) }; } - let mulround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, mulround, src.as_f32x16())) + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_ps&expand=2882) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_mul_round_ps( +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_getmant_ps( k: __mmask16, a: __m512, - b: __m512, - rounding: i32, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, ) -> __m512 { macro_rules! call { - ($imm4:expr) => { - vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + _mm512_setzero_ps().as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + ) }; } - let mulround = constify_imm4_round!(rounding, call); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, mulround, zero)) + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_pd&expand=3937) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_pd&expand=2871) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_mul_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_getmant_pd( + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512d { macro_rules! call { - ($imm4:expr) => { - vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + ) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm4_mantissas!(norm, sign, call); transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_pd&expand=3935) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_pd&expand=2872) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_mul_round_pd( +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_getmant_pd( src: __m512d, k: __mmask8, a: __m512d, - b: __m512d, - rounding: i32, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, ) -> __m512d { macro_rules! call { - ($imm4:expr) => { - vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + ) }; } - let mulround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, mulround, src.as_f64x8())) + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_pd&expand=2873) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_mul_round_pd( +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_getmant_pd( k: __mmask8, a: __m512d, - b: __m512d, - rounding: i32, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, ) -> __m512d { macro_rules! call { - ($imm4:expr) => { - vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + ) }; } - let mulround = constify_imm4_round!(rounding, call); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, mulround, zero)) + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) } -/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst. +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_ps&expand=2168) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_ps&expand=145) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_div_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { +pub unsafe fn _mm512_add_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + vaddps(a, b, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_ps&expand=2169) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_ps&expand=146) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_div_round_ps( +pub unsafe fn _mm512_mask_add_round_ps( src: __m512, k: __mmask16, a: __m512, b: __m512, rounding: i32, ) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + vaddps(a, b, $imm4) }; } - let divround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, divround, src.as_f32x16())) + let addround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, addround, src.as_f32x16())) } -/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_ps&expand=2170) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_ps&expand=147) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_div_round_ps( +pub unsafe fn _mm512_maskz_add_round_ps( k: __mmask16, a: __m512, b: __m512, rounding: i32, ) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + vaddps(a, b, $imm4) }; } - let divround = constify_imm4_round!(rounding, call); + let addround = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, divround, zero)) + transmute(simd_select_bitmask(k, addround, zero)) } -/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, =and store the results in dst. +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_pd&expand=2165) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_pd&expand=142) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_div_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { +pub unsafe fn _mm512_add_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vaddpd(a, b, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_pd&expand=2166) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_pd&expand=143) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_div_round_pd( +pub unsafe fn _mm512_mask_add_round_pd( src: __m512d, k: __mmask8, a: __m512d, b: __m512d, rounding: i32, ) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vaddpd(a, b, $imm4) }; } - let divround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, divround, src.as_f64x8())) + let addround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, addround, src.as_f64x8())) } -/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_pd&expand=2167) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_pd&expand=144) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_div_round_pd( +pub unsafe fn _mm512_maskz_add_round_pd( k: __mmask8, a: __m512d, b: __m512d, rounding: i32, ) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vaddpd(a, b, $imm4) }; } - let divround = constify_imm4_round!(rounding, call); + let addround = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, divround, zero)) + transmute(simd_select_bitmask(k, addround, zero)) } -/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_ps&expand=5377) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_ps&expand=5739) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_sqrt_round_ps(a: __m512, rounding: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_sub_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vsqrtps(a.as_f32x16(), $imm4) + vsubps(a, b, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_ps&expand=5375) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_ps&expand=5737) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_sqrt_round_ps( +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_sub_round_ps( src: __m512, k: __mmask16, a: __m512, + b: __m512, rounding: i32, ) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vsqrtps(a.as_f32x16(), $imm4) + vsubps(a, b, $imm4) }; } - let sqrtround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, sqrtround, src.as_f32x16())) + let subround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, subround, src.as_f32x16())) } -/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_ps&expand=5376) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_ps&expand=5738) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_sqrt_round_ps(k: __mmask16, a: __m512, rounding: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_sub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vsqrtps(a.as_f32x16(), $imm4) + vsubps(a, b, $imm4) }; } - let sqrtround = constify_imm4_round!(rounding, call); + let subround = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, sqrtround, zero)) + transmute(simd_select_bitmask(k, subround, zero)) } -/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_pd&expand=5374) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_pd&expand=5736) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_sqrt_round_pd(a: __m512d, rounding: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_sub_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vsqrtpd(a.as_f64x8(), $imm4) + vsubpd(a, b, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_pd&expand=5372) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_pd&expand=5734) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_sqrt_round_pd( +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_sub_round_pd( src: __m512d, k: __mmask8, a: __m512d, + b: __m512d, rounding: i32, ) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vsqrtpd(a.as_f64x8(), $imm4) + vsubpd(a, b, $imm4) }; } - let sqrtround = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, sqrtround, src.as_f64x8())) + let subround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, subround, src.as_f64x8())) } -/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_pd&expand=5373) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_pd&expand=5735) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_sqrt_round_pd(k: __mmask8, a: __m512d, rounding: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_sub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vsqrtpd(a.as_f64x8(), $imm4) + vsubpd(a, b, $imm4) }; } - let sqrtround = constify_imm4_round!(rounding, call); + let subround = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, sqrtround, zero)) + transmute(simd_select_bitmask(k, subround, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_ps&expand=2565) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_ps&expand=3940) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_mul_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + vmulps(a, b, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_ps&expand=2566) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_ps&expand=3938) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmadd_round_ps( - a: __m512, +pub unsafe fn _mm512_mask_mul_round_ps( + src: __m512, k: __mmask16, + a: __m512, b: __m512, - c: __m512, rounding: i32, ) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + vmulps(a, b, $imm4) }; } - let fmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmadd, a.as_f32x16())) + let mulround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, mulround, src.as_f32x16())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in a using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_ps&expand=2568) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmadd_round_ps( +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_mul_round_ps( k: __mmask16, a: __m512, b: __m512, - c: __m512, rounding: i32, ) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + vmulps(a, b, $imm4) }; } - let fmadd = constify_imm4_round!(rounding, call); + let mulround = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, fmadd, zero)) -} - -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_ps&expand=2567) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmadd_round_ps( - a: __m512, - b: __m512, - c: __m512, - k: __mmask16, - rounding: i32, -) -> __m512 { - macro_rules! call { - ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) - }; - } - let fmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmadd, c.as_f32x16())) + transmute(simd_select_bitmask(k, mulround, zero)) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_pd&expand=2561) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_pd&expand=3937) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_mul_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + vmulpd(a, b, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_pd&expand=2562) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_pd&expand=3935) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmadd_round_pd( - a: __m512d, +pub unsafe fn _mm512_mask_mul_round_pd( + src: __m512d, k: __mmask8, + a: __m512d, b: __m512d, - c: __m512d, rounding: i32, ) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + vmulpd(a, b, $imm4) }; } - let fmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmadd, a.as_f64x8())) + let mulround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, mulround, src.as_f64x8())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_pd&expand=2564) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmadd_round_pd( +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_mul_round_pd( k: __mmask8, a: __m512d, b: __m512d, - c: __m512d, rounding: i32, ) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + vmulpd(a, b, $imm4) }; } - let fmadd = constify_imm4_round!(rounding, call); + let mulround = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, fmadd, zero)) -} - -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). -/// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_pd&expand=2563) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmadd_round_pd( - a: __m512d, - b: __m512d, - c: __m512d, - k: __mmask8, - rounding: i32, -) -> __m512d { - macro_rules! call { - ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) - }; - } - let fmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmadd, c.as_f64x8())) + transmute(simd_select_bitmask(k, mulround, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_ps&expand=2651) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_ps&expand=2168) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f32x16()); +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_div_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vdivps(a, b, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_ps&expand=2652) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_ps&expand=2169) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmsub_round_ps( - a: __m512, +pub unsafe fn _mm512_mask_div_round_ps( + src: __m512, k: __mmask16, + a: __m512, b: __m512, - c: __m512, rounding: i32, ) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f32x16()); + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vdivps(a, b, $imm4) }; } - let fmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsub, a.as_f32x16())) + let divround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, divround, src.as_f32x16())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_ps&expand=2654) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_ps&expand=2170) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmsub_round_ps( +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_div_round_ps( k: __mmask16, a: __m512, b: __m512, - c: __m512, rounding: i32, ) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f32x16()); + let a = a.as_f32x16(); + let b = b.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vdivps(a, b, $imm4) }; } - let fmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsub, zero)) + let divround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, divround, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, =and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_ps&expand=2653) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_pd&expand=2165) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmsub_round_ps( - a: __m512, - b: __m512, - c: __m512, - k: __mmask16, - rounding: i32, -) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f32x16()); +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_div_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vdivpd(a, b, $imm4) }; } - let fmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsub, c.as_f32x16())) + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_pd&expand=2647) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_pd&expand=2166) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f64x8()); +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_div_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vdivpd(a, b, $imm4) }; } - let r = constify_imm4_round!(rounding, call); - transmute(r) + let divround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, divround, src.as_f64x8())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_pd&expand=2648) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_pd&expand=2167) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmsub_round_pd( - a: __m512d, +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_div_round_pd( k: __mmask8, + a: __m512d, b: __m512d, - c: __m512d, rounding: i32, ) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f64x8()); + let a = a.as_f64x8(); + let b = b.as_f64x8(); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vdivpd(a, b, $imm4) }; } - let fmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsub, a.as_f64x8())) + let divround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, divround, zero)) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_pd&expand=2650) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_ps&expand=5377) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmsub_round_pd( - k: __mmask8, - a: __m512d, - b: __m512d, - c: __m512d, +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_sqrt_round_ps(a: __m512, rounding: i32) -> __m512 { + let a = a.as_f32x16(); + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_ps&expand=5375) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_sqrt_round_ps( + src: __m512, + k: __mmask16, + a: __m512, rounding: i32, -) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f64x8()); +) -> __m512 { + let a = a.as_f32x16(); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vsqrtps(a, $imm4) }; } - let fmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsub, zero)) + let sqrtround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, sqrtround, src.as_f32x16())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_pd&expand=2649) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_ps&expand=5376) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmsub_round_pd( - a: __m512d, - b: __m512d, - c: __m512d, +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_sqrt_round_ps(k: __mmask16, a: __m512, rounding: i32) -> __m512 { + let a = a.as_f32x16(); + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a, $imm4) + }; + } + let sqrtround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, sqrtround, zero)) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_pd&expand=5374) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_sqrt_round_pd(a: __m512d, rounding: i32) -> __m512d { + let a = a.as_f64x8(); + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_pd&expand=5372) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_sqrt_round_pd( + src: __m512d, k: __mmask8, + a: __m512d, rounding: i32, ) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vsqrtpd(a.as_f64x8(), $imm4) }; } - let fmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsub, c.as_f64x8())) + let sqrtround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, sqrtround, src.as_f64x8())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_ps&expand=2619) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_pd&expand=5373) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_sqrt_round_pd(k: __mmask8, a: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a.as_f64x8(), $imm4) + }; + } + let sqrtround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, sqrtround, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_ps&expand=2565) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmaddsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { +pub unsafe fn _mm512_fmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_ps&expand=2620) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_ps&expand=2566) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmaddsub_round_ps( +pub unsafe fn _mm512_mask_fmadd_round_ps( a: __m512, k: __mmask16, b: __m512, @@ -3540,28 +3764,28 @@ pub unsafe fn _mm512_mask_fmaddsub_round_ps( ) -> __m512 { macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let fmaddsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmaddsub, a.as_f32x16())) + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, a.as_f32x16())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in a using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_ps&expand=2622) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_ps&expand=2568) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmaddsub_round_ps( +pub unsafe fn _mm512_maskz_fmadd_round_ps( k: __mmask16, a: __m512, b: __m512, @@ -3570,29 +3794,29 @@ pub unsafe fn _mm512_maskz_fmaddsub_round_ps( ) -> __m512 { macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let fmaddsub = constify_imm4_round!(rounding, call); + let fmadd = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, fmaddsub, zero)) + transmute(simd_select_bitmask(k, fmadd, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_ps&expand=2621) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_ps&expand=2567) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmaddsub_round_ps( +pub unsafe fn _mm512_mask3_fmadd_round_ps( a: __m512, b: __m512, c: __m512, @@ -3601,57 +3825,52 @@ pub unsafe fn _mm512_mask3_fmaddsub_round_ps( ) -> __m512 { macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let fmaddsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmaddsub, c.as_f32x16())) + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, c.as_f32x16())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_pd&expand=2615) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_pd&expand=2561) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmaddsub_round_pd( - a: __m512d, - b: __m512d, - c: __m512d, - rounding: i32, -) -> __m512d { +pub unsafe fn _mm512_fmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_pd&expand=2616) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_pd&expand=2562) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmaddsub_round_pd( +pub unsafe fn _mm512_mask_fmadd_round_pd( a: __m512d, k: __mmask8, b: __m512d, @@ -3660,28 +3879,28 @@ pub unsafe fn _mm512_mask_fmaddsub_round_pd( ) -> __m512d { macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let fmaddsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmaddsub, a.as_f64x8())) -} + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, a.as_f64x8())) +} -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_pd&expand=2618) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_pd&expand=2564) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmaddsub_round_pd( +pub unsafe fn _mm512_maskz_fmadd_round_pd( k: __mmask8, a: __m512d, b: __m512d, @@ -3690,29 +3909,29 @@ pub unsafe fn _mm512_maskz_fmaddsub_round_pd( ) -> __m512d { macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let fmaddsub = constify_imm4_round!(rounding, call); + let fmadd = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, fmaddsub, zero)) + transmute(simd_select_bitmask(k, fmadd, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_pd&expand=2617) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_pd&expand=2563) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmaddsub_round_pd( +pub unsafe fn _mm512_mask3_fmadd_round_pd( a: __m512d, b: __m512d, c: __m512d, @@ -3721,54 +3940,54 @@ pub unsafe fn _mm512_mask3_fmaddsub_round_pd( ) -> __m512d { macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let fmaddsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmaddsub, c.as_f64x8())) + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, c.as_f64x8())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_ps&expand=2699) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_ps&expand=2651) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmsubadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { +pub unsafe fn _mm512_fmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { let zero: f32x16 = mem::zeroed(); let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_ps&expand=2700) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_ps&expand=2652) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmsubadd_round_ps( +pub unsafe fn _mm512_mask_fmsub_round_ps( a: __m512, k: __mmask16, b: __m512, @@ -3779,28 +3998,28 @@ pub unsafe fn _mm512_mask_fmsubadd_round_ps( let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } - let fmsubadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsubadd, a.as_f32x16())) + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, a.as_f32x16())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_ps&expand=2702) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_ps&expand=2654) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmsubadd_round_ps( +pub unsafe fn _mm512_maskz_fmsub_round_ps( k: __mmask16, a: __m512, b: __m512, @@ -3811,28 +4030,28 @@ pub unsafe fn _mm512_maskz_fmsubadd_round_ps( let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } - let fmsubadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsubadd, zero)) + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_ps&expand=2701) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_ps&expand=2653) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmsubadd_round_ps( +pub unsafe fn _mm512_mask3_fmsub_round_ps( a: __m512, b: __m512, c: __m512, @@ -3843,59 +4062,54 @@ pub unsafe fn _mm512_mask3_fmsubadd_round_ps( let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } - let fmsubadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsubadd, c.as_f32x16())) + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, c.as_f32x16())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_pd&expand=2695) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_pd&expand=2647) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fmsubadd_round_pd( - a: __m512d, - b: __m512d, - c: __m512d, - rounding: i32, -) -> __m512d { +pub unsafe fn _mm512_fmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { let zero: f64x8 = mem::zeroed(); let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_pd&expand=2696) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_pd&expand=2648) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fmsubadd_round_pd( +pub unsafe fn _mm512_mask_fmsub_round_pd( a: __m512d, k: __mmask8, b: __m512d, @@ -3906,28 +4120,28 @@ pub unsafe fn _mm512_mask_fmsubadd_round_pd( let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } - let fmsubadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsubadd, a.as_f64x8())) + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, a.as_f64x8())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_pd&expand=2698) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_pd&expand=2650) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fmsubadd_round_pd( +pub unsafe fn _mm512_maskz_fmsub_round_pd( k: __mmask8, a: __m512d, b: __m512d, @@ -3938,28 +4152,28 @@ pub unsafe fn _mm512_maskz_fmsubadd_round_pd( let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } - let fmsubadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsubadd, zero)) + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, zero)) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_pd&expand=2697) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_pd&expand=2649) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fmsubadd_round_pd( +pub unsafe fn _mm512_mask3_fmsub_round_pd( a: __m512d, b: __m512d, c: __m512d, @@ -3970,299 +4184,289 @@ pub unsafe fn _mm512_mask3_fmsubadd_round_pd( let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } - let fmsubadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fmsubadd, c.as_f64x8())) + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, c.as_f64x8())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_round_ps&expand=2731) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_ps&expand=2619) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fnmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f32x16()); +pub unsafe fn _mm512_fmaddsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { macro_rules! call { ($imm4:expr) => { - vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_ps&expand=2732) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_ps&expand=2620) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fnmadd_round_ps( +pub unsafe fn _mm512_mask_fmaddsub_round_ps( a: __m512, k: __mmask16, b: __m512, c: __m512, rounding: i32, ) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let fnmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmadd, a.as_f32x16())) + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f32x16())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_ps&expand=2734) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_ps&expand=2622) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fnmadd_round_ps( +pub unsafe fn _mm512_maskz_fmaddsub_round_ps( k: __mmask16, a: __m512, b: __m512, c: __m512, rounding: i32, ) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let fnmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmadd, zero)) + let fmaddsub = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_ps&expand=2733) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_ps&expand=2621) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fnmadd_round_ps( +pub unsafe fn _mm512_mask3_fmaddsub_round_ps( a: __m512, b: __m512, c: __m512, k: __mmask16, rounding: i32, ) -> __m512 { - let zero: f32x16 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let fnmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmadd, c.as_f32x16())) -} + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f32x16())) +} -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_pd&expand=2711) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_pd&expand=2615) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fnmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f64x8()); +pub unsafe fn _mm512_fmaddsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { macro_rules! call { ($imm4:expr) => { - vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_pd&expand=2728) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_pd&expand=2616) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fnmadd_round_pd( +pub unsafe fn _mm512_mask_fmaddsub_round_pd( a: __m512d, k: __mmask8, b: __m512d, c: __m512d, rounding: i32, ) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let fnmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmadd, a.as_f64x8())) + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f64x8())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_pd&expand=2730) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_pd&expand=2618) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fnmadd_round_pd( +pub unsafe fn _mm512_maskz_fmaddsub_round_pd( k: __mmask8, a: __m512d, b: __m512d, c: __m512d, rounding: i32, ) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let fnmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmadd, zero)) + let fmaddsub = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_pd&expand=2729) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_pd&expand=2617) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fnmadd_round_pd( +pub unsafe fn _mm512_mask3_fmaddsub_round_pd( a: __m512d, b: __m512d, c: __m512d, k: __mmask8, rounding: i32, ) -> __m512d { - let zero: f64x8 = mem::zeroed(); - let sub = simd_sub(zero, a.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let fnmadd = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmadd, c.as_f64x8())) + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f64x8())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_ps&expand=2779) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_ps&expand=2699) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fnmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { +pub unsafe fn _mm512_fmsubadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { let zero: f32x16 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f32x16()); - let subc = simd_sub(zero, c.as_f32x16()); + let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_ps&expand=2780) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_ps&expand=2700) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fnmsub_round_ps( +pub unsafe fn _mm512_mask_fmsubadd_round_ps( a: __m512, k: __mmask16, b: __m512, @@ -4270,32 +4474,31 @@ pub unsafe fn _mm512_mask_fnmsub_round_ps( rounding: i32, ) -> __m512 { let zero: f32x16 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f32x16()); - let subc = simd_sub(zero, c.as_f32x16()); + let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } - let fnmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmsub, a.as_f32x16())) + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f32x16())) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_ps&expand=2782) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_ps&expand=2702) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fnmsub_round_ps( +pub unsafe fn _mm512_maskz_fmsubadd_round_ps( k: __mmask16, a: __m512, b: __m512, @@ -4303,32 +4506,31 @@ pub unsafe fn _mm512_maskz_fnmsub_round_ps( rounding: i32, ) -> __m512 { let zero: f32x16 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f32x16()); - let subc = simd_sub(zero, c.as_f32x16()); + let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } - let fnmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmsub, zero)) + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, zero)) } -/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_ps&expand=2781) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_ps&expand=2701) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fnmsub_round_ps( +pub unsafe fn _mm512_mask3_fmsubadd_round_ps( a: __m512, b: __m512, c: __m512, @@ -4336,59 +4538,62 @@ pub unsafe fn _mm512_mask3_fnmsub_round_ps( rounding: i32, ) -> __m512 { let zero: f32x16 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f32x16()); - let subc = simd_sub(zero, c.as_f32x16()); + let sub = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) }; } - let fnmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmsub, c.as_f32x16())) + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f32x16())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_pd&expand=2775) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_pd&expand=2695) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd #[rustc_args_required_const(3)] -pub unsafe fn _mm512_fnmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { +pub unsafe fn _mm512_fmsubadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { let zero: f64x8 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f64x8()); - let subc = simd_sub(zero, c.as_f64x8()); + let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_pd&expand=2776) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_pd&expand=2696) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_fnmsub_round_pd( +pub unsafe fn _mm512_mask_fmsubadd_round_pd( a: __m512d, k: __mmask8, b: __m512d, @@ -4396,32 +4601,31 @@ pub unsafe fn _mm512_mask_fnmsub_round_pd( rounding: i32, ) -> __m512d { let zero: f64x8 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f64x8()); - let subc = simd_sub(zero, c.as_f64x8()); + let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } - let fnmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmsub, a.as_f64x8())) + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f64x8())) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_pd&expand=2778) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_pd&expand=2698) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_maskz_fnmsub_round_pd( +pub unsafe fn _mm512_maskz_fmsubadd_round_pd( k: __mmask8, a: __m512d, b: __m512d, @@ -4429,32 +4633,31 @@ pub unsafe fn _mm512_maskz_fnmsub_round_pd( rounding: i32, ) -> __m512d { let zero: f64x8 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f64x8()); - let subc = simd_sub(zero, c.as_f64x8()); + let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } - let fnmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmsub, zero)) + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, zero)) } -/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_pd&expand=2777) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_pd&expand=2697) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask3_fnmsub_round_pd( +pub unsafe fn _mm512_mask3_fmsubadd_round_pd( a: __m512d, b: __m512d, c: __m512d, @@ -4462,860 +4665,1083 @@ pub unsafe fn _mm512_mask3_fnmsub_round_pd( rounding: i32, ) -> __m512d { let zero: f64x8 = mem::zeroed(); - let suba = simd_sub(zero, a.as_f64x8()); - let subc = simd_sub(zero, c.as_f64x8()); + let sub = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) }; } - let fnmsub = constify_imm4_round!(rounding, call); - transmute(simd_select_bitmask(k, fnmsub, c.as_f64x8())) + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst. -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=max_round_ps&expand=3662) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_round_ps&expand=2731) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_max_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_ps&expand=3660) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_ps&expand=2732) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_max_round_ps( - src: __m512, - k: __mmask16, +pub unsafe fn _mm512_mask_fnmadd_round_ps( a: __m512, + k: __mmask16, b: __m512, - sae: i32, + c: __m512, + rounding: i32, ) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let max = constify_imm4_sae!(sae, call); - transmute(simd_select_bitmask(k, max, src.as_f32x16())) + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, a.as_f32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_ps&expand=3661) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_ps&expand=2734) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_max_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmadd_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let max = constify_imm4_sae!(sae, call); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, max, zero)) + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst. -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_round_pd&expand=3659) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_ps&expand=2733) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_max_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmadd_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) }; } - let r = constify_imm4_sae!(sae, call); - transmute(r) + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, c.as_f32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_pd&expand=3657) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_pd&expand=2711) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_max_round_pd( - src: __m512d, - k: __mmask8, - a: __m512d, - b: __m512d, - sae: i32, -) -> __m512d { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let max = constify_imm4_sae!(sae, call); - transmute(simd_select_bitmask(k, max, src.as_f64x8())) + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_pd&expand=3658) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_pd&expand=2728) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_max_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmadd_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let max = constify_imm4_sae!(sae, call); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, max, zero)) + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, a.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst. -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_ps&expand=3776) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_pd&expand=2730) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vminps, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_min_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmadd_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let r = constify_imm4_sae!(sae, call); - transmute(r) + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_ps&expand=3774) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_pd&expand=2729) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_min_round_ps( - src: __m512, - k: __mmask16, - a: __m512, - b: __m512, - sae: i32, -) -> __m512 { +pub unsafe fn _mm512_mask3_fnmadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) }; } - let max = constify_imm4_sae!(sae, call); - transmute(simd_select_bitmask(k, max, src.as_f32x16())) + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, c.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_ps&expand=3775) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_ps&expand=2779) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps #[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_min_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { +pub unsafe fn _mm512_fnmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) }; } - let max = constify_imm4_sae!(sae, call); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, max, zero)) + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst. -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_pd&expand=3773) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_ps&expand=2780) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vminpd, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_min_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmsub_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); macro_rules! call { ($imm4:expr) => { - vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) }; } - let r = constify_imm4_sae!(sae, call); - transmute(r) + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, a.as_f32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_pd&expand=3771) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_ps&expand=2782) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_min_round_pd( - src: __m512d, - k: __mmask8, +pub unsafe fn _mm512_maskz_fnmsub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_ps&expand=2781) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmsub_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_pd&expand=2775) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set).\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_pd&expand=2776) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmsub_round_pd( a: __m512d, + k: __mmask8, b: __m512d, - sae: i32, + c: __m512d, + rounding: i32, ) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) }; } - let max = constify_imm4_sae!(sae, call); - transmute(simd_select_bitmask(k, max, src.as_f64x8())) + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, a.as_f64x8())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_pd&expand=3772) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_pd&expand=2778) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vminpd, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_min_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmsub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); macro_rules! call { ($imm4:expr) => { - vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) }; } - let max = constify_imm4_sae!(sae, call); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, max, zero)) + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, zero)) } -/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set).\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_pd&expand=2777) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, c.as_f64x8())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst.\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_ps&expand=2850) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=max_round_ps&expand=3662) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_getexp_round_ps(a: __m512, sae: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_max_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { macro_rules! call { ($imm4:expr) => { - vgetexpps( - a.as_f32x16(), - _mm512_setzero_ps().as_f32x16(), - 0b11111111_11111111, - $imm4, - ) + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) }; } let r = constify_imm4_sae!(sae, call); transmute(r) } -/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_ps&expand=2851) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_ps&expand=3660) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_getexp_round_ps( +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_max_round_ps( src: __m512, k: __mmask16, a: __m512, + b: __m512, sae: i32, ) -> __m512 { macro_rules! call { ($imm4:expr) => { - vgetexpps(a.as_f32x16(), src.as_f32x16(), k, $imm4) + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) }; } - let r = constify_imm4_sae!(sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) } -/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_ps&expand=2852) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_ps&expand=3661) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_getexp_round_ps(k: __mmask16, a: __m512, sae: i32) -> __m512 { +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_max_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { macro_rules! call { ($imm4:expr) => { - vgetexpps(a.as_f32x16(), _mm512_setzero_ps().as_f32x16(), k, $imm4) + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) }; } - let r = constify_imm4_sae!(sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst.\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_pd&expand=2847) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_round_pd&expand=3659) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_getexp_round_pd(a: __m512d, sae: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_max_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { macro_rules! call { ($imm4:expr) => { - vgetexppd( - a.as_f64x8(), - _mm512_setzero_pd().as_f64x8(), - 0b11111111, - $imm4, - ) + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) }; } let r = constify_imm4_sae!(sae, call); transmute(r) } -/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_pd&expand=2848) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_pd&expand=3657) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_getexp_round_pd( +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_max_round_pd( src: __m512d, k: __mmask8, a: __m512d, + b: __m512d, sae: i32, ) -> __m512d { macro_rules! call { ($imm4:expr) => { - vgetexppd(a.as_f64x8(), src.as_f64x8(), k, $imm4) + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) }; } - let r = constify_imm4_sae!(sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) } -/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_pd&expand=2849) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_pd&expand=3658) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_getexp_round_pd(k: __mmask8, a: __m512d, sae: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_max_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { macro_rules! call { ($imm4:expr) => { - vgetexppd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) }; } - let r = constify_imm4_sae!(sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst.\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_ps&expand=2886) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_ps&expand=3776) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] -#[rustc_args_required_const(1, 2, 3)] -pub unsafe fn _mm512_getmant_round_ps( - a: __m512, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, - sae: i32, -) -> __m512 { +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_min_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { macro_rules! call { - ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { - vgetmantps( - a.as_f32x16(), - $imm2 << 2 | $imm4_1, - _mm512_setzero_ps().as_f32x16(), - 0b11111111_11111111, - $imm4_2, - ) + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) }; } - let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + let r = constify_imm4_sae!(sae, call); transmute(r) } -/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_ps&expand=2887) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_ps&expand=3774) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] -#[rustc_args_required_const(3, 4, 5)] -pub unsafe fn _mm512_mask_getmant_round_ps( +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_min_round_ps( src: __m512, k: __mmask16, a: __m512, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, + b: __m512, sae: i32, ) -> __m512 { macro_rules! call { - ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { - vgetmantps( - a.as_f32x16(), - $imm2 << 2 | $imm4_1, - src.as_f32x16(), - k, - $imm4_2, - ) + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) }; } - let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) } -/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_ps&expand=2888) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_ps&expand=3775) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] -#[rustc_args_required_const(2, 3, 4)] -pub unsafe fn _mm512_maskz_getmant_round_ps( - k: __mmask16, - a: __m512, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, - sae: i32, -) -> __m512 { +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_min_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { macro_rules! call { - ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { - vgetmantps( - a.as_f32x16(), - $imm2 << 2 | $imm4_1, - _mm512_setzero_ps().as_f32x16(), - k, - $imm4_2, - ) + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) }; } - let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst.\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_pd&expand=2883) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_pd&expand=3773) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] -#[rustc_args_required_const(1, 2, 3)] -pub unsafe fn _mm512_getmant_round_pd( - a: __m512d, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, - sae: i32, -) -> __m512d { +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_min_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { macro_rules! call { - ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { - vgetmantpd( - a.as_f64x8(), - $imm2 << 2 | $imm4_1, - _mm512_setzero_pd().as_f64x8(), - 0b11111111, - $imm4_2, - ) + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) }; } - let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + let r = constify_imm4_sae!(sae, call); transmute(r) } -/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_pd&expand=2884) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_pd&expand=3771) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] -#[rustc_args_required_const(3, 4, 5)] -pub unsafe fn _mm512_mask_getmant_round_pd( +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_min_round_pd( src: __m512d, k: __mmask8, a: __m512d, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, + b: __m512d, sae: i32, ) -> __m512d { macro_rules! call { - ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { - vgetmantpd( - a.as_f64x8(), - $imm2 << 2 | $imm4_1, - src.as_f64x8(), - k, - $imm4_2, - ) + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) }; } - let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) } -/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. -/// The mantissa is normalized to the interval specified by interv, which can take the following values: -/// _MM_MANT_NORM_1_2 // interval [1, 2) -/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) -/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) -/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) -/// The sign is determined by sc which can take the following values: -/// _MM_MANT_SIGN_src // sign = sign(src) -/// _MM_MANT_SIGN_zero // sign = 0 -/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_pd&expand=2885) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_pd&expand=3772) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] -#[rustc_args_required_const(2, 3, 4)] -pub unsafe fn _mm512_maskz_getmant_round_pd( - k: __mmask8, - a: __m512d, - norm: _MM_MANTISSA_NORM_ENUM, - sign: _MM_MANTISSA_SIGN_ENUM, - sae: i32, -) -> __m512d { +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_min_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { macro_rules! call { - ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { - vgetmantpd( - a.as_f64x8(), - $imm2 << 2 | $imm4_1, - _mm512_setzero_pd().as_f64x8(), - k, - $imm4_2, - ) + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) }; } - let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); - transmute(r) + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvtps_epi32&expand=1737) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_ps&expand=2850) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2dq))] -pub unsafe fn _mm512_cvtps_epi32(a: __m512) -> __m512i { - transmute(vcvtps2dq( - a.as_f32x16(), - _mm512_setzero_si512().as_i32x16(), - 0b11111111_11111111, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_getexp_round_ps(a: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epi32&expand=1738) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_ps&expand=2851) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2dq))] -pub unsafe fn _mm512_mask_cvtps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { - transmute(vcvtps2dq( - a.as_f32x16(), - src.as_i32x16(), - k, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_getexp_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps(a.as_f32x16(), src.as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_epi32&expand=1739) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_ps&expand=2852) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2dq))] -pub unsafe fn _mm512_maskz_cvtps_epi32(k: __mmask16, a: __m512) -> __m512i { - transmute(vcvtps2dq( - a.as_f32x16(), - _mm512_setzero_si512().as_i32x16(), - k, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_getexp_round_ps(k: __mmask16, a: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps(a.as_f32x16(), _mm512_setzero_ps().as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_epu32&expand=1755) +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_pd&expand=2847) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2udq))] -pub unsafe fn _mm512_cvtps_epu32(a: __m512) -> __m512i { - transmute(vcvtps2udq( - a.as_f32x16(), - _mm512_setzero_si512().as_u32x16(), - 0b11111111_11111111, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_getexp_round_pd(a: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epu32&expand=1756) +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_pd&expand=2848) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2udq))] -pub unsafe fn _mm512_mask_cvtps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { - transmute(vcvtps2udq( - a.as_f32x16(), - src.as_u32x16(), - k, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_getexp_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd(a.as_f64x8(), src.as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_pd&expand=2849) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2udq))] -pub unsafe fn _mm512_maskz_cvtps_epu32(k: __mmask16, a: __m512) -> __m512i { - transmute(vcvtps2udq( - a.as_f32x16(), - _mm512_setzero_si512().as_u32x16(), - k, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_getexp_round_pd(k: __mmask8, a: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. +/// Round packed single-precision (32-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_pd&expand=1769) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_roundscale_round_ps&expand=4790) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2pd))] -pub unsafe fn _mm512_cvtps_pd(a: __m256) -> __m512d { - transmute(vcvtps2pd( - a.as_f32x8(), - _mm512_setzero_pd().as_f64x8(), - 0b11111111, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vrndscaleps, imm8 = 0, sae = 8))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_roundscale_round_ps(a: __m512, imm8: i32, sae: i32) -> __m512 { + let a = a.as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscaleps(a, $imm8, zero, 0b11111111_11111111, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Round packed single-precision (32-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_pd&expand=1770) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_roundscale_round_ps&expand=4788) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2pd))] -pub unsafe fn _mm512_mask_cvtps_pd(src: __m512d, k: __mmask8, a: __m256) -> __m512d { - transmute(vcvtps2pd( - a.as_f32x8(), - src.as_f64x8(), - k, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vrndscaleps, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_roundscale_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + imm8: i32, + sae: i32, +) -> __m512 { + let a = a.as_f32x16(); + let src = src.as_f32x16(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscaleps(a, $imm8, src, k, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Round packed single-precision (32-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_pd&expand=1771) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_roundscale_round_ps&expand=4789) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2pd))] -pub unsafe fn _mm512_maskz_cvtps_pd(k: __mmask8, a: __m256) -> __m512d { - transmute(vcvtps2pd( - a.as_f32x8(), - _mm512_setzero_pd().as_f64x8(), - k, - _MM_FROUND_CUR_DIRECTION, - )) +#[cfg_attr(test, assert_instr(vrndscaleps, imm8 = 0, sae = 8))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_roundscale_round_ps( + k: __mmask16, + a: __m512, + imm8: i32, + sae: i32, +) -> __m512 { + let a = a.as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscaleps(a, $imm8, zero, k, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. +/// Round packed double-precision (64-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epi32&expand=1335) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_roundscale_round_pd&expand=4787) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_cvt_roundps_epi32(a: __m512, rounding: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vrndscalepd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_roundscale_round_pd(a: __m512d, imm8: i32, sae: i32) -> __m512d { + let a = a.as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); macro_rules! call { - ($imm4:expr) => { - vcvtps2dq( - a.as_f32x16(), - _mm512_setzero_si512().as_i32x16(), - 0b11111111_11111111, - $imm4, - ) + ($imm8:expr, $imm4:expr) => { + vrndscalepd(a, $imm8, zero, 0b11111111, $imm4) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Round packed double-precision (64-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_roundscale_round_pd&expand=4785) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_cvt_roundps_epi32( - src: __m512i, - k: __mmask16, - a: __m512, - rounding: i32, -) -> __m512i { +#[cfg_attr(test, assert_instr(vrndscalepd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_roundscale_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + imm8: i32, + sae: i32, +) -> __m512d { + let a = a.as_f64x8(); + let src = src.as_f64x8(); macro_rules! call { - ($imm4:expr) => { - vcvtps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + ($imm8:expr, $imm4:expr) => { + vrndscalepd(a, $imm8, src, k, $imm4) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Round packed double-precision (64-bit) floating-point elements in a to the number of fraction bits specified by imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions -/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_roundscale_round_pd&expand=4786) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_cvt_roundps_epi32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vrndscalepd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_roundscale_round_pd( + k: __mmask8, + a: __m512d, + imm8: i32, + sae: i32, +) -> __m512d { + let a = a.as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); macro_rules! call { - ($imm4:expr) => { - vcvtps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + ($imm8:expr, $imm4:expr) => { + vrndscalepd(a, $imm8, zero, k, $imm4) }; } - let r = constify_imm4_round!(rounding, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst. +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, and store the results in dst.\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epu32&expand=1341) +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_scalef_round_ps&expand=4889) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_cvt_roundps_epu32(a: __m512, rounding: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vscalefps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_scalef_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { macro_rules! call { ($imm4:expr) => { - vcvtps2udq( + vscalefps( a.as_f32x16(), - _mm512_setzero_si512().as_u32x16(), + b.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), 0b11111111_11111111, $imm4, ) @@ -5325,369 +5751,574 @@ pub unsafe fn _mm512_cvt_roundps_epu32(a: __m512, rounding: i32) -> __m512i { transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epu32&expand=1342) +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_scalef_round_ps&expand=4887) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_cvt_roundps_epu32( - src: __m512i, +#[cfg_attr(test, assert_instr(vscalefps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_scalef_round_ps( + src: __m512, k: __mmask16, a: __m512, + b: __m512, rounding: i32, -) -> __m512i { +) -> __m512 { macro_rules! call { ($imm4:expr) => { - vcvtps2udq(a.as_f32x16(), src.as_u32x16(), k, $imm4) + vscalefps(a.as_f32x16(), b.as_f32x16(), src.as_f32x16(), k, $imm4) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: -/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions -/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions -/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions -/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ /// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_scalef_round_ps&expand=4888) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_cvt_roundps_epu32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vscalefps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_scalef_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { macro_rules! call { ($imm4:expr) => { - vcvtps2udq(a.as_f32x16(), _mm512_setzero_si512().as_u32x16(), k, $imm4) + vscalefps( + a.as_f32x16(), + b.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + k, + $imm4, + ) }; } let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvt_roundps_pd&expand=1347) +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, and store the results in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_scalef_round_pd&expand=4886) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_cvt_roundps_pd(a: __m256, sae: i32) -> __m512d { +#[cfg_attr(test, assert_instr(vscalefpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_scalef_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { macro_rules! call { ($imm4:expr) => { - vcvtps2pd( - a.as_f32x8(), + vscalefpd( + a.as_f64x8(), + b.as_f64x8(), _mm512_setzero_pd().as_f64x8(), 0b11111111, $imm4, ) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_scalef_round_pd&expand=4884) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_cvt_roundps_pd( +#[cfg_attr(test, assert_instr(vscalefpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_scalef_round_pd( src: __m512d, k: __mmask8, - a: __m256, - sae: i32, + a: __m512d, + b: __m512d, + rounding: i32, ) -> __m512d { macro_rules! call { ($imm4:expr) => { - vcvtps2pd(a.as_f32x8(), src.as_f64x8(), k, $imm4) + vscalefpd(a.as_f64x8(), b.as_f64x8(), src.as_f64x8(), k, $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_cvt_roundps_pd(k: __mmask8, a: __m256, sae: i32) -> __m512d { - macro_rules! call { - ($imm4:expr) => { - vcvtps2pd(a.as_f32x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) - }; - } - let r = constify_imm4_sae!(sae, call); - transmute(r) -} - -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epi32&expand=1916) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_scalef_round_pd&expand=4885) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_cvtt_roundps_epi32(a: __m512, sae: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vscalefpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_scalef_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { macro_rules! call { ($imm4:expr) => { - vcvttps2dq( - a.as_f32x16(), - _mm512_setzero_si512().as_i32x16(), - 0b11111111_11111111, + vscalefpd( + a.as_f64x8(), + b.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + k, $imm4, ) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Fix up packed single-precision (32-bit) floating-point elements in a and b using packed 32-bit integers in c, and store the results in dst. imm8 is used to set the required flags reporting.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epi32&expand=1917) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fixupimm_round_ps&expand=2505) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_cvtt_roundps_epi32( - src: __m512i, - k: __mmask16, +#[cfg_attr(test, assert_instr(vfixupimmps, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_fixupimm_round_ps( a: __m512, + b: __m512, + c: __m512i, + imm8: i32, sae: i32, -) -> __m512i { +) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); + let c = c.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vcvttps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + ($imm8:expr, $imm4:expr) => { + vfixupimmps(a, b, c, $imm8, 0b11111111_11111111, $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Fix up packed single-precision (32-bit) floating-point elements in a and b using packed 32-bit integers in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). imm8 is used to set the required flags reporting.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fixupimm_round_ps&expand=2506) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_cvtt_roundps_epi32(k: __mmask16, a: __m512, sae: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vfixupimmps, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm512_mask_fixupimm_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512i, + imm8: i32, + sae: i32, +) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); + let c = c.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vcvttps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + ($imm8:expr, $imm4:expr) => { + vfixupimmps(a, b, c, $imm8, k, $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// Fix up packed single-precision (32-bit) floating-point elements in a and b using packed 32-bit integers in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). imm8 is used to set the required flags reporting.\ +/// /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epu32&expand=1922) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fixupimm_round_ps&expand=2507) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_cvtt_roundps_epu32(a: __m512, sae: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vfixupimmps, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm512_maskz_fixupimm_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512i, + imm8: i32, + sae: i32, +) -> __m512 { + let a = a.as_f32x16(); + let b = b.as_f32x16(); + let c = c.as_i32x16(); macro_rules! call { - ($imm4:expr) => { - vcvttps2udq( - a.as_f32x16(), - _mm512_setzero_si512().as_i32x16(), - 0b11111111_11111111, - $imm4, - ) + ($imm8:expr, $imm4:expr) => { + vfixupimmpsz(a, b, c, $imm8, k, $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Fix up packed double-precision (64-bit) floating-point elements in a and b using packed 64-bit integers in c, and store the results in dst. imm8 is used to set the required flags reporting.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epu32&expand=1923) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fixupimm_round_pd&expand=2502) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_cvtt_roundps_epu32( - src: __m512i, - k: __mmask16, - a: __m512, +#[cfg_attr(test, assert_instr(vfixupimmpd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_fixupimm_round_pd( + a: __m512d, + b: __m512d, + c: __m512i, + imm8: i32, sae: i32, -) -> __m512i { +) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vcvttps2udq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + ($imm8:expr, $imm4:expr) => { + vfixupimmpd(a, b, c, $imm8, 0b11111111, $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// Fix up packed double-precision (64-bit) floating-point elements in a and b using packed 64-bit integers in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). imm8 is used to set the required flags reporting.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epu32&expand=1924) +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fixupimm_round_pd&expand=2503) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_cvtt_roundps_epu32(k: __mmask16, a: __m512, sae: i32) -> __m512i { +#[cfg_attr(test, assert_instr(vfixupimmpd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm512_mask_fixupimm_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512i, + imm8: i32, + sae: i32, +) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vcvttps2udq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + ($imm8:expr, $imm4:expr) => { + vfixupimmpd(a, b, c, $imm8, k, $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// Fix up packed double-precision (64-bit) floating-point elements in a and b using packed 64-bit integers in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). imm8 is used to set the required flags reporting.\ +/// /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epi32&expand=1904) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fixupimm_round_pd&expand=2504) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_cvtt_roundpd_epi32(a: __m512d, sae: i32) -> __m256i { +#[cfg_attr(test, assert_instr(vfixupimmpd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm512_maskz_fixupimm_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512i, + imm8: i32, + sae: i32, +) -> __m512d { + let a = a.as_f64x8(); + let b = b.as_f64x8(); + let c = c.as_i64x8(); macro_rules! call { - ($imm4:expr) => { - vcvttpd2dq( - a.as_f64x8(), - _mm256_setzero_si256().as_i32x8(), - 0b11111111, - $imm4, - ) + ($imm8:expr, $imm4:expr) => { + vfixupimmpdz(a, b, c, $imm8, k, $imm4) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm8_roundscale!(imm8, sae, call); transmute(r) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epi32&expand=1905) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_ps&expand=2886) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_cvtt_roundpd_epi32( - src: __m256i, - k: __mmask8, - a: __m512d, +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(1, 2, 3)] +pub unsafe fn _mm512_getmant_round_ps( + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, sae: i32, -) -> __m256i { +) -> __m512 { macro_rules! call { - ($imm4:expr) => { - vcvttpd2dq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + $imm4_2, + ) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_ps&expand=2887) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_cvtt_roundpd_epi32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm512_mask_getmant_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { macro_rules! call { - ($imm4:expr) => { - vcvttpd2dq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + src.as_f32x16(), + k, + $imm4_2, + ) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); transmute(r) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epu32&expand=1910) +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_ps&expand=2888) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_cvtt_roundpd_epu32(a: __m512d, sae: i32) -> __m256i { +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm512_maskz_getmant_round_ps( + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { macro_rules! call { - ($imm4:expr) => { - vcvttpd2udq( + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_ps().as_f32x16(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_pd&expand=2883) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(1, 2, 3)] +pub unsafe fn _mm512_getmant_round_pd( + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( a.as_f64x8(), - _mm256_setzero_si256().as_i32x8(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_pd().as_f64x8(), 0b11111111, - $imm4, + $imm4_2, ) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); transmute(r) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ /// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epu32&expand=1911) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_pd&expand=2884) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_cvtt_roundpd_epu32( - src: __m256i, +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm512_mask_getmant_round_pd( + src: __m512d, k: __mmask8, a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, sae: i32, -) -> __m256i { +) -> __m512d { macro_rules! call { - ($imm4:expr) => { - vcvttpd2udq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + src.as_f64x8(), + k, + $imm4_2, + ) }; } - let r = constify_imm4_sae!(sae, call); + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); transmute(r) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epi32&expand=1984) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_pd&expand=2885) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2dq))] -pub unsafe fn _mm512_cvttps_epi32(a: __m512) -> __m512i { - transmute(vcvttps2dq( +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm512_maskz_getmant_round_pd( + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_pd().as_f64x8(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvtps_epi32&expand=1737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_cvtps_epi32(a: __m512) -> __m512i { + transmute(vcvtps2dq( a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), 0b11111111_11111111, @@ -5695,14 +6326,14 @@ pub unsafe fn _mm512_cvttps_epi32(a: __m512) -> __m512i { )) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epi32&expand=1985) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epi32&expand=1738) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2dq))] -pub unsafe fn _mm512_mask_cvttps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { - transmute(vcvttps2dq( +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_mask_cvtps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2dq( a.as_f32x16(), src.as_i32x16(), k, @@ -5710,14 +6341,14 @@ pub unsafe fn _mm512_mask_cvttps_epi32(src: __m512i, k: __mmask16, a: __m512) -> )) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epi32&expand=1986) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_epi32&expand=1739) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2dq))] -pub unsafe fn _mm512_maskz_cvttps_epi32(k: __mmask16, a: __m512) -> __m512i { - transmute(vcvttps2dq( +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_maskz_cvtps_epi32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2dq( a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, @@ -5725,7885 +6356,18196 @@ pub unsafe fn _mm512_maskz_cvttps_epi32(k: __mmask16, a: __m512) -> __m512i { )) } -/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epu32&expand=2002) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_epu32&expand=1755) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2udq))] -pub unsafe fn _mm512_cvttps_epu32(a: __m512) -> __m512i { - transmute(vcvttps2udq( +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_cvtps_epu32(a: __m512) -> __m512i { + transmute(vcvtps2udq( a.as_f32x16(), - _mm512_setzero_si512().as_i32x16(), + _mm512_setzero_si512().as_u32x16(), 0b11111111_11111111, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epu32&expand=2003) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epu32&expand=1756) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2udq))] -pub unsafe fn _mm512_mask_cvttps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { - transmute(vcvttps2udq( +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_mask_cvtps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2udq( a.as_f32x16(), - src.as_i32x16(), + src.as_u32x16(), k, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epu32&expand=2004) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttps2udq))] -pub unsafe fn _mm512_maskz_cvttps_epu32(k: __mmask16, a: __m512) -> __m512i { - transmute(vcvttps2udq( +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_maskz_cvtps_epu32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2udq( a.as_f32x16(), - _mm512_setzero_si512().as_i32x16(), + _mm512_setzero_si512().as_u32x16(), k, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundpd_epu32&expand=1912) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_cvtt_roundpd_epu32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { - macro_rules! call { - ($imm4:expr) => { - vcvttpd2udq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) - }; - } - let r = constify_imm4_sae!(sae, call); - transmute(r) -} - -/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epi32&expand=1947) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_pd&expand=1769) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2dq))] -pub unsafe fn _mm512_cvttpd_epi32(a: __m512d) -> __m256i { - transmute(vcvttpd2dq( - a.as_f64x8(), - _mm256_setzero_si256().as_i32x8(), +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_cvtps_pd(a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), 0b11111111, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epi32&expand=1948) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_pd&expand=1770) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2dq))] -pub unsafe fn _mm512_mask_cvttpd_epi32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { - transmute(vcvttpd2dq( - a.as_f64x8(), - src.as_i32x8(), +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_mask_cvtps_pd(src: __m512d, k: __mmask8, a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + src.as_f64x8(), k, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epi32&expand=1949) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_pd&expand=1771) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2dq))] -pub unsafe fn _mm512_maskz_cvttpd_epi32(k: __mmask8, a: __m512d) -> __m256i { - transmute(vcvttpd2dq( - a.as_f64x8(), - _mm256_setzero_si256().as_i32x8(), +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_maskz_cvtps_pd(k: __mmask8, a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), k, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// Performs element-by-element conversion of the lower half of packed single-precision (32-bit) floating-point elements in v2 to packed double-precision (64-bit) floating-point elements, storing the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epu32&expand=1965) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtpslo_pd&expand=1784) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2udq))] -pub unsafe fn _mm512_cvttpd_epu32(a: __m512d) -> __m256i { - transmute(vcvttpd2udq( +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_cvtpslo_pd(v2: __m512) -> __m512d { + transmute(vcvtps2pd( + _mm512_castps512_ps256(v2).as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Performs element-by-element conversion of the lower half of packed single-precision (32-bit) floating-point elements in v2 to packed double-precision (64-bit) floating-point elements, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtpslo_pd&expand=1785) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_mask_cvtpslo_pd(src: __m512d, k: __mmask8, v2: __m512) -> __m512d { + transmute(vcvtps2pd( + _mm512_castps512_ps256(v2).as_f32x8(), + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtpd_ps&expand=1712) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtpd2ps))] +pub unsafe fn _mm512_cvtpd_ps(a: __m512d) -> __m256 { + transmute(vcvtpd2ps( a.as_f64x8(), - _mm256_setzero_si256().as_i32x8(), + _mm256_setzero_ps().as_f32x8(), 0b11111111, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epu32&expand=1966) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtpd_ps&expand=1713) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2udq))] -pub unsafe fn _mm512_mask_cvttpd_epu32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { - transmute(vcvttpd2udq( +#[cfg_attr(test, assert_instr(vcvtpd2ps))] +pub unsafe fn _mm512_mask_cvtpd_ps(src: __m256, k: __mmask8, a: __m512d) -> __m256 { + transmute(vcvtpd2ps( a.as_f64x8(), - src.as_i32x8(), + src.as_f32x8(), k, _MM_FROUND_CUR_DIRECTION, )) } -/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epu32&expand=1967) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtpd_ps&expand=1714) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcvttpd2udq))] -pub unsafe fn _mm512_maskz_cvttpd_epu32(k: __mmask8, a: __m512d) -> __m256i { - transmute(vcvttpd2udq( +#[cfg_attr(test, assert_instr(vcvtpd2ps))] +pub unsafe fn _mm512_maskz_cvtpd_ps(k: __mmask8, a: __m512d) -> __m256 { + transmute(vcvtpd2ps( a.as_f64x8(), - _mm256_setzero_si256().as_i32x8(), + _mm256_setzero_ps().as_f32x8(), k, _MM_FROUND_CUR_DIRECTION, )) } -/// Returns vector of type `__m512d` with all elements set to zero. +/// Performs an element-by-element conversion of packed double-precision (64-bit) floating-point elements in v2 to single-precision (32-bit) floating-point elements and stores them in dst. The elements are stored in the lower half of the results vector, while the remaining upper half locations are set to 0. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtpd_pslo&expand=1715) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vxorps))] -pub unsafe fn _mm512_setzero_pd() -> __m512d { - // All-0 is a properly initialized __m512d - mem::zeroed() +#[cfg_attr(test, assert_instr(vcvtpd2ps))] +pub unsafe fn _mm512_cvtpd_pslo(v2: __m512d) -> __m512 { + let r: f32x8 = vcvtpd2ps( + v2.as_f64x8(), + _mm256_setzero_ps().as_f32x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + ); + simd_shuffle16( + r, + _mm256_setzero_ps().as_f32x8(), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8], + ) } -/// Returns vector of type `__m512d` with all elements set to zero. +/// Performs an element-by-element conversion of packed double-precision (64-bit) floating-point elements in v2 to single-precision (32-bit) floating-point elements and stores them in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The elements are stored in the lower half of the results vector, while the remaining upper half locations are set to 0. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtpd_pslo&expand=1716) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vxorps))] -pub unsafe fn _mm512_setzero_ps() -> __m512 { - // All-0 is a properly initialized __m512 - mem::zeroed() +#[cfg_attr(test, assert_instr(vcvtpd2ps))] +pub unsafe fn _mm512_mask_cvtpd_pslo(src: __m512, k: __mmask8, v2: __m512d) -> __m512 { + let r: f32x8 = vcvtpd2ps( + v2.as_f64x8(), + _mm512_castps512_ps256(src).as_f32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + ); + simd_shuffle16( + r, + _mm256_setzero_ps().as_f32x8(), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8], + ) } -/// Returns vector of type `__m512i` with all elements set to zero. +/// Sign extend packed 8-bit integers in a to packed 32-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_si512) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi8_epi32&expand=1535) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vxorps))] -pub unsafe fn _mm512_setzero_si512() -> __m512i { - // All-0 is a properly initialized __m512i - mem::zeroed() +#[cfg_attr(test, assert_instr(vpmovsxbd))] +pub unsafe fn _mm512_cvtepi8_epi32(a: __m128i) -> __m512i { + let a = a.as_i8x16(); + transmute::(simd_cast(a)) } -/// Sets packed 32-bit integers in `dst` with the supplied values in reverse -/// order. +/// Sign extend packed 8-bit integers in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi8_epi32&expand=1536) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_setr_epi32( - e15: i32, - e14: i32, - e13: i32, - e12: i32, - e11: i32, - e10: i32, - e9: i32, - e8: i32, - e7: i32, - e6: i32, - e5: i32, - e4: i32, - e3: i32, - e2: i32, - e1: i32, - e0: i32, -) -> __m512i { - let r = i32x16( - e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, - ); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxbd))] +pub unsafe fn _mm512_mask_cvtepi8_epi32(src: __m512i, k: __mmask16, a: __m128i) -> __m512i { + let convert = _mm512_cvtepi8_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, convert, src.as_i32x16())) } -/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// Sign extend packed 8-bit integers in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi8_epi32&expand=1537) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_pd(offsets: __m256i, slice: *const u8, scale: i32) -> __m512d { - let zero = _mm512_setzero_pd().as_f64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherdpd(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxbd))] +pub unsafe fn _mm512_maskz_cvtepi8_epi32(k: __mmask16, a: __m128i) -> __m512i { + let convert = _mm512_cvtepi8_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// Sign extend packed 8-bit integers in the low 8 bytes of a to packed 64-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi8_epi64&expand=1544) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_pd( - src: __m512d, - mask: __mmask8, - offsets: __m256i, - slice: *const u8, - scale: i32, -) -> __m512d { - let src = src.as_f64x8(); - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherdpd(src, slice, offsets, mask as i8, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxbq))] +pub unsafe fn _mm512_cvtepi8_epi64(a: __m128i) -> __m512i { + let a = a.as_i8x16(); + let v64: i8x8 = simd_shuffle8(a, a, [0, 1, 2, 3, 4, 5, 6, 7]); + transmute::(simd_cast(v64)) } -/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. +/// Sign extend packed 8-bit integers in the low 8 bytes of a to packed 64-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi8_epi64&expand=1545) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_pd(offsets: __m512i, slice: *const u8, scale: i32) -> __m512d { - let zero = _mm512_setzero_pd().as_f64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqpd(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxbq))] +pub unsafe fn _mm512_mask_cvtepi8_epi64(src: __m512i, k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepi8_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, convert, src.as_i64x8())) } -/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. +/// Sign extend packed 8-bit integers in the low 8 bytes of a to packed 64-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi8_epi64&expand=1546) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_pd( - src: __m512d, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512d { - let src = src.as_f64x8(); - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqpd(src, slice, offsets, mask as i8, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxbq))] +pub unsafe fn _mm512_maskz_cvtepi8_epi64(k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepi8_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. +/// Zero extend packed unsigned 8-bit integers in a to packed 32-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu8_epi32&expand=1621) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m256 { - let zero = _mm256_setzero_ps().as_f32x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqps(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovzxbd))] +pub unsafe fn _mm512_cvtepu8_epi32(a: __m128i) -> __m512i { + let a = a.as_u8x16(); + transmute::(simd_cast(a)) } -/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. +/// Zero extend packed unsigned 8-bit integers in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu8_epi32&expand=1622) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_ps( - src: __m256, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m256 { - let src = src.as_f32x8(); - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vgatherqps(src, slice, offsets, mask as i8, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovzxbd))] +pub unsafe fn _mm512_mask_cvtepu8_epi32(src: __m512i, k: __mmask16, a: __m128i) -> __m512i { + let convert = _mm512_cvtepu8_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, convert, src.as_i32x16())) } -/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// Zero extend packed unsigned 8-bit integers in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepu8_epi32&expand=1623) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m512 { - let zero = _mm512_setzero_ps().as_f32x16(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vgatherdps(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovzxbd))] +pub unsafe fn _mm512_maskz_cvtepu8_epi32(k: __mmask16, a: __m128i) -> __m512i { + let convert = _mm512_cvtepu8_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// Zero extend packed unsigned 8-bit integers in the low 8 byte sof a to packed 64-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu8_epi64&expand=1630) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_ps( - src: __m512, - mask: __mmask16, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512 { - let src = src.as_f32x16(); - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vgatherdps(src, slice, offsets, mask as i16, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovzxbq))] +pub unsafe fn _mm512_cvtepu8_epi64(a: __m128i) -> __m512i { + let a = a.as_u8x16(); + let v64: u8x8 = simd_shuffle8(a, a, [0, 1, 2, 3, 4, 5, 6, 7]); + transmute::(simd_cast(v64)) } -/// Gather 32-bit integers from memory using 32-bit indices. +/// Zero extend packed unsigned 8-bit integers in the low 8 bytes of a to packed 64-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu8_epi64&expand=1631) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { - let zero = _mm512_setzero_si512().as_i32x16(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdd(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovzxbq))] +pub unsafe fn _mm512_mask_cvtepu8_epi64(src: __m512i, k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepu8_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, convert, src.as_i64x8())) } -/// Gather 32-bit integers from memory using 32-bit indices. +/// Zero extend packed unsigned 8-bit integers in the low 8 bytes of a to packed 64-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepu8_epi64&expand=1632) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_epi32( - src: __m512i, - mask: __mmask16, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512i { - let src = src.as_i32x16(); - let mask = mask as i16; - let slice = slice as *const i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdd(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovzxbq))] +pub unsafe fn _mm512_maskz_cvtepu8_epi64(k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepu8_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Gather 64-bit integers from memory using 32-bit indices. +/// Sign extend packed 16-bit integers in a to packed 32-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi16_epi32&expand=1389) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i32gather_epi64(offsets: __m256i, slice: *const u8, scale: i32) -> __m512i { - let zero = _mm512_setzero_si512().as_i64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdq(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxwd))] +pub unsafe fn _mm512_cvtepi16_epi32(a: __m256i) -> __m512i { + let a = a.as_i16x16(); + transmute::(simd_cast(a)) } -/// Gather 64-bit integers from memory using 32-bit indices. +/// Sign extend packed 16-bit integers in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi16_epi32&expand=1390) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32gather_epi64( - src: __m512i, - mask: __mmask8, - offsets: __m256i, - slice: *const u8, - scale: i32, -) -> __m512i { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *const i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherdq(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxwd))] +pub unsafe fn _mm512_mask_cvtepi16_epi32(src: __m512i, k: __mmask16, a: __m256i) -> __m512i { + let convert = _mm512_cvtepi16_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, convert, src.as_i32x16())) } -/// Gather 64-bit integers from memory using 64-bit indices. +/// Sign extend packed 16-bit integers in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi16_epi32&expand=1391) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_epi64(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { - let zero = _mm512_setzero_si512().as_i64x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqq(zero, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxwd))] +pub unsafe fn _mm512_maskz_cvtepi16_epi32(k: __mmask16, a: __m256i) -> __m512i { + let convert = _mm512_cvtepi16_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Gather 64-bit integers from memory using 64-bit indices. +/// Sign extend packed 16-bit integers in a to packed 64-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi16_epi64&expand=1398) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_epi64( - src: __m512i, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m512i { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqq(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxwq))] +pub unsafe fn _mm512_cvtepi16_epi64(a: __m128i) -> __m512i { + let a = a.as_i16x8(); + transmute::(simd_cast(a)) } -/// Gather 32-bit integers from memory using 64-bit indices. +/// Sign extend packed 16-bit integers in a to packed 64-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi16_epi64&expand=1399) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_i64gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m256i { - let zeros = _mm256_setzero_si256().as_i32x8(); - let neg_one = -1; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqd(zeros, slice, offsets, neg_one, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxwq))] +pub unsafe fn _mm512_mask_cvtepi16_epi64(src: __m512i, k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepi16_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, convert, src.as_i64x8())) } -/// Gather 32-bit integers from memory using 64-bit indices. +/// Sign extend packed 16-bit integers in a to packed 64-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi16_epi64&expand=1400) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64gather_epi32( - src: __m256i, - mask: __mmask8, - offsets: __m512i, - slice: *const u8, - scale: i32, -) -> __m256i { - let src = src.as_i32x8(); - let mask = mask as i8; - let slice = slice as *const i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpgatherqd(src, slice, offsets, mask, $imm8) - }; - } - let r = constify_imm8_gather!(scale, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovsxwq))] +pub unsafe fn _mm512_maskz_cvtepi16_epi64(k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepi16_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Scatter double-precision (64-bit) floating-point elements from memory using 32-bit indices. +/// Zero extend packed unsigned 16-bit integers in a to packed 32-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu16_epi32&expand=1553) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_pd(slice: *mut u8, offsets: __m256i, src: __m512d, scale: i32) { - let src = src.as_f64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterdpd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxwd))] +pub unsafe fn _mm512_cvtepu16_epi32(a: __m256i) -> __m512i { + let a = a.as_u16x16(); + transmute::(simd_cast(a)) } -/// Scatter double-precision (64-bit) floating-point elements from src into memory using 32-bit indices. +/// Zero extend packed unsigned 16-bit integers in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu16_epi32&expand=1554) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_pd( - slice: *mut u8, - mask: __mmask8, - offsets: __m256i, - src: __m512d, - scale: i32, -) { - let src = src.as_f64x8(); - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterdpd(slice, mask as i8, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxwd))] +pub unsafe fn _mm512_mask_cvtepu16_epi32(src: __m512i, k: __mmask16, a: __m256i) -> __m512i { + let convert = _mm512_cvtepu16_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, convert, src.as_i32x16())) } -/// Scatter double-precision (64-bit) floating-point elements from src into memory using 64-bit indices. +/// Zero extend packed unsigned 16-bit integers in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepu16_epi32&expand=1555) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_pd(slice: *mut u8, offsets: __m512i, src: __m512d, scale: i32) { - let src = src.as_f64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqpd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxwd))] +pub unsafe fn _mm512_maskz_cvtepu16_epi32(k: __mmask16, a: __m256i) -> __m512i { + let convert = _mm512_cvtepu16_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Scatter double-precision (64-bit) floating-point elements from src into memory using 64-bit indices. +/// Zero extend packed unsigned 16-bit integers in a to packed 64-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu16_epi64&expand=1562) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_pd( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m512d, - scale: i32, -) { - let src = src.as_f64x8(); - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqpd(slice, mask as i8, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxwq))] +pub unsafe fn _mm512_cvtepu16_epi64(a: __m128i) -> __m512i { + let a = a.as_u16x8(); + transmute::(simd_cast(a)) } -/// Scatter single-precision (32-bit) floating-point elements from memory using 32-bit indices. +/// Zero extend packed unsigned 16-bit integers in a to packed 64-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu16_epi64&expand=1563) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_ps(slice: *mut u8, offsets: __m512i, src: __m512, scale: i32) { - let src = src.as_f32x16(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vscatterdps(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxwq))] +pub unsafe fn _mm512_mask_cvtepu16_epi64(src: __m512i, k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepu16_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, convert, src.as_i64x8())) } -/// Scatter single-precision (32-bit) floating-point elements from src into memory using 32-bit indices. +/// Zero extend packed unsigned 16-bit integers in a to packed 64-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepu16_epi64&expand=1564) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_ps( - slice: *mut u8, - mask: __mmask16, - offsets: __m512i, - src: __m512, - scale: i32, -) { - let src = src.as_f32x16(); - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vscatterdps(slice, mask as i16, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxwq))] +pub unsafe fn _mm512_maskz_cvtepu16_epi64(k: __mmask8, a: __m128i) -> __m512i { + let convert = _mm512_cvtepu16_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Scatter single-precision (32-bit) floating-point elements from src into memory using 64-bit indices. +/// Sign extend packed 32-bit integers in a to packed 64-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi32_epi64&expand=1428) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_ps(slice: *mut u8, offsets: __m512i, src: __m256, scale: i32) { - let src = src.as_f32x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqps(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovsxdq))] +pub unsafe fn _mm512_cvtepi32_epi64(a: __m256i) -> __m512i { + let a = a.as_i32x8(); + transmute::(simd_cast(a)) } -/// Scatter single-precision (32-bit) floating-point elements from src into memory using 64-bit indices. +/// Sign extend packed 32-bit integers in a to packed 64-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi32_epi64&expand=1429) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_ps( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m256, - scale: i32, -) { - let src = src.as_f32x8(); - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vscatterqps(slice, mask as i8, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovsxdq))] +pub unsafe fn _mm512_mask_cvtepi32_epi64(src: __m512i, k: __mmask8, a: __m256i) -> __m512i { + let convert = _mm512_cvtepi32_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, convert, src.as_i64x8())) } -/// Scatter 64-bit integers from src into memory using 32-bit indices. +/// Sign extend packed 32-bit integers in a to packed 64-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi32_epi64&expand=1430) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_epi64(slice: *mut u8, offsets: __m256i, src: __m512i, scale: i32) { - let src = src.as_i64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdq(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovsxdq))] +pub unsafe fn _mm512_maskz_cvtepi32_epi64(k: __mmask8, a: __m256i) -> __m512i { + let convert = _mm512_cvtepi32_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Scatter 64-bit integers from src into memory using 32-bit indices. +/// Zero extend packed unsigned 32-bit integers in a to packed 64-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu32_epi64&expand=1571) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_epi64( - slice: *mut u8, - mask: __mmask8, - offsets: __m256i, - src: __m512i, - scale: i32, -) { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdq(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxdq))] +pub unsafe fn _mm512_cvtepu32_epi64(a: __m256i) -> __m512i { + let a = a.as_u32x8(); + transmute::(simd_cast(a)) } -/// Scatter 64-bit integers from src into memory using 64-bit indices. +/// Zero extend packed unsigned 32-bit integers in a to packed 64-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu32_epi64&expand=1572) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_epi64(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { - let src = src.as_i64x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqq(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxdq))] +pub unsafe fn _mm512_mask_cvtepu32_epi64(src: __m512i, k: __mmask8, a: __m256i) -> __m512i { + let convert = _mm512_cvtepu32_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, convert, src.as_i64x8())) } -/// Scatter 64-bit integers from src into memory using 64-bit indices. +/// Zero extend packed unsigned 32-bit integers in a to packed 64-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepu32_epi64&expand=1573) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_epi64( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m512i, - scale: i32, -) { - let src = src.as_i64x8(); - let mask = mask as i8; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqq(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vpmovzxdq))] +pub unsafe fn _mm512_maskz_cvtepu32_epi64(k: __mmask8, a: __m256i) -> __m512i { + let convert = _mm512_cvtepu32_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Scatter 32-bit integers from src into memory using 32-bit indices. +/// Convert packed signed 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi32_ps&expand=1455) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i32scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { - let src = src.as_i32x16(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vcvtdq2ps))] +pub unsafe fn _mm512_cvtepi32_ps(a: __m512i) -> __m512 { + let a = a.as_i32x16(); + transmute::(simd_cast(a)) } -/// Scatter 32-bit integers from src into memory using 32-bit indices. +/// Convert packed signed 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi32_ps&expand=1456) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i32scatter_epi32( - slice: *mut u8, - mask: __mmask16, - offsets: __m512i, - src: __m512i, - scale: i32, -) { - let src = src.as_i32x16(); - let mask = mask as i16; - let slice = slice as *mut i8; - let offsets = offsets.as_i32x16(); - macro_rules! call { - ($imm8:expr) => { - vpscatterdd(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vcvtdq2ps))] +pub unsafe fn _mm512_mask_cvtepi32_ps(src: __m512, k: __mmask16, a: __m512i) -> __m512 { + let convert = _mm512_cvtepi32_ps(a).as_f32x16(); + transmute(simd_select_bitmask(k, convert, src.as_f32x16())) } -/// Scatter 32-bit integers from src into memory using 64-bit indices. +/// Convert packed signed 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi32_ps&expand=1457) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_i64scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m256i, scale: i32) { - let src = src.as_i32x8(); - let neg_one = -1; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqd(slice, neg_one, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vcvtdq2ps))] +pub unsafe fn _mm512_maskz_cvtepi32_ps(k: __mmask16, a: __m512i) -> __m512 { + let convert = _mm512_cvtepi32_ps(a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Scatter 32-bit integers from src into memory using 64-bit indices. +/// Convert packed signed 32-bit integers in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi32_pd&expand=1446) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_i64scatter_epi32( - slice: *mut u8, - mask: __mmask8, - offsets: __m512i, - src: __m256i, - scale: i32, -) { - let src = src.as_i32x8(); - let mask = mask as i8; - let slice = slice as *mut i8; - let offsets = offsets.as_i64x8(); - macro_rules! call { - ($imm8:expr) => { - vpscatterqd(slice, mask, offsets, src, $imm8) - }; - } - constify_imm8_gather!(scale, call); +#[cfg_attr(test, assert_instr(vcvtdq2pd))] +pub unsafe fn _mm512_cvtepi32_pd(a: __m256i) -> __m512d { + let a = a.as_i32x8(); + transmute::(simd_cast(a)) } -/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// Convert packed signed 32-bit integers in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi32&expand=4685) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi32_pd&expand=1447) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_rol_epi32(a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprold(a.as_i32x16(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vcvtdq2pd))] +pub unsafe fn _mm512_mask_cvtepi32_pd(src: __m512d, k: __mmask8, a: __m256i) -> __m512d { + let convert = _mm512_cvtepi32_pd(a).as_f64x8(); + transmute(simd_select_bitmask(k, convert, src.as_f64x8())) } -/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed signed 32-bit integers in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi32&expand=4683) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi32_pd&expand=1448) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_rol_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprold(a.as_i32x16(), $imm8) - }; - } - let rol = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, rol, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtdq2pd))] +pub unsafe fn _mm512_maskz_cvtepi32_pd(k: __mmask8, a: __m256i) -> __m512d { + let convert = _mm512_cvtepi32_pd(a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi32&expand=4684) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu32_ps&expand=1583) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_rol_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprold(a.as_i32x16(), $imm8) - }; - } - let rol = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, rol, zero)) +#[cfg_attr(test, assert_instr(vcvtudq2ps))] +pub unsafe fn _mm512_cvtepu32_ps(a: __m512i) -> __m512 { + let a = a.as_u32x16(); + transmute::(simd_cast(a)) } -/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// Convert packed unsigned 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi32&expand=4721) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu32_ps&expand=1584) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_ror_epi32(a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprord(a.as_i32x16(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vcvtudq2ps))] +pub unsafe fn _mm512_mask_cvtepu32_ps(src: __m512, k: __mmask16, a: __m512i) -> __m512 { + let convert = _mm512_cvtepu32_ps(a).as_f32x16(); + transmute(simd_select_bitmask(k, convert, src.as_f32x16())) } -/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi32&expand=4719) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepu32_ps&expand=1585) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_ror_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprord(a.as_i32x16(), $imm8) - }; - } - let ror = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, ror, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtudq2ps))] +pub unsafe fn _mm512_maskz_cvtepu32_ps(k: __mmask16, a: __m512i) -> __m512 { + let convert = _mm512_cvtepu32_ps(a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi32&expand=4720) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu32_pd&expand=1580) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_ror_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprord(a.as_i32x16(), $imm8) - }; - } - let ror = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, ror, zero)) +#[cfg_attr(test, assert_instr(vcvtudq2pd))] +pub unsafe fn _mm512_cvtepu32_pd(a: __m256i) -> __m512d { + let a = a.as_u32x8(); + transmute::(simd_cast(a)) } -/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// Convert packed unsigned 32-bit integers in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi64&expand=4694) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu32_pd&expand=1581) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_rol_epi64(a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprolq(a.as_i64x8(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vcvtudq2pd))] +pub unsafe fn _mm512_mask_cvtepu32_pd(src: __m512d, k: __mmask8, a: __m256i) -> __m512d { + let convert = _mm512_cvtepu32_pd(a).as_f64x8(); + transmute(simd_select_bitmask(k, convert, src.as_f64x8())) } -/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi64&expand=4692) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepu32_pd&expand=1582) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_rol_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprolq(a.as_i64x8(), $imm8) - }; - } - let rol = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, rol, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtudq2pd))] +pub unsafe fn _mm512_maskz_cvtepu32_pd(k: __mmask8, a: __m256i) -> __m512d { + let convert = _mm512_cvtepu32_pd(a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Performs element-by-element conversion of the lower half of packed 32-bit integer elements in v2 to packed double-precision (64-bit) floating-point elements, storing the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi64&expand=4693) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi32lo_pd&expand=1464) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_rol_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprolq(a.as_i64x8(), $imm8) - }; - } - let rol = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, rol, zero)) +#[cfg_attr(test, assert_instr(vcvtdq2pd))] +pub unsafe fn _mm512_cvtepi32lo_pd(v2: __m512i) -> __m512d { + let v2 = v2.as_i32x16(); + let v256: i32x8 = simd_shuffle8(v2, v2, [0, 1, 2, 3, 4, 5, 6, 7]); + transmute::(simd_cast(v256)) } -/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// Performs element-by-element conversion of the lower half of packed 32-bit integer elements in v2 to packed double-precision (64-bit) floating-point elements, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi64&expand=4730) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi32lo_pd&expand=1465) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_ror_epi64(a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprorq(a.as_i64x8(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vcvtdq2pd))] +pub unsafe fn _mm512_mask_cvtepi32lo_pd(src: __m512d, k: __mmask8, v2: __m512i) -> __m512d { + let convert = _mm512_cvtepi32lo_pd(v2).as_f64x8(); + transmute(simd_select_bitmask(k, convert, src.as_f64x8())) } -/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Performs element-by-element conversion of the lower half of packed 32-bit unsigned integer elements in v2 to packed double-precision (64-bit) floating-point elements, storing the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi64&expand=4728) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepu32lo_pd&expand=1586) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_ror_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprorq(a.as_i64x8(), $imm8) - }; - } - let ror = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, ror, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtudq2pd))] +pub unsafe fn _mm512_cvtepu32lo_pd(v2: __m512i) -> __m512d { + let v2 = v2.as_u32x16(); + let v256: u32x8 = simd_shuffle8(v2, v2, [0, 1, 2, 3, 4, 5, 6, 7]); + transmute::(simd_cast(v256)) } -/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Performs element-by-element conversion of the lower half of 32-bit unsigned integer elements in v2 to packed double-precision (64-bit) floating-point elements, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi64&expand=4729) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepu32lo_pd&expand=1587) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_ror_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vprorq(a.as_i64x8(), $imm8) - }; - } - let ror = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, ror, zero)) +#[cfg_attr(test, assert_instr(vcvtudq2pd))] +pub unsafe fn _mm512_mask_cvtepu32lo_pd(src: __m512d, k: __mmask8, v2: __m512i) -> __m512d { + let convert = _mm512_cvtepu32lo_pd(v2).as_f64x8(); + transmute(simd_select_bitmask(k, convert, src.as_f64x8())) } -/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. +/// Convert packed 32-bit integers in a to packed 16-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi32&expand=5310) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi32_epi16&expand=1419) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_slli_epi32(a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsllid(a.as_i32x16(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovdw))] +pub unsafe fn _mm512_cvtepi32_epi16(a: __m512i) -> __m256i { + let a = a.as_i32x16(); + transmute::(simd_cast(a)) } -/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed 32-bit integers in a to packed 16-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi32&expand=5308) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi32_epi16&expand=1420) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_slli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsllid(a.as_i32x16(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovdw))] +pub unsafe fn _mm512_mask_cvtepi32_epi16(src: __m256i, k: __mmask16, a: __m512i) -> __m256i { + let convert = _mm512_cvtepi32_epi16(a).as_i16x16(); + transmute(simd_select_bitmask(k, convert, src.as_i16x16())) } -/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed 32-bit integers in a to packed 16-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi32&expand=5309) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi32_epi16&expand=1421) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_slli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsllid(a.as_i32x16(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovdw))] +pub unsafe fn _mm512_maskz_cvtepi32_epi16(k: __mmask16, a: __m512i) -> __m256i { + let convert = _mm512_cvtepi32_epi16(a).as_i16x16(); + let zero = _mm256_setzero_si256().as_i16x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. +/// Convert packed 32-bit integers in a to packed 8-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi32&expand=5522) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi32_epi8&expand=1437) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_srli_epi32(a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsrlid(a.as_i32x16(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovdb))] +pub unsafe fn _mm512_cvtepi32_epi8(a: __m512i) -> __m128i { + let a = a.as_i32x16(); + transmute::(simd_cast(a)) } -/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed 32-bit integers in a to packed 8-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi32&expand=5520) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi32_epi8&expand=1438) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_srli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsrlid(a.as_i32x16(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovdb))] +pub unsafe fn _mm512_mask_cvtepi32_epi8(src: __m128i, k: __mmask16, a: __m512i) -> __m128i { + let convert = _mm512_cvtepi32_epi8(a).as_i8x16(); + transmute(simd_select_bitmask(k, convert, src.as_i8x16())) } -/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed 32-bit integers in a to packed 8-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi32&expand=5521) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi32_epi8&expand=1439) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_srli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsrlid(a.as_i32x16(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovdb))] +pub unsafe fn _mm512_maskz_cvtepi32_epi8(k: __mmask16, a: __m512i) -> __m128i { + let convert = _mm512_cvtepi32_epi8(a).as_i8x16(); + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. +/// Convert packed 64-bit integers in a to packed 32-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi64&expand=5319) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi64_epi32&expand=1481) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_slli_epi64(a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpslliq(a.as_i64x8(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovqd))] +pub unsafe fn _mm512_cvtepi64_epi32(a: __m512i) -> __m256i { + let a = a.as_i64x8(); + transmute::(simd_cast(a)) } -/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed 64-bit integers in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi64&expand=5317) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi64_epi32&expand=1482) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_slli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpslliq(a.as_i64x8(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovqd))] +pub unsafe fn _mm512_mask_cvtepi64_epi32(src: __m256i, k: __mmask8, a: __m512i) -> __m256i { + let convert = _mm512_cvtepi64_epi32(a).as_i32x8(); + transmute(simd_select_bitmask(k, convert, src.as_i32x8())) } -/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed 64-bit integers in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi64&expand=5318) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi64_epi32&expand=1483) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_slli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpslliq(a.as_i64x8(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovqd))] +pub unsafe fn _mm512_maskz_cvtepi64_epi32(k: __mmask8, a: __m512i) -> __m256i { + let convert = _mm512_cvtepi64_epi32(a).as_i32x8(); + let zero = _mm256_setzero_si256().as_i32x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. +/// Convert packed 64-bit integers in a to packed 16-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi64&expand=5531) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi64_epi16&expand=1472) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_srli_epi64(a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsrliq(a.as_i64x8(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovqw))] +pub unsafe fn _mm512_cvtepi64_epi16(a: __m512i) -> __m128i { + let a = a.as_i64x8(); + transmute::(simd_cast(a)) } -/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed 64-bit integers in a to packed 16-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi64&expand=5529) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi64_epi16&expand=1473) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_srli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsrliq(a.as_i64x8(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovqw))] +pub unsafe fn _mm512_mask_cvtepi64_epi16(src: __m128i, k: __mmask8, a: __m512i) -> __m128i { + let convert = _mm512_cvtepi64_epi16(a).as_i16x8(); + transmute(simd_select_bitmask(k, convert, src.as_i16x8())) } -/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed 64-bit integers in a to packed 16-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi64&expand=5530) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi64_epi16&expand=1474) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_srli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsrliq(a.as_i64x8(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovqw))] +pub unsafe fn _mm512_maskz_cvtepi64_epi16(k: __mmask8, a: __m512i) -> __m128i { + let convert = _mm512_cvtepi64_epi16(a).as_i16x8(); + let zero = _mm_setzero_si128().as_i16x8(); + transmute(simd_select_bitmask(k, convert, zero)) } -/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst. +/// Convert packed 64-bit integers in a to packed 8-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi32&expand=5280) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtepi64_epi8&expand=1490) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpslld))] -pub unsafe fn _mm512_sll_epi32(a: __m512i, count: __m128i) -> __m512i { - transmute(vpslld(a.as_i32x16(), count.as_i32x4())) +#[cfg_attr(test, assert_instr(vpmovqb))] +pub unsafe fn _mm512_cvtepi64_epi8(a: __m512i) -> __m128i { + transmute(vpmovqb( + a.as_i64x8(), + _mm_setzero_si128().as_i8x16(), + 0b11111111, + )) } -/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed 64-bit integers in a to packed 8-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi32&expand=5278) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtepi64_epi8&expand=1491) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpslld))] -pub unsafe fn _mm512_mask_sll_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - count: __m128i, -) -> __m512i { - let shf = _mm512_sll_epi32(a, count).as_i32x16(); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovqb))] +pub unsafe fn _mm512_mask_cvtepi64_epi8(src: __m128i, k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovqb(a.as_i64x8(), src.as_i8x16(), k)) } -/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed 64-bit integers in a to packed 8-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi32&expand=5279) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtepi64_epi8&expand=1492) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpslld))] -pub unsafe fn _mm512_maskz_sll_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { - let shf = _mm512_sll_epi32(a, count).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovqb))] +pub unsafe fn _mm512_maskz_cvtepi64_epi8(k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovqb(a.as_i64x8(), _mm_setzero_si128().as_i8x16(), k)) } -/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst. +/// Convert packed signed 32-bit integers in a to packed 16-bit integers with signed saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi32&expand=5492) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtsepi32_epi16&expand=1819) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrld))] -pub unsafe fn _mm512_srl_epi32(a: __m512i, count: __m128i) -> __m512i { - transmute(vpsrld(a.as_i32x16(), count.as_i32x4())) +#[cfg_attr(test, assert_instr(vpmovsdw))] +pub unsafe fn _mm512_cvtsepi32_epi16(a: __m512i) -> __m256i { + transmute(vpmovsdw( + a.as_i32x16(), + _mm256_setzero_si256().as_i16x16(), + 0b11111111_11111111, + )) } -/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed signed 32-bit integers in a to packed 16-bit integers with signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi32&expand=5490) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtsepi32_epi16&expand=1820) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrld))] -pub unsafe fn _mm512_mask_srl_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - count: __m128i, -) -> __m512i { - let shf = _mm512_srl_epi32(a, count).as_i32x16(); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovsdw))] +pub unsafe fn _mm512_mask_cvtsepi32_epi16(src: __m256i, k: __mmask16, a: __m512i) -> __m256i { + transmute(vpmovsdw(a.as_i32x16(), src.as_i16x16(), k)) } -/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed signed 32-bit integers in a to packed 16-bit integers with signed saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srl_epi32&expand=5491) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtsepi32_epi16&expand=1819) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrld))] -pub unsafe fn _mm512_maskz_srl_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { - let shf = _mm512_srl_epi32(a, count).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovsdw))] +pub unsafe fn _mm512_maskz_cvtsepi32_epi16(k: __mmask16, a: __m512i) -> __m256i { + transmute(vpmovsdw( + a.as_i32x16(), + _mm256_setzero_si256().as_i16x16(), + k, + )) } -/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst. +/// Convert packed signed 32-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi64&expand=5289) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtsepi32_epi8&expand=1828) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllq))] -pub unsafe fn _mm512_sll_epi64(a: __m512i, count: __m128i) -> __m512i { - transmute(vpsllq(a.as_i64x8(), count.as_i64x2())) +#[cfg_attr(test, assert_instr(vpmovsdb))] +pub unsafe fn _mm512_cvtsepi32_epi8(a: __m512i) -> __m128i { + transmute(vpmovsdb( + a.as_i32x16(), + _mm_setzero_si128().as_i8x16(), + 0b11111111_11111111, + )) } -/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed signed 32-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi64&expand=5287) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtsepi32_epi8&expand=1829) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllq))] -pub unsafe fn _mm512_mask_sll_epi64( - src: __m512i, - k: __mmask8, - a: __m512i, - count: __m128i, -) -> __m512i { - let shf = _mm512_sll_epi64(a, count).as_i64x8(); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovsdb))] +pub unsafe fn _mm512_mask_cvtsepi32_epi8(src: __m128i, k: __mmask16, a: __m512i) -> __m128i { + transmute(vpmovsdb(a.as_i32x16(), src.as_i8x16(), k)) } -/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed signed 32-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtsepi32_epi8&expand=1830) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllq))] -pub unsafe fn _mm512_maskz_sll_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { - let shf = _mm512_sll_epi64(a, count).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovsdb))] +pub unsafe fn _mm512_maskz_cvtsepi32_epi8(k: __mmask16, a: __m512i) -> __m128i { + transmute(vpmovsdb(a.as_i32x16(), _mm_setzero_si128().as_i8x16(), k)) } -/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst. +/// Convert packed signed 64-bit integers in a to packed 32-bit integers with signed saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi64&expand=5501) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtsepi64_epi32&expand=1852) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlq))] -pub unsafe fn _mm512_srl_epi64(a: __m512i, count: __m128i) -> __m512i { - transmute(vpsrlq(a.as_i64x8(), count.as_i64x2())) +#[cfg_attr(test, assert_instr(vpmovsqd))] +pub unsafe fn _mm512_cvtsepi64_epi32(a: __m512i) -> __m256i { + transmute(vpmovsqd( + a.as_i64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + )) } -/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed signed 64-bit integers in a to packed 32-bit integers with signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi64&expand=5499) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtsepi64_epi32&expand=1853) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlq))] -pub unsafe fn _mm512_mask_srl_epi64( - src: __m512i, - k: __mmask8, - a: __m512i, - count: __m128i, -) -> __m512i { - let shf = _mm512_srl_epi64(a, count).as_i64x8(); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovsqd))] +pub unsafe fn _mm512_mask_cvtsepi64_epi32(src: __m256i, k: __mmask8, a: __m512i) -> __m256i { + transmute(vpmovsqd(a.as_i64x8(), src.as_i32x8(), k)) } -/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed signed 64-bit integers in a to packed 32-bit integers with signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtsepi64_epi32&expand=1854) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlq))] -pub unsafe fn _mm512_maskz_srl_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { - let shf = _mm512_srl_epi64(a, count).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovsqd))] +pub unsafe fn _mm512_maskz_cvtsepi64_epi32(k: __mmask8, a: __m512i) -> __m256i { + transmute(vpmovsqd(a.as_i64x8(), _mm256_setzero_si256().as_i32x8(), k)) } -/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst. +/// Convert packed signed 64-bit integers in a to packed 16-bit integers with signed saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi32&expand=5407) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtsepi64_epi16&expand=1843) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrad))] -pub unsafe fn _mm512_sra_epi32(a: __m512i, count: __m128i) -> __m512i { - transmute(vpsrad(a.as_i32x16(), count.as_i32x4())) -} +#[cfg_attr(test, assert_instr(vpmovsqw))] +pub unsafe fn _mm512_cvtsepi64_epi16(a: __m512i) -> __m128i { + transmute(vpmovsqw( + a.as_i64x8(), + _mm_setzero_si128().as_i16x8(), + 0b11111111, + )) +} -/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed signed 64-bit integers in a to packed 16-bit integers with signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi32&expand=5405) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtsepi64_epi16&expand=1844) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrad))] -pub unsafe fn _mm512_mask_sra_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - count: __m128i, -) -> __m512i { - let shf = _mm512_sra_epi32(a, count).as_i32x16(); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovsqw))] +pub unsafe fn _mm512_mask_cvtsepi64_epi16(src: __m128i, k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovsqw(a.as_i64x8(), src.as_i16x8(), k)) } -/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed signed 64-bit integers in a to packed 16-bit integers with signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi32&expand=5406) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtsepi64_epi16&expand=1845) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrad))] -pub unsafe fn _mm512_maskz_sra_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { - let shf = _mm512_sra_epi32(a, count).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovsqw))] +pub unsafe fn _mm512_maskz_cvtsepi64_epi16(k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovsqw(a.as_i64x8(), _mm_setzero_si128().as_i16x8(), k)) } -/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst. +/// Convert packed signed 64-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi64&expand=5416) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtsepi64_epi8&expand=1861) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsraq))] -pub unsafe fn _mm512_sra_epi64(a: __m512i, count: __m128i) -> __m512i { - transmute(vpsraq(a.as_i64x8(), count.as_i64x2())) +#[cfg_attr(test, assert_instr(vpmovsqb))] +pub unsafe fn _mm512_cvtsepi64_epi8(a: __m512i) -> __m128i { + transmute(vpmovsqb( + a.as_i64x8(), + _mm_setzero_si128().as_i8x16(), + 0b11111111, + )) } -/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed signed 64-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi64&expand=5414) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtsepi64_epi8&expand=1862) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsraq))] -pub unsafe fn _mm512_mask_sra_epi64( - src: __m512i, - k: __mmask8, - a: __m512i, - count: __m128i, -) -> __m512i { - let shf = _mm512_sra_epi64(a, count).as_i64x8(); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovsqb))] +pub unsafe fn _mm512_mask_cvtsepi64_epi8(src: __m128i, k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovsqb(a.as_i64x8(), src.as_i8x16(), k)) } -/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed signed 64-bit integers in a to packed 8-bit integers with signed saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi64&expand=5415) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtsepi64_epi8&expand=1863) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsraq))] -pub unsafe fn _mm512_maskz_sra_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { - let shf = _mm512_sra_epi64(a, count).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovsqb))] +pub unsafe fn _mm512_maskz_cvtsepi64_epi8(k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovsqb(a.as_i64x8(), _mm_setzero_si128().as_i8x16(), k)) } -/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. +/// Convert packed unsigned 32-bit integers in a to packed unsigned 16-bit integers with unsigned saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi32&expand=5436) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtusepi32_epi16&expand=2054) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_srai_epi32(a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsraid(a.as_i32x16(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovusdw))] +pub unsafe fn _mm512_cvtusepi32_epi16(a: __m512i) -> __m256i { + transmute(vpmovusdw( + a.as_u32x16(), + _mm256_setzero_si256().as_u16x16(), + 0b11111111_11111111, + )) } -/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed unsigned 16-bit integers with unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi32&expand=5434) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtusepi32_epi16&expand=2055) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_srai_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsraid(a.as_i32x16(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovusdw))] +pub unsafe fn _mm512_mask_cvtusepi32_epi16(src: __m256i, k: __mmask16, a: __m512i) -> __m256i { + transmute(vpmovusdw(a.as_u32x16(), src.as_u16x16(), k)) } -/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed unsigned 16-bit integers with unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi32&expand=5435) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtusepi32_epi16&expand=2056) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_srai_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsraid(a.as_i32x16(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovusdw))] +pub unsafe fn _mm512_maskz_cvtusepi32_epi16(k: __mmask16, a: __m512i) -> __m256i { + transmute(vpmovusdw( + a.as_u32x16(), + _mm256_setzero_si256().as_u16x16(), + k, + )) } -/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. +/// Convert packed unsigned 32-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi64&expand=5445) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtusepi32_epi8&expand=2063) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_srai_epi64(a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsraiq(a.as_i64x8(), $imm8) - }; - } - let r = constify_imm8_sae!(imm8, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpmovusdb))] +pub unsafe fn _mm512_cvtusepi32_epi8(a: __m512i) -> __m128i { + transmute(vpmovusdb( + a.as_u32x16(), + _mm_setzero_si128().as_u8x16(), + 0b11111111_11111111, + )) } -/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi64&expand=5443) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtusepi32_epi8&expand=2064) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_srai_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsraiq(a.as_i64x8(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovusdb))] +pub unsafe fn _mm512_mask_cvtusepi32_epi8(src: __m128i, k: __mmask16, a: __m512i) -> __m128i { + transmute(vpmovusdb(a.as_u32x16(), src.as_u8x16(), k)) } -/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi64&expand=5444) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtusepi32_epi8&expand=2065) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_srai_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { - macro_rules! call { - ($imm8:expr) => { - vpsraiq(a.as_i64x8(), $imm8) - }; - } - let shf = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovusdb))] +pub unsafe fn _mm512_maskz_cvtusepi32_epi8(k: __mmask16, a: __m512i) -> __m128i { + transmute(vpmovusdb(a.as_u32x16(), _mm_setzero_si128().as_u8x16(), k)) } -/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// Convert packed unsigned 64-bit integers in a to packed unsigned 32-bit integers with unsigned saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi32&expand=5465) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtusepi64_epi32&expand=2087) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsravd))] -pub unsafe fn _mm512_srav_epi32(a: __m512i, count: __m512i) -> __m512i { - transmute(vpsravd(a.as_i32x16(), count.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovusqd))] +pub unsafe fn _mm512_cvtusepi64_epi32(a: __m512i) -> __m256i { + transmute(vpmovusqd( + a.as_u64x8(), + _mm256_setzero_si256().as_u32x8(), + 0b11111111, + )) } -/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 64-bit integers in a to packed unsigned 32-bit integers with unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi32&expand=5463) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtusepi64_epi32&expand=2088) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsravd))] -pub unsafe fn _mm512_mask_srav_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - count: __m512i, -) -> __m512i { - let shf = _mm512_srav_epi32(a, count).as_i32x16(); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovusqd))] +pub unsafe fn _mm512_mask_cvtusepi64_epi32(src: __m256i, k: __mmask8, a: __m512i) -> __m256i { + transmute(vpmovusqd(a.as_u64x8(), src.as_u32x8(), k)) } -/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 64-bit integers in a to packed unsigned 32-bit integers with unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi32&expand=5464) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtusepi64_epi32&expand=2089) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsravd))] -pub unsafe fn _mm512_maskz_srav_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { - let shf = _mm512_srav_epi32(a, count).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovusqd))] +pub unsafe fn _mm512_maskz_cvtusepi64_epi32(k: __mmask8, a: __m512i) -> __m256i { + transmute(vpmovusqd( + a.as_u64x8(), + _mm256_setzero_si256().as_u32x8(), + k, + )) } -/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// Convert packed unsigned 64-bit integers in a to packed unsigned 16-bit integers with unsigned saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi64&expand=5474) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtusepi64_epi16&expand=2078) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsravq))] -pub unsafe fn _mm512_srav_epi64(a: __m512i, count: __m512i) -> __m512i { - transmute(vpsravq(a.as_i64x8(), count.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovusqw))] +pub unsafe fn _mm512_cvtusepi64_epi16(a: __m512i) -> __m128i { + transmute(vpmovusqw( + a.as_u64x8(), + _mm_setzero_si128().as_u16x8(), + 0b11111111, + )) } -/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 64-bit integers in a to packed unsigned 16-bit integers with unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi64&expand=5472) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtusepi64_epi16&expand=2079) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsravq))] -pub unsafe fn _mm512_mask_srav_epi64( - src: __m512i, - k: __mmask8, - a: __m512i, - count: __m512i, -) -> __m512i { - let shf = _mm512_srav_epi64(a, count).as_i64x8(); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpmovusqw))] +pub unsafe fn _mm512_mask_cvtusepi64_epi16(src: __m128i, k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovusqw(a.as_u64x8(), src.as_u16x8(), k)) } -/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 64-bit integers in a to packed unsigned 16-bit integers with unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi64&expand=5473) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtusepi64_epi16&expand=2080) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsravq))] -pub unsafe fn _mm512_maskz_srav_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { - let shf = _mm512_srav_epi64(a, count).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vpmovusqw))] +pub unsafe fn _mm512_maskz_cvtusepi64_epi16(k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovusqw(a.as_u64x8(), _mm_setzero_si128().as_u16x8(), k)) } -/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. +/// Convert packed unsigned 64-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi32&expand=4703) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtusepi64_epi8&expand=2096) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolvd))] -pub unsafe fn _mm512_rolv_epi32(a: __m512i, b: __m512i) -> __m512i { - transmute(vprolvd(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovusqb))] +pub unsafe fn _mm512_cvtusepi64_epi8(a: __m512i) -> __m128i { + transmute(vpmovusqb( + a.as_u64x8(), + _mm_setzero_si128().as_u8x16(), + 0b11111111, + )) } -/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 64-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi32&expand=4701) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtusepi64_epi8&expand=2097) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolvd))] -pub unsafe fn _mm512_mask_rolv_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - b: __m512i, -) -> __m512i { - let rol = _mm512_rolv_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, rol, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpmovusqb))] +pub unsafe fn _mm512_mask_cvtusepi64_epi8(src: __m128i, k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovusqb(a.as_u64x8(), src.as_u8x16(), k)) } -/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 64-bit integers in a to packed unsigned 8-bit integers with unsigned saturation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi32&expand=4702) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtusepi64_epi8&expand=2098) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolvd))] -pub unsafe fn _mm512_maskz_rolv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let rol = _mm512_rolv_epi32(a, b).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, rol, zero)) +#[cfg_attr(test, assert_instr(vpmovusqb))] +pub unsafe fn _mm512_maskz_cvtusepi64_epi8(k: __mmask8, a: __m512i) -> __m128i { + transmute(vpmovusqb(a.as_u64x8(), _mm_setzero_si128().as_u8x16(), k)) } -/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi32&expand=4739) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epi32&expand=1335) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprorvd))] -pub unsafe fn _mm512_rorv_epi32(a: __m512i, b: __m512i) -> __m512i { - transmute(vprorvd(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_epi32(a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi32&expand=4737) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprorvd))] -pub unsafe fn _mm512_mask_rorv_epi32( +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_epi32( src: __m512i, k: __mmask16, - a: __m512i, - b: __m512i, + a: __m512, + rounding: i32, ) -> __m512i { - let ror = _mm512_rorv_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, ror, src.as_i32x16())) + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi32&expand=4738) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprorvd))] -pub unsafe fn _mm512_maskz_rorv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let ror = _mm512_rorv_epi32(a, b).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, ror, zero)) +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_epi32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi64&expand=4712) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epu32&expand=1341) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolvq))] -pub unsafe fn _mm512_rolv_epi64(a: __m512i, b: __m512i) -> __m512i { - transmute(vprolvq(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_epu32(a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_u32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi64&expand=4710) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epu32&expand=1342) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolvq))] -pub unsafe fn _mm512_mask_rolv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let rol = _mm512_rolv_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, rol, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_epu32( + src: __m512i, + k: __mmask16, + a: __m512, + rounding: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq(a.as_f32x16(), src.as_u32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi64&expand=4711) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprolvq))] -pub unsafe fn _mm512_maskz_rolv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let rol = _mm512_rolv_epi64(a, b).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, rol, zero)) +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_epu32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq(a.as_f32x16(), _mm512_setzero_si512().as_u32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi64&expand=4748) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvt_roundps_pd&expand=1347) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprorvq))] -pub unsafe fn _mm512_rorv_epi64(a: __m512i, b: __m512i) -> __m512i { - transmute(vprorvq(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_pd(a: __m256, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi64&expand=4746) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprorvq))] -pub unsafe fn _mm512_mask_rorv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let ror = _mm512_rorv_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, ror, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_pd( + src: __m512d, + k: __mmask8, + a: __m256, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd(a.as_f32x8(), src.as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi64&expand=4747) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vprorvq))] -pub unsafe fn _mm512_maskz_rorv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let ror = _mm512_rorv_epi64(a, b).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, ror, zero)) +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_pd(k: __mmask8, a: __m256, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd(a.as_f32x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi32&expand=5342) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundpd_epi32&expand=1315) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllvd))] -pub unsafe fn _mm512_sllv_epi32(a: __m512i, count: __m512i) -> __m512i { - transmute(vpsllvd(a.as_i32x16(), count.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtpd2dq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundpd_epi32(a: __m512d, rounding: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi32&expand=5340) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundpd_epi32&expand=1316) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllvd))] -pub unsafe fn _mm512_mask_sllv_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - count: __m512i, -) -> __m512i { - let shf = _mm512_sllv_epi32(a, count).as_i32x16(); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtpd2dq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundpd_epi32( + src: __m256i, + k: __mmask8, + a: __m512d, + rounding: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2dq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi32&expand=5341) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/IntrinsicsGuide/#text=512_maskz_cvt_roundpd_epi32&expand=1317) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllvd))] -pub unsafe fn _mm512_maskz_sllv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { - let shf = _mm512_sllv_epi32(a, count).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vcvtpd2dq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundpd_epi32(k: __mmask8, a: __m512d, rounding: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2dq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi32&expand=5554) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundpd_epu32&expand=1321) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlvd))] -pub unsafe fn _mm512_srlv_epi32(a: __m512i, count: __m512i) -> __m512i { - transmute(vpsrlvd(a.as_i32x16(), count.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtpd2udq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundpd_epu32(a: __m512d, rounding: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_u32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srlv_epi32&expand=5552) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundpd_epu32&expand=1322) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlvd))] -pub unsafe fn _mm512_mask_srlv_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - count: __m512i, -) -> __m512i { - let shf = _mm512_srlv_epi32(a, count).as_i32x16(); - transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtpd2udq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundpd_epu32( + src: __m256i, + k: __mmask8, + a: __m512d, + rounding: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2udq(a.as_f64x8(), src.as_u32x8(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi32&expand=5553) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/IntrinsicsGuide/#text=512_maskz_cvt_roundpd_epu32&expand=1323) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlvd))] -pub unsafe fn _mm512_maskz_srlv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { - let shf = _mm512_srlv_epi32(a, count).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shf, zero)) -} - -/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi64&expand=5351) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllvq))] -pub unsafe fn _mm512_sllv_epi64(a: __m512i, count: __m512i) -> __m512i { - transmute(vpsllvq(a.as_i64x8(), count.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtpd2udq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundpd_epu32(k: __mmask8, a: __m512d, rounding: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2udq(a.as_f64x8(), _mm256_setzero_si256().as_u32x8(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi64&expand=5349) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllvq))] -pub unsafe fn _mm512_mask_sllv_epi64( - src: __m512i, - k: __mmask8, - a: __m512i, - count: __m512i, -) -> __m512i { - let shf = _mm512_sllv_epi64(a, count).as_i64x8(); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) -} - -/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi64&expand=5350) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundpd_ps&expand=1327) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsllvq))] -pub unsafe fn _mm512_maskz_sllv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { - let shf = _mm512_sllv_epi64(a, count).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vcvtpd2ps, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundpd_ps(a: __m512d, rounding: i32) -> __m256 { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2ps( + a.as_f64x8(), + _mm256_setzero_ps().as_f32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// Convert packed double-precision (64-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi64&expand=5563) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlvq))] -pub unsafe fn _mm512_srlv_epi64(a: __m512i, count: __m512i) -> __m512i { - transmute(vpsrlvq(a.as_i64x8(), count.as_i64x8())) -} - -/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mask_srlv_epi64&expand=5561) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundpd_ps&expand=1328) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlvq))] -pub unsafe fn _mm512_mask_srlv_epi64( - src: __m512i, +#[cfg_attr(test, assert_instr(vcvtpd2ps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundpd_ps( + src: __m256, k: __mmask8, - a: __m512i, - count: __m512i, -) -> __m512i { - let shf = _mm512_srlv_epi64(a, count).as_i64x8(); - transmute(simd_select_bitmask(k, shf, src.as_i64x8())) + a: __m512d, + rounding: i32, +) -> __m256 { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2ps(a.as_f64x8(), src.as_f32x8(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi64&expand=5562) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundpd_ps&expand=1329) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpsrlvq))] -pub unsafe fn _mm512_maskz_srlv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { - let shf = _mm512_srlv_epi64(a, count).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shf, zero)) +#[cfg_attr(test, assert_instr(vcvtpd2ps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundpd_ps(k: __mmask8, a: __m512d, rounding: i32) -> __m256 { + macro_rules! call { + ($imm4:expr) => { + vcvtpd2ps(a.as_f64x8(), _mm256_setzero_ps().as_f32x8(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// Convert packed signed 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_ps&expand=4170) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundepi32_ps&expand=1294) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[cfg_attr(test, assert_instr(vcvtdq2ps, rounding = 8))] #[rustc_args_required_const(1)] -pub unsafe fn _mm512_permute_ps(a: __m512, imm8: i32) -> __m512 { +pub unsafe fn _mm512_cvt_roundepi32_ps(a: __m512i, rounding: i32) -> __m512 { macro_rules! call { - ($imm8:expr) => { - vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + ($imm4:expr) => { + vcvtdq2ps(a.as_i32x16(), $imm4) }; } - let r = constify_imm8_sae!(imm8, call); + let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed signed 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_ps&expand=4168) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundepi32_ps&expand=1295) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[cfg_attr(test, assert_instr(vcvtdq2ps, rounding = 8))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_permute_ps(src: __m512, k: __mmask16, a: __m512, imm8: i32) -> __m512 { +pub unsafe fn _mm512_mask_cvt_roundepi32_ps( + src: __m512, + k: __mmask16, + a: __m512i, + rounding: i32, +) -> __m512 { macro_rules! call { - ($imm8:expr) => { - vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + ($imm4:expr) => { + vcvtdq2ps(a.as_i32x16(), $imm4) }; } - let permute = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, permute, src.as_f32x16())) + let r: f32x16 = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, r, src.as_f32x16())) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed signed 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_ps&expand=4169) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundepi32_ps&expand=1296) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[cfg_attr(test, assert_instr(vcvtdq2ps, rounding = 8))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_permute_ps(k: __mmask16, a: __m512, imm8: i32) -> __m512 { +pub unsafe fn _mm512_maskz_cvt_roundepi32_ps(k: __mmask16, a: __m512i, rounding: i32) -> __m512 { macro_rules! call { - ($imm8:expr) => { - vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + ($imm4:expr) => { + vcvtdq2ps(a.as_i32x16(), $imm4) }; } - let permute = constify_imm8_sae!(imm8, call); + let r = constify_imm4_round!(rounding, call); let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, permute, zero)) + transmute(simd_select_bitmask(k, r, zero)) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// Convert packed unsigned 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst.\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_pd&expand=4161) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundepu32_ps&expand=1303) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[cfg_attr(test, assert_instr(vcvtudq2ps, rounding = 8))] #[rustc_args_required_const(1)] -pub unsafe fn _mm512_permute_pd(a: __m512d, imm8: i32) -> __m512d { +pub unsafe fn _mm512_cvt_roundepu32_ps(a: __m512i, rounding: i32) -> __m512 { macro_rules! call { - ($imm8:expr) => { - vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtudq2ps(a.as_u32x16(), $imm4) }; } - let r = constify_imm8_sae!(imm8, call); + let r = constify_imm4_round!(rounding, call); transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_pd&expand=4159) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundepu32_ps&expand=1304) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[cfg_attr(test, assert_instr(vcvtudq2ps, rounding = 8))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_permute_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { +pub unsafe fn _mm512_mask_cvt_roundepu32_ps( + src: __m512, + k: __mmask16, + a: __m512i, + rounding: i32, +) -> __m512 { macro_rules! call { - ($imm8:expr) => { - vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtudq2ps(a.as_u32x16(), $imm4) }; } - let permute = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, permute, src.as_f64x8())) + let r: f32x16 = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, r, src.as_f32x16())) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed unsigned 32-bit integers in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_pd&expand=4160) +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundepu32_ps&expand=1305) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[cfg_attr(test, assert_instr(vcvtudq2ps, rounding = 8))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_permute_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { +pub unsafe fn _mm512_maskz_cvt_roundepu32_ps(k: __mmask16, a: __m512i, rounding: i32) -> __m512 { macro_rules! call { - ($imm8:expr) => { - vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtudq2ps(a.as_u32x16(), $imm4) }; } - let permute = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, permute, zero)) + let r = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, r, zero)) } -/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_epi64&expand=4208) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed half-precision (16-bit) floating-point elements, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_ph&expand=1354) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] -//shoud be vpermq, but generate vpermpd. It generates vpermq with mask. change to vbroadcast becaise CI Windows +#[cfg_attr(test, assert_instr(vcvtps2ph, sae = 8))] #[rustc_args_required_const(1)] -pub unsafe fn _mm512_permutex_epi64(a: __m512i, imm8: i32) -> __m512i { +pub unsafe fn _mm512_cvt_roundps_ph(a: __m512, sae: i32) -> __m256i { macro_rules! call { - ($imm8:expr) => { - vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtps2ph( + a.as_f32x16(), + $imm4, + _mm256_setzero_si256().as_i16x16(), + 0b11111111_11111111, + ) }; } - let r = constify_imm8_sae!(imm8, call); + let r = constify_imm4_sae!(sae, call); transmute(r) } -/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_epi64&expand=4206) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed half-precision (16-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_ph&expand=1355) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[cfg_attr(test, assert_instr(vcvtps2ph, sae = 8))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_permutex_epi64( - src: __m512i, - k: __mmask8, - a: __m512i, - imm8: i32, -) -> __m512i { +pub unsafe fn _mm512_mask_cvt_roundps_ph( + src: __m256i, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m256i { macro_rules! call { - ($imm8:expr) => { - vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtps2ph(a.as_f32x16(), $imm4, src.as_i16x16(), k) }; } - let permute = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, permute, src.as_i64x8())) + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_epi64&expand=4207) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed half-precision (16-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_ph&expand=1356) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[cfg_attr(test, assert_instr(vcvtps2ph, sae = 8))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_permutex_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { +pub unsafe fn _mm512_maskz_cvt_roundps_ph(k: __mmask16, a: __m512, sae: i32) -> __m256i { macro_rules! call { - ($imm8:expr) => { - vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtps2ph(a.as_f32x16(), $imm4, _mm256_setzero_si256().as_i16x16(), k) }; } - let permute = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, permute, zero)) + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_pd&expand=4214) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed half-precision (16-bit) floating-point elements, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_ph&expand=1778) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[cfg_attr(test, assert_instr(vcvtps2ph, sae = 8))] #[rustc_args_required_const(1)] -pub unsafe fn _mm512_permutex_pd(a: __m512d, imm8: i32) -> __m512d { +pub unsafe fn _mm512_cvtps_ph(a: __m512, sae: i32) -> __m256i { macro_rules! call { - ($imm8:expr) => { - vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtps2ph( + a.as_f32x16(), + $imm4, + _mm256_setzero_si256().as_i16x16(), + 0b11111111_11111111, + ) }; } - let r = constify_imm8_sae!(imm8, call); + let r = constify_imm4_sae!(sae, call); transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_pd&expand=4212) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed half-precision (16-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_ph&expand=1779) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[cfg_attr(test, assert_instr(vcvtps2ph, sae = 8))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_permutex_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { +pub unsafe fn _mm512_mask_cvtps_ph(src: __m256i, k: __mmask16, a: __m512, sae: i32) -> __m256i { macro_rules! call { - ($imm8:expr) => { - vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtps2ph(a.as_f32x16(), $imm4, src.as_i16x16(), k) }; } - let permute = constify_imm8_sae!(imm8, call); - transmute(simd_select_bitmask(k, permute, src.as_f64x8())) + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_pd&expand=4213) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed half-precision (16-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_ph&expand=1780) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[cfg_attr(test, assert_instr(vcvtps2ph, sae = 8))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_permutex_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { +pub unsafe fn _mm512_maskz_cvtps_ph(k: __mmask16, a: __m512, sae: i32) -> __m256i { macro_rules! call { - ($imm8:expr) => { - vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + ($imm4:expr) => { + vcvtps2ph(a.as_f32x16(), $imm4, _mm256_setzero_si256().as_i16x16(), k) }; } - let permute = constify_imm8_sae!(imm8, call); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, permute, zero)) -} - -/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_permutexvar_epi32, and it is recommended that you use that intrinsic name. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_epi32&expand=4182) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask -pub unsafe fn _mm512_permutevar_epi32(idx: __m512i, a: __m512i) -> __m512i { - transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) -} - -/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_mask_permutexvar_epi32, and it is recommended that you use that intrinsic name. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_epi32&expand=4181) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermd))] -pub unsafe fn _mm512_mask_permutevar_epi32( - src: __m512i, - k: __mmask16, - idx: __m512i, - a: __m512i, -) -> __m512i { - let permute = _mm512_permutevar_epi32(idx, a).as_i32x16(); - transmute(simd_select_bitmask(k, permute, src.as_i32x16())) + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) +/// Convert packed half-precision (16-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundph_ps&expand=1332) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilps))] -pub unsafe fn _mm512_permutevar_ps(a: __m512, b: __m512i) -> __m512 { - transmute(vpermilps(a.as_f32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvtph2ps, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundph_ps(a: __m256i, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vcvtph2ps( + a.as_i16x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_ps&expand=4198) +/// Convert packed half-precision (16-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundph_ps&expand=1333) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilps))] -pub unsafe fn _mm512_mask_permutevar_ps( +#[cfg_attr(test, assert_instr(vcvtph2ps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundph_ps( src: __m512, k: __mmask16, - a: __m512, - b: __m512i, + a: __m256i, + sae: i32, ) -> __m512 { - let permute = _mm512_permutevar_ps(a, b).as_f32x16(); - transmute(simd_select_bitmask(k, permute, src.as_f32x16())) + macro_rules! call { + ($imm4:expr) => { + vcvtph2ps(a.as_i16x16(), src.as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_ps&expand=4199) +/// Convert packed half-precision (16-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundph_ps&expand=1334) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilps))] -pub unsafe fn _mm512_maskz_permutevar_ps(k: __mmask16, a: __m512, b: __m512i) -> __m512 { - let permute = _mm512_permutevar_ps(a, b).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvtph2ps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundph_ps(k: __mmask16, a: __m256i, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vcvtph2ps(a.as_i16x16(), _mm512_setzero_ps().as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. +/// Convert packed half-precision (16-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_pd&expand=4191) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtph_ps&expand=1723) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilpd))] -pub unsafe fn _mm512_permutevar_pd(a: __m512d, b: __m512i) -> __m512d { - transmute(vpermilpd(a.as_f64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvtph2ps))] +pub unsafe fn _mm512_cvtph_ps(a: __m256i) -> __m512 { + transmute(vcvtph2ps( + a.as_i16x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + _MM_FROUND_NO_EXC, + )) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed half-precision (16-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_pd&expand=4189) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtph_ps&expand=1724) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilpd))] -pub unsafe fn _mm512_mask_permutevar_pd( - src: __m512d, - k: __mmask8, - a: __m512d, - b: __m512i, -) -> __m512d { - let permute = _mm512_permutevar_pd(a, b).as_f64x8(); - transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +#[cfg_attr(test, assert_instr(vcvtph2ps))] +pub unsafe fn _mm512_mask_cvtph_ps(src: __m512, k: __mmask16, a: __m256i) -> __m512 { + transmute(vcvtph2ps( + a.as_i16x16(), + src.as_f32x16(), + k, + _MM_FROUND_NO_EXC, + )) } -/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed half-precision (16-bit) floating-point elements in a to packed single-precision (32-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_pd&expand=4190) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtph_ps&expand=1725) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilpd))] -pub unsafe fn _mm512_maskz_permutevar_pd(k: __mmask8, a: __m512d, b: __m512i) -> __m512d { - let permute = _mm512_permutevar_pd(a, b).as_f64x8(); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvtph2ps))] +pub unsafe fn _mm512_maskz_cvtph_ps(k: __mmask16, a: __m256i) -> __m512 { + transmute(vcvtph2ps( + a.as_i16x16(), + _mm512_setzero_ps().as_f32x16(), + k, + _MM_FROUND_NO_EXC, + )) } -/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi32&expand=4301) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epi32&expand=1916) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask -pub unsafe fn _mm512_permutexvar_epi32(idx: __m512i, a: __m512i) -> __m512i { - transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundps_epi32(a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi32&expand=4299) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epi32&expand=1917) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermd))] -pub unsafe fn _mm512_mask_permutexvar_epi32( +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundps_epi32( src: __m512i, k: __mmask16, - idx: __m512i, - a: __m512i, + a: __m512, + sae: i32, ) -> __m512i { - let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); - transmute(simd_select_bitmask(k, permute, src.as_i32x16())) + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi32&expand=4300) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermd))] -pub unsafe fn _mm512_maskz_permutexvar_epi32(k: __mmask16, idx: __m512i, a: __m512i) -> __m512i { - let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundps_epi32(k: __mmask16, a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi64&expand=4307) +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epu32&expand=1922) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //should be vpermq, but generate vpermpd. It generates vpermd with mask -pub unsafe fn _mm512_permutexvar_epi64(idx: __m512i, a: __m512i) -> __m512i { - transmute(vpermq(a.as_i64x8(), idx.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundps_epu32(a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi64&expand=4305) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epu32&expand=1923) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermq))] -pub unsafe fn _mm512_mask_permutexvar_epi64( +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundps_epu32( src: __m512i, - k: __mmask8, - idx: __m512i, - a: __m512i, + k: __mmask16, + a: __m512, + sae: i32, ) -> __m512i { - let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); - transmute(simd_select_bitmask(k, permute, src.as_i64x8())) -} - -/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi64&expand=4306) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermq))] -pub unsafe fn _mm512_maskz_permutexvar_epi64(k: __mmask8, idx: __m512i, a: __m512i) -> __m512i { - let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, permute, zero)) + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx. +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epu32&expand=1924) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermps))] -pub unsafe fn _mm512_permutexvar_ps(idx: __m512i, a: __m512) -> __m512 { - transmute(vpermps(a.as_f32x16(), idx.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundps_epu32(k: __mmask16, a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_ps&expand=4326) +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epi32&expand=1904) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermps))] -pub unsafe fn _mm512_mask_permutexvar_ps( - src: __m512, - k: __mmask16, - idx: __m512i, - a: __m512, -) -> __m512 { - let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); - transmute(simd_select_bitmask(k, permute, src.as_f32x16())) +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundpd_epi32(a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_ps&expand=4327) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epi32&expand=1905) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermps))] -pub unsafe fn _mm512_maskz_permutexvar_ps(k: __mmask16, idx: __m512i, a: __m512) -> __m512 { - let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundpd_epi32( + src: __m256i, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst. +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_pd&expand=4322) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermpd))] -pub unsafe fn _mm512_permutexvar_pd(idx: __m512i, a: __m512d) -> __m512d { - transmute(vpermpd(a.as_f64x8(), idx.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundpd_epi32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_pd&expand=4320) +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epu32&expand=1910) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermpd))] -pub unsafe fn _mm512_mask_permutexvar_pd( - src: __m512d, - k: __mmask8, - idx: __m512i, - a: __m512d, -) -> __m512d { - let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); - transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundpd_epu32(a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_pd&expand=4321) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epu32&expand=1911) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermpd))] -pub unsafe fn _mm512_maskz_permutexvar_pd(k: __mmask8, idx: __m512i, a: __m512d) -> __m512d { - let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundpd_epu32( + src: __m256i, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi32&expand=4238) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epi32&expand=1984) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d -pub unsafe fn _mm512_permutex2var_epi32(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { - transmute(vpermi2d(a.as_i32x16(), idx.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_cvttps_epi32(a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi32&expand=4235) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epi32&expand=1985) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermt2d))] -pub unsafe fn _mm512_mask_permutex2var_epi32( - a: __m512i, - k: __mmask16, - idx: __m512i, - b: __m512i, -) -> __m512i { - let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); - transmute(simd_select_bitmask(k, permute, a.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_mask_cvttps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi32&expand=4237) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epi32&expand=1986) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d -pub unsafe fn _mm512_maskz_permutex2var_epi32( - k: __mmask16, - a: __m512i, - idx: __m512i, - b: __m512i, -) -> __m512i { - let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_maskz_cvttps_epi32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi32&expand=4236) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epu32&expand=2002) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermi2d))] -pub unsafe fn _mm512_mask2_permutex2var_epi32( - a: __m512i, - idx: __m512i, - k: __mmask16, - b: __m512i, -) -> __m512i { - let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); - transmute(simd_select_bitmask(k, permute, idx.as_i32x16())) +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_cvttps_epu32(a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi64&expand=4250) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epu32&expand=2003) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q -pub unsafe fn _mm512_permutex2var_epi64(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { - transmute(vpermi2q(a.as_i64x8(), idx.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_mask_cvttps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi64&expand=4247) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epu32&expand=2004) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermt2q))] -pub unsafe fn _mm512_mask_permutex2var_epi64( - a: __m512i, - k: __mmask8, - idx: __m512i, - b: __m512i, -) -> __m512i { - let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); - transmute(simd_select_bitmask(k, permute, a.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_maskz_cvttps_epu32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi64&expand=4249) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundpd_epu32&expand=1912) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q -pub unsafe fn _mm512_maskz_permutex2var_epi64( - k: __mmask8, - a: __m512i, - idx: __m512i, - b: __m512i, -) -> __m512i { - let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundpd_epu32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) } -/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi64&expand=4248) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epi32&expand=1947) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermi2q))] -pub unsafe fn _mm512_mask2_permutex2var_epi64( - a: __m512i, - idx: __m512i, - k: __mmask8, - b: __m512i, -) -> __m512i { - let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); - transmute(simd_select_bitmask(k, permute, idx.as_i64x8())) +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_cvttpd_epi32(a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_ps&expand=4286) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epi32&expand=1948) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps -pub unsafe fn _mm512_permutex2var_ps(a: __m512, idx: __m512i, b: __m512) -> __m512 { - transmute(vpermi2ps(a.as_f32x16(), idx.as_i32x16(), b.as_f32x16())) +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_mask_cvttpd_epi32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + src.as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_ps&expand=4283) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epi32&expand=1949) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermt2ps))] -pub unsafe fn _mm512_mask_permutex2var_ps( - a: __m512, - k: __mmask16, - idx: __m512i, - b: __m512, -) -> __m512 { - let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); - transmute(simd_select_bitmask(k, permute, a.as_f32x16())) +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_maskz_cvttpd_epi32(k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_ps&expand=4285) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epu32&expand=1965) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps -pub unsafe fn _mm512_maskz_permutex2var_ps( - k: __mmask16, - a: __m512, - idx: __m512i, - b: __m512, -) -> __m512 { - let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_cvttpd_epu32(a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_ps&expand=4284) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epu32&expand=1966) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2ps, but it shows vpermt2ps -pub unsafe fn _mm512_mask2_permutex2var_ps( - a: __m512, - idx: __m512i, - k: __mmask16, - b: __m512, -) -> __m512 { - let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_mask_cvttpd_epu32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + src.as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_pd&expand=4274) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epu32&expand=1967) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd -pub unsafe fn _mm512_permutex2var_pd(a: __m512d, idx: __m512i, b: __m512d) -> __m512d { - transmute(vpermi2pd(a.as_f64x8(), idx.as_i64x8(), b.as_f64x8())) +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_maskz_cvttpd_epu32(k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) } -/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// Returns vector of type `__m512d` with all elements set to zero. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_pd&expand=4271) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermt2pd))] -pub unsafe fn _mm512_mask_permutex2var_pd( - a: __m512d, - k: __mmask8, - idx: __m512i, - b: __m512d, -) -> __m512d { - let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); - transmute(simd_select_bitmask(k, permute, a.as_f64x8())) +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero_pd() -> __m512d { + // All-0 is a properly initialized __m512d + mem::zeroed() } -/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Returns vector of type `__m512d` with all elements set to zero. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_pd&expand=4273) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd -pub unsafe fn _mm512_maskz_permutex2var_pd( - k: __mmask8, - a: __m512d, - idx: __m512i, - b: __m512d, -) -> __m512d { - let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero_ps() -> __m512 { + // All-0 is a properly initialized __m512 + mem::zeroed() } -/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set) +/// Return vector of type __m512 with all elements set to zero. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_pd&expand=4272) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_setzero&expand=5014) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2pd, but it shows vpermt2pd -pub unsafe fn _mm512_mask2_permutex2var_pd( - a: __m512d, - idx: __m512i, - k: __mmask8, - b: __m512d, -) -> __m512d { - let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, permute, zero)) +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero() -> __m512 { + // All-0 is a properly initialized __m512 + mem::zeroed() } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// Returns vector of type `__m512i` with all elements set to zero. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_epi32&expand=5150) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_si512) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpermilps, imm8 = 9))] //should be vpshufd, but generate vpermilps -#[rustc_args_required_const(1)] -pub unsafe fn _mm512_shuffle_epi32(a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { - let imm8 = (imm8 & 0xFF) as u8; +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero_si512() -> __m512i { + // All-0 is a properly initialized __m512i + mem::zeroed() +} - let a = a.as_i32x16(); - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - a, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), - 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), - 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), - _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), - 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), - 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), - _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), - 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), - 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), - _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), - } - }; - } - let r: i32x16 = match imm8 & 0x3 { - 0 => shuffle1!(0, 4, 8, 12), - 1 => shuffle1!(1, 5, 9, 13), - 2 => shuffle1!(2, 6, 10, 14), - _ => shuffle1!(3, 7, 11, 15), - }; +/// Return vector of type __m512i with all elements set to zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_setzero_epi32&expand=5015) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vxorps))] +pub unsafe fn _mm512_setzero_epi32() -> __m512i { + // All-0 is a properly initialized __m512i + mem::zeroed() +} + +/// Sets packed 32-bit integers in `dst` with the supplied values in reverse +/// order. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr_epi32( + e15: i32, + e14: i32, + e13: i32, + e12: i32, + e11: i32, + e10: i32, + e9: i32, + e8: i32, + e7: i32, + e6: i32, + e5: i32, + e4: i32, + e3: i32, + e2: i32, + e1: i32, + e0: i32, +) -> __m512i { + let r = i32x16( + e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, + ); transmute(r) } -/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Set packed 8-bit integers in dst with the supplied values. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set_epi8&expand=4915) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_epi8( + e63: i8, + e62: i8, + e61: i8, + e60: i8, + e59: i8, + e58: i8, + e57: i8, + e56: i8, + e55: i8, + e54: i8, + e53: i8, + e52: i8, + e51: i8, + e50: i8, + e49: i8, + e48: i8, + e47: i8, + e46: i8, + e45: i8, + e44: i8, + e43: i8, + e42: i8, + e41: i8, + e40: i8, + e39: i8, + e38: i8, + e37: i8, + e36: i8, + e35: i8, + e34: i8, + e33: i8, + e32: i8, + e31: i8, + e30: i8, + e29: i8, + e28: i8, + e27: i8, + e26: i8, + e25: i8, + e24: i8, + e23: i8, + e22: i8, + e21: i8, + e20: i8, + e19: i8, + e18: i8, + e17: i8, + e16: i8, + e15: i8, + e14: i8, + e13: i8, + e12: i8, + e11: i8, + e10: i8, + e9: i8, + e8: i8, + e7: i8, + e6: i8, + e5: i8, + e4: i8, + e3: i8, + e2: i8, + e1: i8, + e0: i8, +) -> __m512i { + let r = i8x64( + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, + e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32, e33, e34, e35, e36, e37, + e38, e39, e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, e50, e51, e52, e53, e54, e55, + e56, e57, e58, e59, e60, e61, e62, e63, + ); + transmute(r) +} + +/// Set packed 16-bit integers in dst with the supplied values. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set_epi16&expand=4905) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_epi16( + e31: i16, + e30: i16, + e29: i16, + e28: i16, + e27: i16, + e26: i16, + e25: i16, + e24: i16, + e23: i16, + e22: i16, + e21: i16, + e20: i16, + e19: i16, + e18: i16, + e17: i16, + e16: i16, + e15: i16, + e14: i16, + e13: i16, + e12: i16, + e11: i16, + e10: i16, + e9: i16, + e8: i16, + e7: i16, + e6: i16, + e5: i16, + e4: i16, + e3: i16, + e2: i16, + e1: i16, + e0: i16, +) -> __m512i { + let r = i16x32( + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, + e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, + ); + transmute(r) +} + +/// Set packed 32-bit integers in dst with the repeated 4 element sequence. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_epi32&expand=5148) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set4_epi32&expand=4982) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_mask_shuffle_epi32( - src: __m512i, - k: __mmask16, - a: __m512i, - imm8: _MM_PERM_ENUM, +pub unsafe fn _mm512_set4_epi32(d: i32, c: i32, b: i32, a: i32) -> __m512i { + _mm512_set_epi32(d, c, b, a, d, c, b, a, d, c, b, a, d, c, b, a) +} + +/// Set packed single-precision (32-bit) floating-point elements in dst with the repeated 4 element sequence. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set4_ps&expand=4985) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set4_ps(d: f32, c: f32, b: f32, a: f32) -> __m512 { + _mm512_set_ps(d, c, b, a, d, c, b, a, d, c, b, a, d, c, b, a) +} + +/// Set packed double-precision (64-bit) floating-point elements in dst with the repeated 4 element sequence. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set4_pd&expand=4984) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set4_pd(d: f64, c: f64, b: f64, a: f64) -> __m512d { + _mm512_set_pd(d, c, b, a, d, c, b, a) +} + +/// Set packed 32-bit integers in dst with the repeated 4 element sequence in reverse order. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_setr4_epi32&expand=5009) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr4_epi32(d: i32, c: i32, b: i32, a: i32) -> __m512i { + _mm512_set_epi32(a, b, c, d, a, b, c, d, a, b, c, d, a, b, c, d) +} + +/// Set packed single-precision (32-bit) floating-point elements in dst with the repeated 4 element sequence in reverse order. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_setr4_ps&expand=5012) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr4_ps(d: f32, c: f32, b: f32, a: f32) -> __m512 { + _mm512_set_ps(a, b, c, d, a, b, c, d, a, b, c, d, a, b, c, d) +} + +/// Set packed double-precision (64-bit) floating-point elements in dst with the repeated 4 element sequence in reverse order. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_setr4_pd&expand=5011) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr4_pd(d: f64, c: f64, b: f64, a: f64) -> __m512d { + _mm512_set_pd(a, b, c, d, a, b, c, d) +} + +/// Set packed 64-bit integers in dst with the supplied values. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set_epi64&expand=4910) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_epi64( + e0: i64, + e1: i64, + e2: i64, + e3: i64, + e4: i64, + e5: i64, + e6: i64, + e7: i64, ) -> __m512i { - let imm8 = (imm8 & 0xFF) as u8; + _mm512_setr_epi64(e7, e6, e5, e4, e3, e2, e1, e0) +} - let a = a.as_i32x16(); - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - a, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); +/// Set packed 64-bit integers in dst with the supplied values in reverse order. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_setr_epi64&expand=4993) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr_epi64( + e0: i64, + e1: i64, + e2: i64, + e3: i64, + e4: i64, + e5: i64, + e6: i64, + e7: i64, +) -> __m512i { + let r = i64x8::new(e0, e1, e2, e3, e4, e5, e6, e7); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32gather_pd&expand=3002) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i32gather_pd(offsets: __m256i, slice: *const u8, scale: i32) -> __m512d { + let zero = _mm512_setzero_pd().as_f64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherdpd(zero, slice, offsets, neg_one, $imm8) }; } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), - 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), - 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), - _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 32-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32gather_pd&expand=3003) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherdpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32gather_pd( + src: __m512d, + mask: __mmask8, + offsets: __m256i, + slice: *const u8, + scale: i32, +) -> __m512d { + let src = src.as_f64x8(); + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherdpd(src, slice, offsets, mask as i8, $imm8) }; } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), - 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), - 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), - _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64gather_pd&expand=3092) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i64gather_pd(offsets: __m512i, slice: *const u8, scale: i32) -> __m512d { + let zero = _mm512_setzero_pd().as_f64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqpd(zero, slice, offsets, neg_one, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), - 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), - 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), - _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather double-precision (64-bit) floating-point elements from memory using 64-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64gather_pd&expand=3093) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherqpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64gather_pd( + src: __m512d, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m512d { + let src = src.as_f64x8(); + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqpd(src, slice, offsets, mask as i8, $imm8) }; } - let shuffle: i32x16 = match imm8 & 0x3 { - 0 => shuffle1!(0, 4, 8, 12), - 1 => shuffle1!(1, 5, 9, 13), - 2 => shuffle1!(2, 6, 10, 14), - _ => shuffle1!(3, 7, 11, 15), - }; - transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) + let r = constify_imm8_gather!(scale, call); + transmute(r) } -/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_epi32&expand=5149) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64gather_ps&expand=3100) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_maskz_shuffle_epi32(k: __mmask16, a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { - let imm8 = (imm8 & 0xFF) as u8; +pub unsafe fn _mm512_i64gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m256 { + let zero = _mm256_setzero_ps().as_f32x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqps(zero, slice, offsets, neg_one, $imm8) + }; + } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} - let a = a.as_i32x16(); - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - a, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), - 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), - 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), - _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), - 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), - 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), - _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), - 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), - 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), - _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), - } +/// Gather single-precision (32-bit) floating-point elements from memory using 64-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64gather_ps&expand=3101) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgatherqps, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64gather_ps( + src: __m256, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m256 { + let src = src.as_f32x8(); + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vgatherqps(src, slice, offsets, mask as i8, $imm8) }; } - let shuffle: i32x16 = match imm8 & 0x3 { - 0 => shuffle1!(0, 4, 8, 12), - 1 => shuffle1!(1, 5, 9, 13), - 2 => shuffle1!(2, 6, 10, 14), - _ => shuffle1!(3, 7, 11, 15), - }; - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shuffle, zero)) + let r = constify_imm8_gather!(scale, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_ps&expand=5203) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32gather_ps&expand=3010) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_shuffle_ps(a: __m512, b: __m512, imm8: i32) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), - 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), - 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), - _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), - 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), - 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), - _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), - 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), - 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), - _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), - } +pub unsafe fn _mm512_i32gather_ps(offsets: __m512i, slice: *const u8, scale: i32) -> __m512 { + let zero = _mm512_setzero_ps().as_f32x16(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vgatherdps(zero, slice, offsets, neg_one, $imm8) }; } - match imm8 & 0x3 { - 0 => shuffle1!(0, 4, 8, 12), - 1 => shuffle1!(1, 5, 9, 13), - 2 => shuffle1!(2, 6, 10, 14), - _ => shuffle1!(3, 7, 11, 15), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Gather single-precision (32-bit) floating-point elements from memory using 32-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_ps&expand=5201) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32gather_ps&expand=3011) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[cfg_attr(test, assert_instr(vgatherdps, scale = 1))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_shuffle_ps( +pub unsafe fn _mm512_mask_i32gather_ps( src: __m512, - k: __mmask16, - a: __m512, - b: __m512, - imm8: i32, + mask: __mmask16, + offsets: __m512i, + slice: *const u8, + scale: i32, ) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), - 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), - 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), - _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), - 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), - 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), - _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), - 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), - 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), - _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), - } + let src = src.as_f32x16(); + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vgatherdps(src, slice, offsets, mask as i16, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 4, 8, 12), - 1 => shuffle1!(1, 5, 9, 13), - 2 => shuffle1!(2, 6, 10, 14), - _ => shuffle1!(3, 7, 11, 15), - }; - - transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) + let r = constify_imm8_gather!(scale, call); + transmute(r) } -/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Gather 32-bit integers from memory using 32-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_ps&expand=5202) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32gather_epi32&expand=2986) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_shuffle_ps(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), - 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), - 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), - _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), - 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), - 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), - _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), - } +#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i32gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { + let zero = _mm512_setzero_si512().as_i32x16(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdd(zero, slice, offsets, neg_one, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), - 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), - 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), - _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 32-bit integers from memory using 32-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32gather_epi32&expand=2987) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherdd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32gather_epi32( + src: __m512i, + mask: __mmask16, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m512i { + let src = src.as_i32x16(); + let mask = mask as i16; + let slice = slice as *const i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdd(src, slice, offsets, mask, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 4, 8, 12), - 1 => shuffle1!(1, 5, 9, 13), - 2 => shuffle1!(2, 6, 10, 14), - _ => shuffle1!(3, 7, 11, 15), - }; - - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, shuffle, zero)) + let r = constify_imm8_gather!(scale, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst. +/// Gather 64-bit integers from memory using 32-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_pd&expand=5192) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32gather_epi64&expand=2994) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_shuffle_pd(a: __m512d, b: __m512d, imm8: i32) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle8 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle7 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 7) & 0x1 { - 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), - _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), - } - }; - } - macro_rules! shuffle6 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { - match (imm8 >> 6) & 0x1 { - 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), - _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), - } - }; - } - macro_rules! shuffle5 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { - match (imm8 >> 5) & 0x1 { - 0 => shuffle6!($a, $b, $c, $d, $e, 12), - _ => shuffle6!($a, $b, $c, $d, $e, 13), - } +pub unsafe fn _mm512_i32gather_epi64(offsets: __m256i, slice: *const u8, scale: i32) -> __m512i { + let zero = _mm512_setzero_si512().as_i64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdq(zero, slice, offsets, neg_one, $imm8) }; } - macro_rules! shuffle4 { - ($a:expr, $b:expr, $c:expr, $d:expr) => { - match (imm8 >> 4) & 0x1 { - 0 => shuffle5!($a, $b, $c, $d, 4), - _ => shuffle5!($a, $b, $c, $d, 5), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 64-bit integers from memory using 32-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32gather_epi64&expand=2995) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherdq, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32gather_epi64( + src: __m512i, + mask: __mmask8, + offsets: __m256i, + slice: *const u8, + scale: i32, +) -> __m512i { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *const i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherdq(src, slice, offsets, mask, $imm8) }; } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr) => { - match (imm8 >> 3) & 0x1 { - 0 => shuffle4!($a, $b, $c, 10), - _ => shuffle4!($a, $b, $c, 11), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 64-bit integers from memory using 64-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64gather_epi64&expand=3084) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i64gather_epi64(offsets: __m512i, slice: *const u8, scale: i32) -> __m512i { + let zero = _mm512_setzero_si512().as_i64x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqq(zero, slice, offsets, neg_one, $imm8) }; } - macro_rules! shuffle2 { - ($a:expr, $b:expr) => { - match (imm8 >> 2) & 0x1 { - 0 => shuffle3!($a, $b, 2), - _ => shuffle3!($a, $b, 3), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 64-bit integers from memory using 64-bit indices. 64-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64gather_epi64&expand=3085) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherqq, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64gather_epi64( + src: __m512i, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m512i { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqq(src, slice, offsets, mask, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr) => { - match (imm8 >> 1) & 0x1 { - 0 => shuffle2!($a, 8), - _ => shuffle2!($a, 9), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Gather 32-bit integers from memory using 64-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64gather_epi32&expand=3074) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_i64gather_epi32(offsets: __m512i, slice: *const u8, scale: i32) -> __m256i { + let zeros = _mm256_setzero_si256().as_i32x8(); + let neg_one = -1; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqd(zeros, slice, offsets, neg_one, $imm8) }; } - match imm8 & 0x1 { - 0 => shuffle1!(0), - _ => shuffle1!(1), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) } -/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Gather 32-bit integers from memory using 64-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst using writemask k (elements are copied from src when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_pd&expand=5190) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64gather_epi32&expand=3075) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[cfg_attr(test, assert_instr(vpgatherqd, scale = 1))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_shuffle_pd( - src: __m512d, - k: __mmask8, - a: __m512d, - b: __m512d, - imm8: i32, -) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle8 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle7 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 7) & 0x1 { - 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), - _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), - } +pub unsafe fn _mm512_mask_i64gather_epi32( + src: __m256i, + mask: __mmask8, + offsets: __m512i, + slice: *const u8, + scale: i32, +) -> __m256i { + let src = src.as_i32x8(); + let mask = mask as i8; + let slice = slice as *const i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpgatherqd(src, slice, offsets, mask, $imm8) }; } - macro_rules! shuffle6 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { - match (imm8 >> 6) & 0x1 { - 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), - _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), - } + let r = constify_imm8_gather!(scale, call); + transmute(r) +} + +/// Scatter double-precision (64-bit) floating-point elements from a into memory using 32-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32scatter_pd&expand=3044) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_pd(slice: *mut u8, offsets: __m256i, src: __m512d, scale: i32) { + let src = src.as_f64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterdpd(slice, neg_one, offsets, src, $imm8) }; } - macro_rules! shuffle5 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { - match (imm8 >> 5) & 0x1 { - 0 => shuffle6!($a, $b, $c, $d, $e, 12), - _ => shuffle6!($a, $b, $c, $d, $e, 13), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter double-precision (64-bit) floating-point elements from a into memory using 32-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32scatter_pd&expand=3045) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_pd( + slice: *mut u8, + mask: __mmask8, + offsets: __m256i, + src: __m512d, + scale: i32, +) { + let src = src.as_f64x8(); + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterdpd(slice, mask as i8, offsets, src, $imm8) }; } - macro_rules! shuffle4 { - ($a:expr, $b:expr, $c:expr, $d:expr) => { - match (imm8 >> 4) & 0x1 { - 0 => shuffle5!($a, $b, $c, $d, 4), - _ => shuffle5!($a, $b, $c, $d, 5), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter double-precision (64-bit) floating-point elements from a into memory using 64-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64scatter_pd&expand=3122) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i64scatter_pd(slice: *mut u8, offsets: __m512i, src: __m512d, scale: i32) { + let src = src.as_f64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqpd(slice, neg_one, offsets, src, $imm8) }; } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr) => { - match (imm8 >> 3) & 0x1 { - 0 => shuffle4!($a, $b, $c, 10), - _ => shuffle4!($a, $b, $c, 11), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter double-precision (64-bit) floating-point elements from a into memory using 64-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64scatter_pd&expand=3123) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterqpd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64scatter_pd( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, + src: __m512d, + scale: i32, +) { + let src = src.as_f64x8(); + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqpd(slice, mask as i8, offsets, src, $imm8) }; } - macro_rules! shuffle2 { - ($a:expr, $b:expr) => { - match (imm8 >> 2) & 0x1 { - 0 => shuffle3!($a, $b, 2), - _ => shuffle3!($a, $b, 3), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter single-precision (32-bit) floating-point elements from a into memory using 32-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32scatter_ps&expand=3050) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_ps(slice: *mut u8, offsets: __m512i, src: __m512, scale: i32) { + let src = src.as_f32x16(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vscatterdps(slice, neg_one, offsets, src, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr) => { - match (imm8 >> 1) & 0x1 { - 0 => shuffle2!($a, 8), - _ => shuffle2!($a, 9), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter single-precision (32-bit) floating-point elements from a into memory using 32-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32scatter_ps&expand=3051) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterdps, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_ps( + slice: *mut u8, + mask: __mmask16, + offsets: __m512i, + src: __m512, + scale: i32, +) { + let src = src.as_f32x16(); + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vscatterdps(slice, mask as i16, offsets, src, $imm8) }; } - let shuffle = match imm8 & 0x1 { - 0 => shuffle1!(0), - _ => shuffle1!(1), - }; - - transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) + constify_imm8_gather!(scale, call); } -/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Scatter single-precision (32-bit) floating-point elements from a into memory using 64-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_pd&expand=5191) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64scatter_ps&expand=3128) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_shuffle_pd(k: __mmask8, a: __m512d, b: __m512d, imm8: i32) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle8 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle7 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 7) & 0x1 { - 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), - _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), - } +pub unsafe fn _mm512_i64scatter_ps(slice: *mut u8, offsets: __m512i, src: __m256, scale: i32) { + let src = src.as_f32x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqps(slice, neg_one, offsets, src, $imm8) }; } - macro_rules! shuffle6 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { - match (imm8 >> 6) & 0x1 { - 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), - _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter single-precision (32-bit) floating-point elements from a into memory using 64-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64scatter_ps&expand=3129) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscatterqps, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i64scatter_ps( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, + src: __m256, + scale: i32, +) { + let src = src.as_f32x8(); + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vscatterqps(slice, mask as i8, offsets, src, $imm8) }; } - macro_rules! shuffle5 { - ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { - match (imm8 >> 5) & 0x1 { - 0 => shuffle6!($a, $b, $c, $d, $e, 12), - _ => shuffle6!($a, $b, $c, $d, $e, 13), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter 64-bit integers from a into memory using 32-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32scatter_epi64&expand=3038) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_epi64(slice: *mut u8, offsets: __m256i, src: __m512i, scale: i32) { + let src = src.as_i64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdq(slice, neg_one, offsets, src, $imm8) }; } - macro_rules! shuffle4 { - ($a:expr, $b:expr, $c:expr, $d:expr) => { - match (imm8 >> 4) & 0x1 { - 0 => shuffle5!($a, $b, $c, $d, 4), - _ => shuffle5!($a, $b, $c, $d, 5), - } - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr) => { - match (imm8 >> 3) & 0x1 { - 0 => shuffle4!($a, $b, $c, 10), - _ => shuffle4!($a, $b, $c, 11), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr) => { - match (imm8 >> 2) & 0x1 { - 0 => shuffle3!($a, $b, 2), - _ => shuffle3!($a, $b, 3), - } - }; - } - macro_rules! shuffle1 { - ($a:expr) => { - match (imm8 >> 1) & 0x1 { - 0 => shuffle2!($a, 8), - _ => shuffle2!($a, 9), - } - }; - } - let shuffle = match imm8 & 0x1 { - 0 => shuffle1!(0), - _ => shuffle1!(1), - }; - - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, shuffle, zero)) + constify_imm8_gather!(scale, call); } -/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst. +/// Scatter 64-bit integers from a into memory using 32-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i32&expand=5177) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32scatter_epi64&expand=3039) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] //should be vshufi32x4, but generate vshufi64x2 -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_shuffle_i32x4(a: __m512i, b: __m512i, imm8: i32) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - let a = a.as_i32x16(); - let b = b.as_i32x16(); - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), - _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), - 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), - 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), - _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), - } +#[cfg_attr(test, assert_instr(vpscatterdq, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_epi64( + slice: *mut u8, + mask: __mmask8, + offsets: __m256i, + src: __m512i, + scale: i32, +) { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdq(slice, mask, offsets, src, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), - 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), - 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), - _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter 64-bit integers from a into memory using 64-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64scatter_epi64&expand=3116) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i64scatter_epi64(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { + let src = src.as_i64x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqq(slice, neg_one, offsets, src, $imm8) }; } - let r: i32x16 = match imm8 & 0x3 { - 0 => shuffle1!(0, 1, 2, 3), - 1 => shuffle1!(4, 5, 6, 7), - 2 => shuffle1!(8, 9, 10, 11), - _ => shuffle1!(12, 13, 14, 15), - }; - - transmute(r) + constify_imm8_gather!(scale, call); } -/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Scatter 64-bit integers from a into memory using 64-bit indices. 64-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i32x&expand=5175) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64scatter_epi64&expand=3117) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] +#[cfg_attr(test, assert_instr(vpscatterqq, scale = 1))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_shuffle_i32x4( +pub unsafe fn _mm512_mask_i64scatter_epi64( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, src: __m512i, - k: __mmask16, - a: __m512i, - b: __m512i, - imm8: i32, -) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - let a = a.as_i32x16(); - let b = b.as_i32x16(); - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), - _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), - 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), - 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), - _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), - } + scale: i32, +) { + let src = src.as_i64x8(); + let mask = mask as i8; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqq(slice, mask, offsets, src, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), - 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), - 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), - _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), - } + constify_imm8_gather!(scale, call); +} + +/// Scatter 32-bit integers from a into memory using 32-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). scale should be 1, 2, 4 or 8. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i32scatter_epi32&expand=3032) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i32scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m512i, scale: i32) { + let src = src.as_i32x16(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdd(slice, neg_one, offsets, src, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1, 2, 3), - 1 => shuffle1!(4, 5, 6, 7), - 2 => shuffle1!(8, 9, 10, 11), - _ => shuffle1!(12, 13, 14, 15), - }; - - transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) + constify_imm8_gather!(scale, call); } -/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Scatter 32-bit integers from a into memory using 32-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i32&expand=5176) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i32scatter_epi32&expand=3033) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_shuffle_i32x4( - k: __mmask16, - a: __m512i, - b: __m512i, - imm8: i32, -) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - let a = a.as_i32x16(); - let b = b.as_i32x16(); - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), - _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), - 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), - 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), - _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), - 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), - 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), - _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), - } +#[cfg_attr(test, assert_instr(vpscatterdd, scale = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_i32scatter_epi32( + slice: *mut u8, + mask: __mmask16, + offsets: __m512i, + src: __m512i, + scale: i32, +) { + let src = src.as_i32x16(); + let mask = mask as i16; + let slice = slice as *mut i8; + let offsets = offsets.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpscatterdd(slice, mask, offsets, src, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1, 2, 3), - 1 => shuffle1!(4, 5, 6, 7), - 2 => shuffle1!(8, 9, 10, 11), - _ => shuffle1!(12, 13, 14, 15), - }; - - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, shuffle, zero)) + constify_imm8_gather!(scale, call); } -/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst. +/// Scatter 32-bit integers from a into memory using 64-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i64x2&expand=5183) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_i64scatter_epi32&expand=3108) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_shuffle_i64x2(a: __m512i, b: __m512i, imm8: i32) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr - ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), - _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, 8, 9), - 1 => shuffle3!($a, $b, $e, $f, 10, 11), - 2 => shuffle3!($a, $b, $e, $f, 12, 13), - _ => shuffle3!($a, $b, $e, $f, 14, 15), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, 0, 1), - 1 => shuffle2!($a, $e, 2, 3), - 2 => shuffle2!($a, $e, 4, 5), - _ => shuffle2!($a, $e, 6, 7), - } +#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_i64scatter_epi32(slice: *mut u8, offsets: __m512i, src: __m256i, scale: i32) { + let src = src.as_i32x8(); + let neg_one = -1; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqd(slice, neg_one, offsets, src, $imm8) }; } - match imm8 & 0x3 { - 0 => shuffle1!(0, 1), - 1 => shuffle1!(2, 3), - 2 => shuffle1!(4, 5), - _ => shuffle1!(6, 7), - } + constify_imm8_gather!(scale, call); } -/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Scatter 32-bit integers from a into memory using 64-bit indices. 32-bit elements are stored at addresses starting at base_addr and offset by each 64-bit element in vindex (each index is scaled by the factor in scale) subject to mask k (elements are not stored when the corresponding mask bit is not set). scale should be 1, 2, 4 or 8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i64x&expand=5181) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_i64scatter_epi32&expand=3109) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[cfg_attr(test, assert_instr(vpscatterqd, scale = 1))] #[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_shuffle_i64x2( - src: __m512i, - k: __mmask8, - a: __m512i, - b: __m512i, - imm8: i32, -) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr - ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), - _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, 8, 9), - 1 => shuffle3!($a, $b, $e, $f, 10, 11), - 2 => shuffle3!($a, $b, $e, $f, 12, 13), - _ => shuffle3!($a, $b, $e, $f, 14, 15), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, 0, 1), - 1 => shuffle2!($a, $e, 2, 3), - 2 => shuffle2!($a, $e, 4, 5), - _ => shuffle2!($a, $e, 6, 7), - } +pub unsafe fn _mm512_mask_i64scatter_epi32( + slice: *mut u8, + mask: __mmask8, + offsets: __m512i, + src: __m256i, + scale: i32, +) { + let src = src.as_i32x8(); + let mask = mask as i8; + let slice = slice as *mut i8; + let offsets = offsets.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpscatterqd(slice, mask, offsets, src, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1), - 1 => shuffle1!(2, 3), - 2 => shuffle1!(4, 5), - _ => shuffle1!(6, 7), - }; + constify_imm8_gather!(scale, call); +} - transmute(simd_select_bitmask(k, shuffle, src.as_i64x8())) +/// Contiguously store the active 32-bit integers in a (those with their respective bit set in writemask k) to dst, and pass through the remaining elements from src. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_compress_epi32&expand=1198) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcompressd))] +pub unsafe fn _mm512_mask_compress_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i { + transmute(vpcompressd(a.as_i32x16(), src.as_i32x16(), k)) } -/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Contiguously store the active 32-bit integers in a (those with their respective bit set in zeromask k) to dst, and set the remaining elements to zero. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i64&expand=5182) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_compress_epi32&expand=1199) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_shuffle_i64x2( - k: __mmask8, - a: __m512i, - b: __m512i, - imm8: i32, -) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr - ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), - _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, 8, 9), - 1 => shuffle3!($a, $b, $e, $f, 10, 11), - 2 => shuffle3!($a, $b, $e, $f, 12, 13), - _ => shuffle3!($a, $b, $e, $f, 14, 15), - } +#[cfg_attr(test, assert_instr(vpcompressd))] +pub unsafe fn _mm512_maskz_compress_epi32(k: __mmask16, a: __m512i) -> __m512i { + transmute(vpcompressd( + a.as_i32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + )) +} + +/// Contiguously store the active 64-bit integers in a (those with their respective bit set in writemask k) to dst, and pass through the remaining elements from src. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_compress_epi64&expand=1204) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcompressq))] +pub unsafe fn _mm512_mask_compress_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + transmute(vpcompressq(a.as_i64x8(), src.as_i64x8(), k)) +} + +/// Contiguously store the active 64-bit integers in a (those with their respective bit set in zeromask k) to dst, and set the remaining elements to zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_compress_epi64&expand=1205) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcompressq))] +pub unsafe fn _mm512_maskz_compress_epi64(k: __mmask8, a: __m512i) -> __m512i { + transmute(vpcompressq( + a.as_i64x8(), + _mm512_setzero_si512().as_i64x8(), + k, + )) +} + +/// Contiguously store the active single-precision (32-bit) floating-point elements in a (those with their respective bit set in writemask k) to dst, and pass through the remaining elements from src. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_compress_ps&expand=1222) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcompressps))] +pub unsafe fn _mm512_mask_compress_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vcompressps(a.as_f32x16(), src.as_f32x16(), k)) +} + +/// Contiguously store the active single-precision (32-bit) floating-point elements in a (those with their respective bit set in zeromask k) to dst, and set the remaining elements to zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_compress_ps&expand=1223) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcompressps))] +pub unsafe fn _mm512_maskz_compress_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vcompressps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + k, + )) +} + +/// Contiguously store the active double-precision (64-bit) floating-point elements in a (those with their respective bit set in writemask k) to dst, and pass through the remaining elements from src. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_compress_pd&expand=1216) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcompresspd))] +pub unsafe fn _mm512_mask_compress_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vcompresspd(a.as_f64x8(), src.as_f64x8(), k)) +} + +/// Contiguously store the active double-precision (64-bit) floating-point elements in a (those with their respective bit set in zeromask k) to dst, and set the remaining elements to zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_compress_pd&expand=1217) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcompresspd))] +pub unsafe fn _mm512_maskz_compress_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vcompresspd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k)) +} + +/// Load contiguous active 32-bit integers from a (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_expand_epi32&expand=2316) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpexpandd))] +pub unsafe fn _mm512_mask_expand_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i { + transmute(vpexpandd(a.as_i32x16(), src.as_i32x16(), k)) +} + +/// Load contiguous active 32-bit integers from a (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_expand_epi32&expand=2317) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpexpandd))] +pub unsafe fn _mm512_maskz_expand_epi32(k: __mmask16, a: __m512i) -> __m512i { + transmute(vpexpandd( + a.as_i32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + )) +} + +/// Load contiguous active 64-bit integers from a (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_expand_epi64&expand=2322) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpexpandq))] +pub unsafe fn _mm512_mask_expand_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + transmute(vpexpandq(a.as_i64x8(), src.as_i64x8(), k)) +} + +/// Load contiguous active 64-bit integers from a (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_expand_epi64&expand=2323) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpexpandq))] +pub unsafe fn _mm512_maskz_expand_epi64(k: __mmask8, a: __m512i) -> __m512i { + transmute(vpexpandq( + a.as_i64x8(), + _mm512_setzero_si512().as_i64x8(), + k, + )) +} + +/// Load contiguous active single-precision (32-bit) floating-point elements from a (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_expand_ps&expand=2340) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vexpandps))] +pub unsafe fn _mm512_mask_expand_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vexpandps(a.as_f32x16(), src.as_f32x16(), k)) +} + +/// Load contiguous active single-precision (32-bit) floating-point elements from a (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_expand_ps&expand=2341) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vexpandps))] +pub unsafe fn _mm512_maskz_expand_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vexpandps(a.as_f32x16(), _mm512_setzero_ps().as_f32x16(), k)) +} + +/// Load contiguous active double-precision (64-bit) floating-point elements from a (those with their respective bit set in mask k), and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_expand_pd&expand=2334) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vexpandpd))] +pub unsafe fn _mm512_mask_expand_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vexpandpd(a.as_f64x8(), src.as_f64x8(), k)) +} + +/// Load contiguous active double-precision (64-bit) floating-point elements from a (those with their respective bit set in mask k), and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_expand_pd&expand=2335) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vexpandpd))] +pub unsafe fn _mm512_maskz_expand_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vexpandpd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi32&expand=4685) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_rol_epi32(a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vprold(a, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, 0, 1), - 1 => shuffle2!($a, $e, 2, 3), - 2 => shuffle2!($a, $e, 4, 5), - _ => shuffle2!($a, $e, 6, 7), - } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi32&expand=4683) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_rol_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vprold(a, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1), - 1 => shuffle1!(2, 3), - 2 => shuffle1!(4, 5), - _ => shuffle1!(6, 7), - }; - - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, shuffle, zero)) + let rol = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, rol, src.as_i32x16())) } -/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f32x4&expand=5165) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi32&expand=4684) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] //should be vshuff32x4, but generate vshuff64x2 +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_shuffle_f32x4(a: __m512, b: __m512, imm8: i32) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), - _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), - } +pub unsafe fn _mm512_maskz_rol_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vprold(a, $imm8) }; } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), - 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), - 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), - _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), - } + let rol = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi32&expand=4721) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_ror_epi32(a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vprord(a, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), - 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), - 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), - _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), - } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi32&expand=4719) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_ror_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vprord(a, $imm8) }; } - match imm8 & 0x3 { - 0 => shuffle1!(0, 1, 2, 3), - 1 => shuffle1!(4, 5, 6, 7), - 2 => shuffle1!(8, 9, 10, 11), - _ => shuffle1!(12, 13, 14, 15), - } + let ror = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ror, src.as_i32x16())) } -/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f32&expand=5163) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi32&expand=4720) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_shuffle_f32x4( - src: __m512, - k: __mmask16, - a: __m512, - b: __m512, - imm8: i32, -) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), - _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), - 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), - 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), - _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), - } +#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_ror_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vprord(a, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), - 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), - 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), - _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), - } + let ror = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi64&expand=4694) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_rol_epi64(a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vprolq(a, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1, 2, 3), - 1 => shuffle1!(4, 5, 6, 7), - 2 => shuffle1!(8, 9, 10, 11), - _ => shuffle1!(12, 13, 14, 15), - }; - - transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f32&expand=5164) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi64&expand=4692) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] #[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_shuffle_f32x4(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr, - $i:expr, - $j:expr, - $k:expr, - $l:expr, - $m:expr, - $n:expr, - $o:expr, - $p:expr - ) => { - simd_shuffle16( - a, - b, - [ - $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, - ], - ); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), - _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), - 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), - 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), - _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr, $i: expr, $m: expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), - 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), - 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), - _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), - } +pub unsafe fn _mm512_mask_rol_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vprolq(a, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1, 2, 3), - 1 => shuffle1!(4, 5, 6, 7), - 2 => shuffle1!(8, 9, 10, 11), - _ => shuffle1!(12, 13, 14, 15), - }; - - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, shuffle, zero)) + let rol = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, rol, src.as_i64x8())) } -/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f64x2&expand=5171) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi64&expand=4693) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_shuffle_f64x2(a: __m512d, b: __m512d, imm8: i32) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr - ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), - _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, 8, 9), - 1 => shuffle3!($a, $b, $e, $f, 10, 11), - 2 => shuffle3!($a, $b, $e, $f, 12, 13), - _ => shuffle3!($a, $b, $e, $f, 14, 15), - } +pub unsafe fn _mm512_maskz_rol_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vprolq(a, $imm8) }; } - macro_rules! shuffle1 { - ($a:expr, $e:expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, 0, 1), - 1 => shuffle2!($a, $e, 2, 3), - 2 => shuffle2!($a, $e, 4, 5), - _ => shuffle2!($a, $e, 6, 7), - } + let rol = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi64&expand=4730) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_ror_epi64(a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vprorq(a, $imm8) }; } - match imm8 & 0x3 { - 0 => shuffle1!(0, 1), - 1 => shuffle1!(2, 3), - 2 => shuffle1!(4, 5), - _ => shuffle1!(6, 7), - } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f64x2&expand=5169) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi64&expand=4728) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_shuffle_f64x2( - src: __m512d, - k: __mmask8, - a: __m512d, - b: __m512d, - imm8: i32, -) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr - ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), - _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, 8, 9), - 1 => shuffle3!($a, $b, $e, $f, 10, 11), - 2 => shuffle3!($a, $b, $e, $f, 12, 13), - _ => shuffle3!($a, $b, $e, $f, 14, 15), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, 0, 1), - 1 => shuffle2!($a, $e, 2, 3), - 2 => shuffle2!($a, $e, 4, 5), - _ => shuffle2!($a, $e, 6, 7), - } +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_ror_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vprorq(a, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1), - 1 => shuffle1!(2, 3), - 2 => shuffle1!(4, 5), - _ => shuffle1!(6, 7), - }; - - transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) + let ror = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ror, src.as_i64x8())) } -/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f64x2&expand=5170) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi64&expand=4729) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_shuffle_f64x2( - k: __mmask8, - a: __m512d, - b: __m512d, - imm8: i32, -) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 255); - let imm8 = (imm8 & 0xFF) as u8; - macro_rules! shuffle4 { - ( - $a:expr, - $b:expr, - $c:expr, - $d:expr, - $e:expr, - $f:expr, - $g:expr, - $h:expr - ) => { - simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); - }; - } - macro_rules! shuffle3 { - ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { - match (imm8 >> 6) & 0x3 { - 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), - 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), - 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), - _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), - } - }; - } - macro_rules! shuffle2 { - ($a:expr, $b:expr, $e:expr, $f:expr) => { - match (imm8 >> 4) & 0x3 { - 0 => shuffle3!($a, $b, $e, $f, 8, 9), - 1 => shuffle3!($a, $b, $e, $f, 10, 11), - 2 => shuffle3!($a, $b, $e, $f, 12, 13), - _ => shuffle3!($a, $b, $e, $f, 14, 15), - } - }; - } - macro_rules! shuffle1 { - ($a:expr, $e:expr) => { - match (imm8 >> 2) & 0x3 { - 0 => shuffle2!($a, $e, 0, 1), - 1 => shuffle2!($a, $e, 2, 3), - 2 => shuffle2!($a, $e, 4, 5), - _ => shuffle2!($a, $e, 6, 7), - } +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_ror_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vprorq(a, $imm8) }; } - let shuffle = match imm8 & 0x3 { - 0 => shuffle1!(0, 1), - 1 => shuffle1!(2, 3), - 2 => shuffle1!(4, 5), - _ => shuffle1!(6, 7), - }; - - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, shuffle, zero)) + let ror = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, ror, zero)) } -/// Extract 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from a, selected with imm8, and store the result in dst. +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_extractf32x4_ps&expand=2442) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi32&expand=5310) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr( - all(test, not(target_os = "windows")), - assert_instr(vextractf32x4, imm8 = 3) -)] +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] #[rustc_args_required_const(1)] -pub unsafe fn _mm512_extractf32x4_ps(a: __m512, imm8: i32) -> __m128 { - assert!(imm8 >= 0 && imm8 <= 3); - match imm8 & 0x3 { - 0 => simd_shuffle4(a, _mm512_undefined_ps(), [0, 1, 2, 3]), - 1 => simd_shuffle4(a, _mm512_undefined_ps(), [4, 5, 6, 7]), - 2 => simd_shuffle4(a, _mm512_undefined_ps(), [8, 9, 10, 11]), - _ => simd_shuffle4(a, _mm512_undefined_ps(), [12, 13, 14, 15]), +pub unsafe fn _mm512_slli_epi32(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsllid(a, $imm8) + }; } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_moveldup_ps&expand=3862) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi32&expand=5308) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovsldup))] -pub unsafe fn _mm512_moveldup_ps(a: __m512) -> __m512 { - let r: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); - transmute(r) +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_slli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsllid(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_moveldup_ps&expand=3860) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi32&expand=5309) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovsldup))] -pub unsafe fn _mm512_mask_moveldup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { - let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); - transmute(simd_select_bitmask(k, mov, src.as_f32x16())) +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_slli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsllid(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveldup_ps&expand=3861) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi32&expand=5522) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovsldup))] -pub unsafe fn _mm512_maskz_moveldup_ps(k: __mmask16, a: __m512) -> __m512 { - let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, mov, zero)) +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srli_epi32(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movehdup_ps&expand=3852) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi32&expand=5520) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovshdup))] -pub unsafe fn _mm512_movehdup_ps(a: __m512) -> __m512 { - let r: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); - transmute(r) +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movehdup&expand=3850) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi32&expand=5521) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovshdup))] -pub unsafe fn _mm512_mask_movehdup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { - let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); - transmute(simd_select_bitmask(k, mov, src.as_f32x16())) +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveh&expand=3851) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi64&expand=5319) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovshdup))] -pub unsafe fn _mm512_maskz_movehdup_ps(k: __mmask16, a: __m512) -> __m512 { - let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, mov, zero)) +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_slli_epi64(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpslliq(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst. +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movedup_pd&expand=3843) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi64&expand=5317) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovddup))] -pub unsafe fn _mm512_movedup_pd(a: __m512d) -> __m512d { - let r: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); - transmute(r) +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_slli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpslliq(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movedup_pd&expand=3841) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi64&expand=5318) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovddup))] -pub unsafe fn _mm512_mask_movedup_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { - let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); - transmute(simd_select_bitmask(k, mov, src.as_f64x8())) +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_slli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpslliq(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_movedup_pd&expand=3842) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi64&expand=5531) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovddup))] -pub unsafe fn _mm512_maskz_movedup_pd(k: __mmask8, a: __m512d) -> __m512d { - let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, mov, zero)) +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srli_epi64(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Copy a to dst, then insert 128 bits (composed of 4 packed 32-bit integers) from b into dst at the location specified by imm8. +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_inserti32x4&expand=3174) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi64&expand=5529) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] //should be vinserti32x4 +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi64&expand=5530) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] #[rustc_args_required_const(2)] -pub unsafe fn _mm512_inserti32x4(a: __m512i, b: __m128i, imm8: i32) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 3); - let a = a.as_i32x16(); - let b = _mm512_castsi128_si512(b).as_i32x16(); - let ret: i32x16 = match imm8 & 0b11 { - 0 => simd_shuffle16( - a, - b, - [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 1 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 2 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], - ), - _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), - }; - transmute(ret) +pub unsafe fn _mm512_maskz_srli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Copy a to tmp, then insert 128 bits (composed of 4 packed 32-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_inserti32x4&expand=3175) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi32&expand=5280) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinserti32x4, imm8 = 2))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_inserti32x4( +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_sll_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpslld(a.as_i32x16(), count.as_i32x4())) +} + +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi32&expand=5278) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_mask_sll_epi32( src: __m512i, k: __mmask16, a: __m512i, - b: __m128i, - imm8: i32, + count: __m128i, ) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 3); - let a = a.as_i32x16(); - let b = _mm512_castsi128_si512(b).as_i32x16(); - let insert: i32x16 = match imm8 & 0b11 { - 0 => simd_shuffle16( - a, - b, - [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 1 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 2 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], - ), - _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), - }; - transmute(simd_select_bitmask(k, insert, src.as_i32x16())) + let shf = _mm512_sll_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Copy a to tmp, then insert 128 bits (composed of 4 packed 32-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_inserti32x4&expand=3176) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi32&expand=5279) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinserti32x4, imm8 = 2))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_inserti32x4(k: __mmask16, a: __m512i, b: __m128i, imm8: i32) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 3); - let a = a.as_i32x16(); - let b = _mm512_castsi128_si512(b).as_i32x16(); - let insert = match imm8 & 0b11 { - 0 => simd_shuffle16( - a, - b, - [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 1 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 2 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], - ), - _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), - }; +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_maskz_sll_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sll_epi32(a, count).as_i32x16(); let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, insert, zero)) + transmute(simd_select_bitmask(k, shf, zero)) } -/// Copy a to dst, then insert 256 bits (composed of 4 packed 64-bit integers) from b into dst at the location specified by imm8. +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_inserti64x4&expand=3186) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi32&expand=5492) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] //should be vinserti64x4 -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_inserti64x4(a: __m512i, b: __m256i, imm8: i32) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 1); - let b = _mm512_castsi256_si512(b); - match imm8 & 0b1 { - 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), - _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), - } +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_srl_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrld(a.as_i32x16(), count.as_i32x4())) } -/// Copy a to tmp, then insert 256 bits (composed of 4 packed 64-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_inserti64x4&expand=3187) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi32&expand=5490) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinserti64x4, imm8 = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_inserti64x4( +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_mask_srl_epi32( src: __m512i, - k: __mmask8, + k: __mmask16, a: __m512i, - b: __m256i, - imm8: i32, + count: __m128i, ) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 1); - let b = _mm512_castsi256_si512(b); - let insert = match imm8 & 0b1 { - 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), - _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), - }; - transmute(simd_select_bitmask(k, insert, src.as_i64x8())) + let shf = _mm512_srl_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Copy a to tmp, then insert 256 bits (composed of 4 packed 64-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_inserti64x4&expand=3188) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srl_epi32&expand=5491) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinserti64x4, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_inserti64x4(k: __mmask8, a: __m512i, b: __m256i, imm8: i32) -> __m512i { - assert!(imm8 >= 0 && imm8 <= 1); - let b = _mm512_castsi256_si512(b); - let insert = match imm8 & 0b1 { - 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), - _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), - }; - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, insert, zero)) +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_maskz_srl_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_srl_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Copy a to dst, then insert 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from b into dst at the location specified by imm8. +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_insertf32x4&expand=3155) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi64&expand=5289) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_insertf32x4(a: __m512, b: __m128, imm8: i32) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 3); - let b = _mm512_castps128_ps512(b); - match imm8 & 0b11 { - 0 => simd_shuffle16( - a, - b, - [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 1 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 2 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], - ), - _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), - } +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_sll_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsllq(a.as_i64x8(), count.as_i64x2())) } -/// Copy a to tmp, then insert 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_insertf32x4&expand=3156) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi64&expand=5287) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_insertf32x4( - src: __m512, - k: __mmask16, - a: __m512, - b: __m128, - imm8: i32, -) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 3); - let b = _mm512_castps128_ps512(b); - let insert = match imm8 & 0b11 { - 0 => simd_shuffle16( - a, - b, - [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 1 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 2 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], - ), - _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), - }; - transmute(simd_select_bitmask(k, insert, src.as_f32x16())) +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_mask_sll_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sll_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Copy a to tmp, then insert 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_insertf32x4&expand=3157) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_insertf32x4(k: __mmask16, a: __m512, b: __m128, imm8: i32) -> __m512 { - assert!(imm8 >= 0 && imm8 <= 3); - let b = _mm512_castps128_ps512(b); - let insert = match imm8 & 0b11 { - 0 => simd_shuffle16( - a, - b, - [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 1 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], - ), - 2 => simd_shuffle16( - a, - b, - [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], - ), - _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), - }; - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, insert, zero)) +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_maskz_sll_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sll_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Copy a to dst, then insert 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from b into dst at the location specified by imm8. +/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_insertf64x4&expand=3167) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi64&expand=5501) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm512_insertf64x4(a: __m512d, b: __m256d, imm8: i32) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 1); - let b = _mm512_castpd256_pd512(b); - match imm8 & 0b1 { - 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), - _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), - } +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_srl_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrlq(a.as_i64x8(), count.as_i64x2())) } -/// Copy a to tmp, then insert 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_insertf64x4&expand=3168) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi64&expand=5499) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] -#[rustc_args_required_const(4)] -pub unsafe fn _mm512_mask_insertf64x4( - src: __m512d, +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_mask_srl_epi64( + src: __m512i, k: __mmask8, - a: __m512d, - b: __m256d, - imm8: i32, -) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 1); - let b = _mm512_castpd256_pd512(b); - let insert = match imm8 & 0b1 { - 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), - _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), - }; - transmute(simd_select_bitmask(k, insert, src.as_f64x8())) + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_srl_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Copy a to tmp, then insert 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_insertf64x4&expand=3169) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] -#[rustc_args_required_const(3)] -pub unsafe fn _mm512_maskz_insertf64x4(k: __mmask8, a: __m512d, b: __m256d, imm8: i32) -> __m512d { - assert!(imm8 >= 0 && imm8 <= 1); - let b = _mm512_castpd256_pd512(b); - let insert = match imm8 & 0b1 { - 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), - _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), - }; - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, insert, zero)) +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_maskz_srl_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_srl_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Unpack and interleave 32-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst. +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_epi32&expand=6021) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi32&expand=5407) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhps))] //should be vpunpckhdq -pub unsafe fn _mm512_unpackhi_epi32(a: __m512i, b: __m512i) -> __m512i { - let a = a.as_i32x16(); - let b = b.as_i32x16(); - let r: i32x16 = simd_shuffle16( - a, - b, - [ - 2, - 18, - 3, - 19, - 2 + 4, - 18 + 4, - 3 + 4, - 19 + 4, - 2 + 8, - 18 + 8, - 3 + 8, - 19 + 8, - 2 + 12, - 18 + 12, - 3 + 12, - 19 + 12, - ], - ); - transmute(r) +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_sra_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrad(a.as_i32x16(), count.as_i32x4())) } -/// Unpack and interleave 32-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_epi32&expand=6019) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi32&expand=5405) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpckhdq))] -pub unsafe fn _mm512_mask_unpackhi_epi32( +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_mask_sra_epi32( src: __m512i, k: __mmask16, a: __m512i, - b: __m512i, + count: __m128i, ) -> __m512i { - let unpackhi = _mm512_unpackhi_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, unpackhi, src.as_i32x16())) + let shf = _mm512_sra_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Unpack and interleave 32-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_epi32&expand=6020) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi32&expand=5406) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpckhdq))] -pub unsafe fn _mm512_maskz_unpackhi_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let unpackhi = _mm512_unpackhi_epi32(a, b).as_i32x16(); +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_maskz_sra_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sra_epi32(a, count).as_i32x16(); let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, unpackhi, zero)) + transmute(simd_select_bitmask(k, shf, zero)) } -/// Unpack and interleave 64-bit integers from the high half of each 128-bit lane in a and b, and -/// store the results in dst. +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_epi64&expand=6030) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi64&expand=5416) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhpd))] //should be vpunpckhqdq -pub unsafe fn _mm512_unpackhi_epi64(a: __m512i, b: __m512i) -> __m512i { - simd_shuffle8(a, b, [1, 9, 1 + 2, 9 + 2, 1 + 4, 9 + 4, 1 + 6, 9 + 6]) +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_sra_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsraq(a.as_i64x8(), count.as_i64x2())) } -/// Unpack and interleave 64-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_epi64&expand=6028) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi64&expand=5414) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpckhqdq))] -pub unsafe fn _mm512_mask_unpackhi_epi64( +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_mask_sra_epi64( src: __m512i, k: __mmask8, a: __m512i, - b: __m512i, + count: __m128i, ) -> __m512i { - let unpackhi = _mm512_unpackhi_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, unpackhi, src.as_i64x8())) + let shf = _mm512_sra_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Unpack and interleave 64-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_epi64&expand=6029) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi64&expand=5415) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpckhqdq))] -pub unsafe fn _mm512_maskz_unpackhi_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let unpackhi = _mm512_unpackhi_epi64(a, b).as_i64x8(); +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_maskz_sra_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sra_epi64(a, count).as_i64x8(); let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, unpackhi, zero)) + transmute(simd_select_bitmask(k, shf, zero)) } -/// Unpack and interleave single-precision (32-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst. +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_ps&expand=6060) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi32&expand=5436) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhps))] -pub unsafe fn _mm512_unpackhi_ps(a: __m512, b: __m512) -> __m512 { - simd_shuffle16( - a, - b, - [ - 2, - 18, - 3, - 19, - 2 + 4, - 18 + 4, - 3 + 4, - 19 + 4, - 2 + 8, - 18 + 8, - 3 + 8, - 19 + 8, - 2 + 12, - 18 + 12, - 3 + 12, - 19 + 12, - ], - ) +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srai_epi32(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsraid(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Unpack and interleave single-precision (32-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_ps&expand=6058) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi32&expand=5434) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhps))] -pub unsafe fn _mm512_mask_unpackhi_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { - let unpackhi = _mm512_unpackhi_ps(a, b).as_f32x16(); - transmute(simd_select_bitmask(k, unpackhi, src.as_f32x16())) +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srai_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsraid(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Unpack and interleave single-precision (32-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_ps&expand=6059) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi32&expand=5435) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhps))] -pub unsafe fn _mm512_maskz_unpackhi_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { - let unpackhi = _mm512_unpackhi_ps(a, b).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, unpackhi, zero)) +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srai_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i32x16(); + macro_rules! call { + ($imm8:expr) => { + vpsraid(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Unpack and interleave double-precision (64-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst. +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_pd&expand=6048) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi64&expand=5445) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhpd))] -pub unsafe fn _mm512_unpackhi_pd(a: __m512d, b: __m512d) -> __m512d { - simd_shuffle8(a, b, [1, 9, 1 + 2, 9 + 2, 1 + 4, 9 + 4, 1 + 6, 9 + 6]) +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srai_epi64(a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a, $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Unpack and interleave double-precision (64-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_pd&expand=6046) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi64&expand=5443) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhpd))] -pub unsafe fn _mm512_mask_unpackhi_pd( - src: __m512d, - k: __mmask8, - a: __m512d, - b: __m512d, -) -> __m512d { - let unpackhi = _mm512_unpackhi_pd(a, b).as_f64x8(); - transmute(simd_select_bitmask(k, unpackhi, src.as_f64x8())) +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srai_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Unpack and interleave double-precision (64-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_pd&expand=6047) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi64&expand=5444) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpckhpd))] -pub unsafe fn _mm512_maskz_unpackhi_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { - let unpackhi = _mm512_unpackhi_pd(a, b).as_f64x8(); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, unpackhi, zero)) +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srai_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a, $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Unpack and interleave 32-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst. +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_epi32&expand=6078) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi32&expand=5465) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklps))] //should be vpunpckldq -pub unsafe fn _mm512_unpacklo_epi32(a: __m512i, b: __m512i) -> __m512i { - let a = a.as_i32x16(); - let b = b.as_i32x16(); - let r: i32x16 = simd_shuffle16( - a, - b, - [ - 0, - 16, - 1, - 17, - 0 + 4, - 16 + 4, - 1 + 4, - 17 + 4, - 0 + 8, - 16 + 8, - 1 + 8, - 17 + 8, - 0 + 12, - 16 + 12, - 1 + 12, - 17 + 12, - ], - ); - transmute(r) +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_srav_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsravd(a.as_i32x16(), count.as_i32x16())) } -/// Unpack and interleave 32-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_epi32&expand=6076) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi32&expand=5463) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpckldq))] -pub unsafe fn _mm512_mask_unpacklo_epi32( +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_mask_srav_epi32( src: __m512i, k: __mmask16, a: __m512i, - b: __m512i, + count: __m512i, ) -> __m512i { - let unpackhi = _mm512_unpacklo_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, unpackhi, src.as_i32x16())) + let shf = _mm512_srav_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Unpack and interleave 32-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_epi32&expand=6077) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi32&expand=5464) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpckldq))] -pub unsafe fn _mm512_maskz_unpacklo_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let unpackhi = _mm512_unpacklo_epi32(a, b).as_i32x16(); +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_maskz_srav_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srav_epi32(a, count).as_i32x16(); let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, unpackhi, zero)) + transmute(simd_select_bitmask(k, shf, zero)) } -/// Unpack and interleave 64-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst. +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_epi64&expand=6087) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi64&expand=5474) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklpd))] //should be vpunpcklqdq -pub unsafe fn _mm512_unpacklo_epi64(a: __m512i, b: __m512i) -> __m512i { - simd_shuffle8(a, b, [0, 8, 0 + 2, 8 + 2, 0 + 4, 8 + 4, 0 + 6, 8 + 6]) +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_srav_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsravq(a.as_i64x8(), count.as_i64x8())) } -/// Unpack and interleave 64-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_epi64&expand=6085) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi64&expand=5472) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpcklqdq))] -pub unsafe fn _mm512_mask_unpacklo_epi64( +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_mask_srav_epi64( src: __m512i, k: __mmask8, a: __m512i, - b: __m512i, + count: __m512i, ) -> __m512i { - let unpackhi = _mm512_unpacklo_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, unpackhi, src.as_i64x8())) + let shf = _mm512_srav_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Unpack and interleave 64-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_epi64&expand=6086) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi64&expand=5473) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpunpcklqdq))] -pub unsafe fn _mm512_maskz_unpacklo_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let unpackhi = _mm512_unpacklo_epi64(a, b).as_i64x8(); +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_maskz_srav_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srav_epi64(a, count).as_i64x8(); let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, unpackhi, zero)) + transmute(simd_select_bitmask(k, shf, zero)) } -/// Unpack and interleave single-precision (32-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst. +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_ps&expand=6117) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi32&expand=4703) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklps))] -pub unsafe fn _mm512_unpacklo_ps(a: __m512, b: __m512) -> __m512 { - simd_shuffle16( - a, - b, - [ - 0, - 16, - 1, - 17, - 0 + 4, - 16 + 4, - 1 + 4, - 17 + 4, - 0 + 8, - 16 + 8, - 1 + 8, - 17 + 8, - 0 + 12, - 16 + 12, - 1 + 12, - 17 + 12, - ], - ) +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_rolv_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vprolvd(a.as_i32x16(), b.as_i32x16())) } -/// Unpack and interleave single-precision (32-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_ps&expand=6115) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi32&expand=4701) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklps))] -pub unsafe fn _mm512_mask_unpacklo_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { - let unpackhi = _mm512_unpacklo_ps(a, b).as_f32x16(); - transmute(simd_select_bitmask(k, unpackhi, src.as_f32x16())) +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_mask_rolv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let rol = _mm512_rolv_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, rol, src.as_i32x16())) } -/// Unpack and interleave single-precision (32-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_ps&expand=6116) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi32&expand=4702) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklps))] -pub unsafe fn _mm512_maskz_unpacklo_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { - let unpackhi = _mm512_unpacklo_ps(a, b).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, unpackhi, zero)) +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_maskz_rolv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, rol, zero)) } -/// Unpack and interleave double-precision (64-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst. +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_pd&expand=6105) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi32&expand=4739) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklpd))] -pub unsafe fn _mm512_unpacklo_pd(a: __m512d, b: __m512d) -> __m512d { - simd_shuffle8(a, b, [0, 8, 0 + 2, 8 + 2, 0 + 4, 8 + 4, 0 + 6, 8 + 6]) +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_rorv_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vprorvd(a.as_i32x16(), b.as_i32x16())) } -/// Unpack and interleave double-precision (64-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_pd&expand=6103) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi32&expand=4737) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklpd))] -pub unsafe fn _mm512_mask_unpacklo_pd( - src: __m512d, - k: __mmask8, - a: __m512d, - b: __m512d, -) -> __m512d { - let unpackhi = _mm512_unpacklo_pd(a, b).as_f64x8(); - transmute(simd_select_bitmask(k, unpackhi, src.as_f64x8())) +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_mask_rorv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let ror = _mm512_rorv_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, ror, src.as_i32x16())) } -/// Unpack and interleave double-precision (64-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_pd&expand=6104) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi32&expand=4738) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vunpcklpd))] -pub unsafe fn _mm512_maskz_unpacklo_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { - let unpackhi = _mm512_unpacklo_pd(a, b).as_f64x8(); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, unpackhi, zero)) +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_maskz_rorv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, ror, zero)) } -/// Cast vector of type __m128 to type __m512; the upper 384 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps128_ps512&expand=621) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi64&expand=4712) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castps128_ps512(a: __m128) -> __m512 { - simd_shuffle16( - a, - _mm_set1_ps(-1.), - [0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], - ) +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_rolv_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vprolvq(a.as_i64x8(), b.as_i64x8())) } -/// Cast vector of type __m256 to type __m512; the upper 256 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps256_ps512&expand=623) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi64&expand=4710) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castps256_ps512(a: __m256) -> __m512 { - simd_shuffle16( - a, - _mm256_set1_ps(-1.), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8], - ) +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_mask_rolv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, rol, src.as_i64x8())) } -/// Cast vector of type __m512 to type __m128. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps512_ps128&expand=624) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi64&expand=4711) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castps512_ps128(a: __m512) -> __m128 { - simd_shuffle4(a, a, [0, 1, 2, 3]) +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_maskz_rolv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, rol, zero)) } -/// Cast vector of type __m512 to type __m256. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps512_ps256&expand=625) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi64&expand=4748) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castps512_ps256(a: __m512) -> __m256 { - simd_shuffle8(a, a, [0, 1, 2, 3, 4, 5, 6, 7]) +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_rorv_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vprorvq(a.as_i64x8(), b.as_i64x8())) } -/// Cast vector of type __m512 to type __m512d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps_pd&expand=616) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi64&expand=4746) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castps_pd(a: __m512) -> __m512d { - transmute(a.as_m512()) +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_mask_rorv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, ror, src.as_i64x8())) } -/// Cast vector of type __m512 to type __m512i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps_si512&expand=619) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi64&expand=4747) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castps_si512(a: __m512) -> __m512i { - transmute(a.as_m512()) +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_maskz_rorv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, ror, zero)) } -/// Cast vector of type __m128d to type __m512d; the upper 384 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd128_pd512&expand=609) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi32&expand=5342) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castpd128_pd512(a: __m128d) -> __m512d { - simd_shuffle8(a, _mm_set1_pd(-1.), [0, 1, 2, 2, 2, 2, 2, 2]) +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_sllv_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsllvd(a.as_i32x16(), count.as_i32x16())) } -/// Cast vector of type __m256d to type __m512d; the upper 256 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd256_pd512&expand=611) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi32&expand=5340) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castpd256_pd512(a: __m256d) -> __m512d { - simd_shuffle8(a, _mm256_set1_pd(-1.), [0, 1, 2, 3, 4, 4, 4, 4]) +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_mask_sllv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_sllv_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Cast vector of type __m512d to type __m128d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd512_pd128&expand=612) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi32&expand=5341) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castpd512_pd128(a: __m512d) -> __m128d { - simd_shuffle2(a, a, [0, 1]) +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_maskz_sllv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_sllv_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Cast vector of type __m512d to type __m256d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd512_pd256&expand=613) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi32&expand=5554) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castpd512_pd256(a: __m512d) -> __m256d { - simd_shuffle4(a, a, [0, 1, 2, 3]) +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_srlv_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsrlvd(a.as_i32x16(), count.as_i32x16())) } -/// Cast vector of type __m512d to type __m512. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd_ps&expand=604) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srlv_epi32&expand=5552) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castpd_ps(a: __m512d) -> __m512 { - transmute(a.as_m512d()) +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_mask_srlv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srlv_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) } -/// Cast vector of type __m512d to type __m512i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd_si512&expand=607) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi32&expand=5553) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castpd_si512(a: __m512d) -> __m512i { - transmute(a.as_m512d()) +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_maskz_srlv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srlv_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Cast vector of type __m128i to type __m512i; the upper 384 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi128_si512&expand=629) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi64&expand=5351) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castsi128_si512(a: __m128i) -> __m512i { - simd_shuffle8(a, _mm_set1_epi64x(-1), [0, 1, 2, 2, 2, 2, 2, 2]) +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_sllv_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsllvq(a.as_i64x8(), count.as_i64x8())) } -/// Cast vector of type __m256i to type __m512i; the upper 256 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi256_si512&expand=633) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi64&expand=5349) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castsi256_si512(a: __m256i) -> __m512i { - simd_shuffle8(a, _mm256_set1_epi64x(-1), [0, 1, 2, 3, 4, 4, 4, 4]) +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_mask_sllv_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_sllv_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Cast vector of type __m512i to type __m128i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_si128&expand=636) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi64&expand=5350) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castsi512_si128(a: __m512i) -> __m128i { - simd_shuffle2(a, a, [0, 1]) +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_maskz_sllv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_sllv_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Cast vector of type __m512i to type __m256i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_si256&expand=637) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi64&expand=5563) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castsi512_si256(a: __m512i) -> __m256i { - simd_shuffle4(a, a, [0, 1, 2, 3]) +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_srlv_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsrlvq(a.as_i64x8(), count.as_i64x8())) } -/// Cast vector of type __m512i to type __m512. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_ps&expand=635) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mask_srlv_epi64&expand=5561) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castsi512_ps(a: __m512i) -> __m512 { - transmute(a) +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_mask_srlv_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srlv_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) } -/// Cast vector of type __m512i to type __m512d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_pd&expand=634) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi64&expand=5562) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_castsi512_pd(a: __m512i) -> __m512d { - transmute(a) +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_maskz_srlv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srlv_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) } -/// Broadcast the low packed 32-bit integer from a to all elements of dst. +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastd_epi32&expand=545) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_ps&expand=4170) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcast))] //should be vpbroadcastd -pub unsafe fn _mm512_broadcastd_epi32(a: __m128i) -> __m512i { - let a = _mm512_castsi128_si512(a).as_i32x16(); - let ret: i32x16 = simd_shuffle16(a, a, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - transmute(ret) +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permute_ps(a: __m512, imm8: i32) -> __m512 { + let a = a.as_f32x16(); + macro_rules! call { + ($imm8:expr) => { + vpermilps(a, _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Broadcast the low packed 32-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastd_epi32&expand=546) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_ps&expand=4168) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastd -pub unsafe fn _mm512_mask_broadcastd_epi32(src: __m512i, k: __mmask16, a: __m128i) -> __m512i { - let broadcast = _mm512_broadcastd_epi32(a).as_i32x16(); - transmute(simd_select_bitmask(k, broadcast, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permute_ps(src: __m512, k: __mmask16, a: __m512, imm8: i32) -> __m512 { + let a = a.as_f32x16(); + macro_rules! call { + ($imm8:expr) => { + vpermilps(a, _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) } -/// Broadcast the low packed 32-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastd_epi32&expand=547) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_ps&expand=4169) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastd -pub unsafe fn _mm512_maskz_broadcastd_epi32(k: __mmask16, a: __m128i) -> __m512i { - let broadcast = _mm512_broadcastd_epi32(a).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, broadcast, zero)) +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permute_ps(k: __mmask16, a: __m512, imm8: i32) -> __m512 { + let a = a.as_f32x16(); + macro_rules! call { + ($imm8:expr) => { + vpermilps(a, _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Broadcast the low packed 64-bit integer from a to all elements of dst. +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastq_epi64&expand=560) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_pd&expand=4161) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcas))] //should be vpbroadcastq -pub unsafe fn _mm512_broadcastq_epi64(a: __m128i) -> __m512i { - simd_shuffle8(a, a, [0, 0, 0, 0, 0, 0, 0, 0]) +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permute_pd(a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Broadcast the low packed 64-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastq_epi64&expand=561) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_pd&expand=4159) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastq -pub unsafe fn _mm512_mask_broadcastq_epi64(src: __m512i, k: __mmask8, a: __m128i) -> __m512i { - let broadcast = _mm512_broadcastq_epi64(a).as_i64x8(); - transmute(simd_select_bitmask(k, broadcast, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permute_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) } -/// Broadcast the low packed 64-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastq_epi64&expand=562) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_pd&expand=4160) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastq -pub unsafe fn _mm512_maskz_broadcastq_epi64(k: __mmask8, a: __m128i) -> __m512i { - let broadcast = _mm512_broadcastq_epi64(a).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, broadcast, zero)) +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permute_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Broadcast the low single-precision (32-bit) floating-point element from a to all elements of dst. +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastss_ps&expand=578) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_epi64&expand=4208) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcastss))] -pub unsafe fn _mm512_broadcastss_ps(a: __m128) -> __m512 { - simd_shuffle16(a, a, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] +//shoud be vpermq, but generate vpermpd. It generates vpermq with mask. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permutex_epi64(a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermq(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Broadcast the low single-precision (32-bit) floating-point element from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastss_ps&expand=579) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_epi64&expand=4206) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcastss))] -pub unsafe fn _mm512_mask_broadcastss_ps(src: __m512, k: __mmask16, a: __m128) -> __m512 { - let broadcast = _mm512_broadcastss_ps(a).as_f32x16(); - transmute(simd_select_bitmask(k, broadcast, src.as_f32x16())) +#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permutex_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + imm8: i32, +) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermq(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_i64x8())) } -/// Broadcast the low single-precision (32-bit) floating-point element from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastss_ps&expand=580) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_epi64&expand=4207) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcastss))] -pub unsafe fn _mm512_maskz_broadcastss_ps(k: __mmask16, a: __m128) -> __m512 { - let broadcast = _mm512_broadcastss_ps(a).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, broadcast, zero)) +#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permutex_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + let a = a.as_i64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermq(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Broadcast the low double-precision (64-bit) floating-point element from a to all elements of dst. +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastsd_pd&expand=567) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_pd&expand=4214) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcastsd))] -pub unsafe fn _mm512_broadcastsd_pd(a: __m128d) -> __m512d { - simd_shuffle8(a, a, [1, 1, 1, 1, 1, 1, 1, 1]) +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permutex_pd(a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermpd(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) } -/// Broadcast the low double-precision (64-bit) floating-point element from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastsd_pd&expand=568) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_pd&expand=4212) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcastsd))] -pub unsafe fn _mm512_mask_broadcastsd_pd(src: __m512d, k: __mmask8, a: __m128d) -> __m512d { - let broadcast = _mm512_broadcastsd_pd(a).as_f64x8(); - transmute(simd_select_bitmask(k, broadcast, src.as_f64x8())) +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permutex_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermpd(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) } -/// Broadcast the low double-precision (64-bit) floating-point element from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastsd_pd&expand=569) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_pd&expand=4213) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vbroadcastsd))] -pub unsafe fn _mm512_maskz_broadcastsd_pd(k: __mmask8, a: __m128d) -> __m512d { - let broadcast = _mm512_broadcastsd_pd(a).as_f64x8(); +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permutex_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + let a = a.as_f64x8(); + macro_rules! call { + ($imm8:expr) => { + vpermpd(a, _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, broadcast, zero)) + transmute(simd_select_bitmask(k, permute, zero)) } -/// Broadcast the 4 packed 32-bit integers from a to all elements of dst. +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_permutexvar_epi32, and it is recommended that you use that intrinsic name. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_i32x4&expand=510) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_epi32&expand=4182) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcasti32x4, linux: vshuf -pub unsafe fn _mm512_broadcast_i32x4(a: __m128i) -> __m512i { - let a = _mm512_castsi128_si512(a).as_i32x16(); - let ret: i32x16 = simd_shuffle16(a, a, [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]); - transmute(ret) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask +pub unsafe fn _mm512_permutevar_epi32(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) } -/// Broadcast the 4 packed 32-bit integers from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_mask_permutexvar_epi32, and it is recommended that you use that intrinsic name. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_i32x4&expand=511) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_epi32&expand=4181) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcasti32x4, linux: vshuf -pub unsafe fn _mm512_mask_broadcast_i32x4(src: __m512i, k: __mmask16, a: __m128i) -> __m512i { - let broadcast = _mm512_broadcast_i32x4(a).as_i32x16(); - transmute(simd_select_bitmask(k, broadcast, src.as_i32x16())) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_mask_permutevar_epi32( + src: __m512i, + k: __mmask16, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutevar_epi32(idx, a).as_i32x16(); + transmute(simd_select_bitmask(k, permute, src.as_i32x16())) } -/// Broadcast the 4 packed 32-bit integers from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_i32x4&expand=512) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcasti32x4, linux: vshuf -pub unsafe fn _mm512_maskz_broadcast_i32x4(k: __mmask16, a: __m128i) -> __m512i { - let broadcast = _mm512_broadcast_i32x4(a).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, broadcast, zero)) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_permutevar_ps(a: __m512, b: __m512i) -> __m512 { + transmute(vpermilps(a.as_f32x16(), b.as_i32x16())) } -/// Broadcast the 4 packed 64-bit integers from a to all elements of dst. +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_i64x4&expand=522) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_ps&expand=4198) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcasti64x4, linux: vperm -pub unsafe fn _mm512_broadcast_i64x4(a: __m256i) -> __m512i { - simd_shuffle8(a, a, [0, 1, 2, 3, 0, 1, 2, 3]) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_mask_permutevar_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512i, +) -> __m512 { + let permute = _mm512_permutevar_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) } -/// Broadcast the 4 packed 64-bit integers from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_i64x4&expand=523) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_ps&expand=4199) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcasti64x4, linux: vperm -pub unsafe fn _mm512_mask_broadcast_i64x4(src: __m512i, k: __mmask8, a: __m256i) -> __m512i { - let broadcast = _mm512_broadcast_i64x4(a).as_i64x8(); - transmute(simd_select_bitmask(k, broadcast, src.as_i64x8())) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_maskz_permutevar_ps(k: __mmask16, a: __m512, b: __m512i) -> __m512 { + let permute = _mm512_permutevar_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Broadcast the 4 packed 64-bit integers from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_i64x4&expand=524) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_pd&expand=4191) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcasti64x4, linux: vperm -pub unsafe fn _mm512_maskz_broadcast_i64x4(k: __mmask8, a: __m256i) -> __m512i { - let broadcast = _mm512_broadcast_i64x4(a).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, broadcast, zero)) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_permutevar_pd(a: __m512d, b: __m512i) -> __m512d { + transmute(vpermilpd(a.as_f64x8(), b.as_i64x8())) } -/// Broadcast the 4 packed single-precision (32-bit) floating-point elements from a to all elements of dst. +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_f32x4&expand=483) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_pd&expand=4189) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcastf32x4, linux: vshuf -pub unsafe fn _mm512_broadcast_f32x4(a: __m128) -> __m512 { - simd_shuffle16(a, a, [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_mask_permutevar_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512i, +) -> __m512d { + let permute = _mm512_permutevar_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) } -/// Broadcast the 4 packed single-precision (32-bit) floating-point elements from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_f32x4&expand=484) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_pd&expand=4190) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcastf32x4, linux: vshu -pub unsafe fn _mm512_mask_broadcast_f32x4(src: __m512, k: __mmask16, a: __m128) -> __m512 { - let broadcast = _mm512_broadcast_f32x4(a).as_f32x16(); - transmute(simd_select_bitmask(k, broadcast, src.as_f32x16())) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_maskz_permutevar_pd(k: __mmask8, a: __m512d, b: __m512i) -> __m512d { + let permute = _mm512_permutevar_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Broadcast the 4 packed single-precision (32-bit) floating-point elements from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_f32x4&expand=485) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi32&expand=4301) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcastf32x4, linux: vshu -pub unsafe fn _mm512_maskz_broadcast_f32x4(k: __mmask16, a: __m128) -> __m512 { - let broadcast = _mm512_broadcast_f32x4(a).as_f32x16(); - let zero = _mm512_setzero_ps().as_f32x16(); - transmute(simd_select_bitmask(k, broadcast, zero)) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask +pub unsafe fn _mm512_permutexvar_epi32(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) } -/// Broadcast the 4 packed double-precision (64-bit) floating-point elements from a to all elements of dst. +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_f64x4&expand=495) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi32&expand=4299) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcastf64x4, linux: vperm -pub unsafe fn _mm512_broadcast_f64x4(a: __m256d) -> __m512d { - simd_shuffle8(a, a, [0, 1, 2, 3, 0, 1, 2, 3]) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_mask_permutexvar_epi32( + src: __m512i, + k: __mmask16, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); + transmute(simd_select_bitmask(k, permute, src.as_i32x16())) } -/// Broadcast the 4 packed double-precision (64-bit) floating-point elements from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_f64x4&expand=496) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi32&expand=4300) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcastf64x4, linux: vper -pub unsafe fn _mm512_mask_broadcast_f64x4(src: __m512d, k: __mmask8, a: __m256d) -> __m512d { - let broadcast = _mm512_broadcast_f64x4(a).as_f64x8(); - transmute(simd_select_bitmask(k, broadcast, src.as_f64x8())) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_maskz_permutexvar_epi32(k: __mmask16, idx: __m512i, a: __m512i) -> __m512i { + let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Broadcast the 4 packed double-precision (64-bit) floating-point elements from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_f64x4&expand=497) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi64&expand=4307) #[inline] -#[target_feature(enable = "avx512f")] //msvc: vbroadcastf64x4, linux: vper -pub unsafe fn _mm512_maskz_broadcast_f64x4(k: __mmask8, a: __m256d) -> __m512d { - let broadcast = _mm512_broadcast_f64x4(a).as_f64x8(); - let zero = _mm512_setzero_pd().as_f64x8(); - transmute(simd_select_bitmask(k, broadcast, zero)) +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermq, but generate vpermpd. It generates vpermd with mask +pub unsafe fn _mm512_permutexvar_epi64(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermq(a.as_i64x8(), idx.as_i64x8())) } -/// Blend packed 32-bit integers from a and b using control mask k, and store the results in dst. +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_epi32&expand=435) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi64&expand=4305) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovdqa32))] //should be vpblendmd -pub unsafe fn _mm512_mask_blend_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - transmute(simd_select_bitmask(k, b.as_i32x16(), a.as_i32x16())) +#[cfg_attr(test, assert_instr(vpermq))] +pub unsafe fn _mm512_mask_permutexvar_epi64( + src: __m512i, + k: __mmask8, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); + transmute(simd_select_bitmask(k, permute, src.as_i64x8())) } -/// Blend packed 64-bit integers from a and b using control mask k, and store the results in dst. +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_epi64&expand=438) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi64&expand=4306) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovdqa64))] //should be vpblendmq -pub unsafe fn _mm512_mask_blend_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - transmute(simd_select_bitmask(k, b.as_i64x8(), a.as_i64x8())) +#[cfg_attr(test, assert_instr(vpermq))] +pub unsafe fn _mm512_maskz_permutexvar_epi64(k: __mmask8, idx: __m512i, a: __m512i) -> __m512i { + let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Blend packed single-precision (32-bit) floating-point elements from a and b using control mask k, and store the results in dst. +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_ps&expand=451) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovaps))] //should be vpblendmps -pub unsafe fn _mm512_mask_blend_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { - transmute(simd_select_bitmask(k, b.as_f32x16(), a.as_f32x16())) +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_permutexvar_ps(idx: __m512i, a: __m512) -> __m512 { + transmute(vpermps(a.as_f32x16(), idx.as_i32x16())) } -/// Blend packed double-precision (64-bit) floating-point elements from a and b using control mask k, and store the results in dst. +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_pd&expand=446) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_ps&expand=4326) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovapd))] //should be vpblendmpd -pub unsafe fn _mm512_mask_blend_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { - transmute(simd_select_bitmask(k, b.as_f64x8(), a.as_f64x8())) +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_mask_permutexvar_ps( + src: __m512, + k: __mmask16, + idx: __m512i, + a: __m512, +) -> __m512 { + let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) } -/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst. +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi32&expand=272) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_ps&expand=4327) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandq))] //should be vpandd, but generate vpandq -pub unsafe fn _mm512_and_epi32(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_and(a.as_i32x16(), b.as_i32x16())) -} - -/// Performs element-by-element bitwise AND between packed 32-bit integer elements of v2 and v3, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi32&expand=273) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandd))] -pub unsafe fn _mm512_mask_and_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let and = _mm512_and_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, and, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_maskz_permutexvar_ps(k: __mmask16, idx: __m512i, a: __m512) -> __m512 { + let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_epi32&expand=274) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_pd&expand=4322) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandd))] -pub unsafe fn _mm512_maskz_and_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let and = _mm512_and_epi32(a, b).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, and, zero)) +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_permutexvar_pd(idx: __m512i, a: __m512d) -> __m512d { + transmute(vpermpd(a.as_f64x8(), idx.as_i64x8())) } -/// Compute the bitwise AND of 512 bits (composed of packed 64-bit integers) in a and b, and store the results in dst. +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi64&expand=279) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_pd&expand=4320) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandq))] -pub unsafe fn _mm512_and_epi64(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_and(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_mask_permutexvar_pd( + src: __m512d, + k: __mmask8, + idx: __m512i, + a: __m512d, +) -> __m512d { + let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) } -/// Compute the bitwise AND of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi64&expand=280) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_pd&expand=4321) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandq))] -pub unsafe fn _mm512_mask_and_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let and = _mm512_and_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, and, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_maskz_permutexvar_pd(k: __mmask8, idx: __m512i, a: __m512d) -> __m512d { + let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_Epi32&expand=274) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi32&expand=4238) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandq))] -pub unsafe fn _mm512_maskz_and_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let and = _mm512_and_epi64(a, b).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, and, zero)) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d +pub unsafe fn _mm512_permutex2var_epi32(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { + transmute(vpermi2d(a.as_i32x16(), idx.as_i32x16(), b.as_i32x16())) } -/// Compute the bitwise AND of 512 bits (representing integer data) in a and b, and store the result in dst. +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_si512&expand=302) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi32&expand=4235) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandq))] -pub unsafe fn _mm512_and_si512(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_and(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vpermt2d))] +pub unsafe fn _mm512_mask_permutex2var_epi32( + a: __m512i, + k: __mmask16, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + transmute(simd_select_bitmask(k, permute, a.as_i32x16())) } -/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst. +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi32&expand=4042) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi32&expand=4237) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vporq))] -pub unsafe fn _mm512_or_epi32(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d +pub unsafe fn _mm512_maskz_permutex2var_epi32( + k: __mmask16, + a: __m512i, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi32&expand=4040) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi32&expand=4236) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpord))] -pub unsafe fn _mm512_mask_or_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let or = _mm512_or_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, or, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vpermi2d))] +pub unsafe fn _mm512_mask2_permutex2var_epi32( + a: __m512i, + idx: __m512i, + k: __mmask16, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + transmute(simd_select_bitmask(k, permute, idx.as_i32x16())) } -/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi32&expand=4041) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi64&expand=4250) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpord))] -pub unsafe fn _mm512_maskz_or_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let or = _mm512_or_epi32(a, b).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, or, zero)) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q +pub unsafe fn _mm512_permutex2var_epi64(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { + transmute(vpermi2q(a.as_i64x8(), idx.as_i64x8(), b.as_i64x8())) } -/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the resut in dst. +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi64&expand=4051) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi64&expand=4247) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vporq))] -pub unsafe fn _mm512_or_epi64(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_or(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vpermt2q))] +pub unsafe fn _mm512_mask_permutex2var_epi64( + a: __m512i, + k: __mmask8, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + transmute(simd_select_bitmask(k, permute, a.as_i64x8())) } -/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi64&expand=4049) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi64&expand=4249) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vporq))] -pub unsafe fn _mm512_mask_or_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let or = _mm512_or_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, or, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q +pub unsafe fn _mm512_maskz_permutex2var_epi64( + k: __mmask8, + a: __m512i, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi64&expand=4050) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi64&expand=4248) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vporq))] -pub unsafe fn _mm512_maskz_or_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let or = _mm512_or_epi64(a, b).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, or, zero)) +#[cfg_attr(test, assert_instr(vpermi2q))] +pub unsafe fn _mm512_mask2_permutex2var_epi64( + a: __m512i, + idx: __m512i, + k: __mmask8, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + transmute(simd_select_bitmask(k, permute, idx.as_i64x8())) } -/// Compute the bitwise OR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_si512&expand=4072) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_ps&expand=4286) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vporq))] -pub unsafe fn _mm512_or_si512(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps +pub unsafe fn _mm512_permutex2var_ps(a: __m512, idx: __m512i, b: __m512) -> __m512 { + transmute(vpermi2ps(a.as_f32x16(), idx.as_i32x16(), b.as_f32x16())) } -/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst. +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi32&expand=6142) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_ps&expand=4283) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpxorq))] -pub unsafe fn _mm512_xor_epi32(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vpermt2ps))] +pub unsafe fn _mm512_mask_permutex2var_ps( + a: __m512, + k: __mmask16, + idx: __m512i, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + transmute(simd_select_bitmask(k, permute, a.as_f32x16())) } -/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi32&expand=6140) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_ps&expand=4285) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpxord))] -pub unsafe fn _mm512_mask_xor_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let xor = _mm512_xor_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, xor, src.as_i32x16())) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps +pub unsafe fn _mm512_maskz_permutex2var_ps( + k: __mmask16, + a: __m512, + idx: __m512i, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi32&expand=6141) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_ps&expand=4284) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpxord))] -pub unsafe fn _mm512_maskz_xor_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let xor = _mm512_xor_epi32(a, b).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, xor, zero)) +#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2ps, but it shows vpermt2ps +pub unsafe fn _mm512_mask2_permutex2var_ps( + a: __m512, + idx: __m512i, + k: __mmask16, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst. +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi64&expand=6151) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_pd&expand=4274) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpxorq))] -pub unsafe fn _mm512_xor_epi64(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_xor(a.as_i64x8(), b.as_i64x8())) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd +pub unsafe fn _mm512_permutex2var_pd(a: __m512d, idx: __m512i, b: __m512d) -> __m512d { + transmute(vpermi2pd(a.as_f64x8(), idx.as_i64x8(), b.as_f64x8())) } -/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi64&expand=6149) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_pd&expand=4271) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpxorq))] -pub unsafe fn _mm512_mask_xor_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let xor = _mm512_xor_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, xor, src.as_i64x8())) +#[cfg_attr(test, assert_instr(vpermt2pd))] +pub unsafe fn _mm512_mask_permutex2var_pd( + a: __m512d, + k: __mmask8, + idx: __m512i, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + transmute(simd_select_bitmask(k, permute, a.as_f64x8())) } -/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi64&expand=6150) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_pd&expand=4273) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpxorq))] -pub unsafe fn _mm512_maskz_xor_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let xor = _mm512_xor_epi64(a, b).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, xor, zero)) +#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd +pub unsafe fn _mm512_maskz_permutex2var_pd( + k: __mmask8, + a: __m512d, + idx: __m512i, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise XOR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set) /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_si512&expand=6172) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_pd&expand=4272) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpxorq))] -pub unsafe fn _mm512_xor_si512(a: __m512i, b: __m512i) -> __m512i { - transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2pd, but it shows vpermt2pd +pub unsafe fn _mm512_mask2_permutex2var_pd( + a: __m512d, + idx: __m512i, + k: __mmask8, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) } -/// Compute the bitwise NOT of packed 32-bit integers in a and then AND with b, and store the results in dst. +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_andnot_epi32&expand=310) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_epi32&expand=5150) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandnq))] //should be vpandnd -pub unsafe fn _mm512_andnot_epi32(a: __m512i, b: __m512i) -> __m512i { - _mm512_and_epi32(_mm512_xor_epi32(a, _mm512_set1_epi32(u32::MAX as i32)), b) +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_shuffle_epi32(a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let r: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + transmute(r) } -/// Compute the bitwise NOT of packed 32-bit integers in a and then AND with b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_andnot_epi32&expand=311) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_epi32&expand=5148) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandnd))] -pub unsafe fn _mm512_mask_andnot_epi32( +#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_shuffle_epi32( src: __m512i, k: __mmask16, a: __m512i, - b: __m512i, + imm8: _MM_PERM_ENUM, ) -> __m512i { - let andnot = _mm512_andnot_epi32(a, b).as_i32x16(); - transmute(simd_select_bitmask(k, andnot, src.as_i32x16())) -} - -/// Compute the bitwise NOT of packed 32-bit integers in a and then AND with b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_andnot_epi32&expand=312) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandnd))] -pub unsafe fn _mm512_maskz_andnot_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { - let andnot = _mm512_andnot_epi32(a, b).as_i32x16(); - let zero = _mm512_setzero_si512().as_i32x16(); - transmute(simd_select_bitmask(k, andnot, zero)) -} + let imm8 = (imm8 & 0xFF) as u8; -/// Compute the bitwise NOT of 512 bits (composed of packed 64-bit integers) in a and then AND with b, and store the results in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_andnot_epi64&expand=317) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandnq))] //should be vpandnd -pub unsafe fn _mm512_andnot_epi64(a: __m512i, b: __m512i) -> __m512i { - _mm512_and_epi64(_mm512_xor_epi64(a, _mm512_set1_epi64(u64::MAX as i64)), b) + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) } -/// Compute the bitwise NOT of packed 64-bit integers in a and then AND with b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_andnot_epi64&expand=318) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_epi32&expand=5149) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandnq))] -pub unsafe fn _mm512_mask_andnot_epi64( - src: __m512i, - k: __mmask8, - a: __m512i, - b: __m512i, -) -> __m512i { - let andnot = _mm512_andnot_epi64(a, b).as_i64x8(); - transmute(simd_select_bitmask(k, andnot, src.as_i64x8())) -} +#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_shuffle_epi32(k: __mmask16, a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; -/// Compute the bitwise NOT of packed 64-bit integers in a and then AND with b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_andnot_epi64&expand=319) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandnq))] -pub unsafe fn _mm512_maskz_andnot_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { - let andnot = _mm512_andnot_epi64(a, b).as_i64x8(); - let zero = _mm512_setzero_si512().as_i64x8(); - transmute(simd_select_bitmask(k, andnot, zero)) -} - -/// Compute the bitwise NOT of 512 bits (representing integer data) in a and then AND with b, and store the result in dst. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_andnot_si512&expand=340) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpandnq))] -pub unsafe fn _mm512_andnot_si512(a: __m512i, b: __m512i) -> __m512i { - _mm512_and_epi64(_mm512_xor_epi64(a, _mm512_set1_epi64(u64::MAX as i64)), b) + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) } -/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kand_mask16&expand=3212) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_ps&expand=5203) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw -pub unsafe fn _kand_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { - transmute(a & b) +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_ps(a: __m512, b: __m512, imm8: i32) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + } } -/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kand&expand=3210) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_ps&expand=5201) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw -pub unsafe fn _mm512_kand(a: __mmask16, b: __mmask16) -> __mmask16 { - transmute(a & b) -} +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + imm8: i32, +) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; -/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kor_mask16&expand=3239) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw -pub unsafe fn _kor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { - transmute(a | b) + transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) } -/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kor&expand=3237) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_ps&expand=5202) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw -pub unsafe fn _mm512_kor(a: __mmask16, b: __mmask16) -> __mmask16 { - transmute(a | b) -} - -/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxor_mask16&expand=3291) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw -pub unsafe fn _kxor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { - transmute(a ^ b) -} +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_ps(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; -/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxor&expand=3289) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw -pub unsafe fn _mm512_kxor(a: __mmask16, b: __mmask16) -> __mmask16 { - transmute(a ^ b) + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) } -/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=knot_mask16&expand=3233) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_pd&expand=5192) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _knot_mask16(a: __mmask16) -> __mmask16 { - transmute(a ^ 0b11111111_11111111) +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_pd(a: __m512d, b: __m512d, imm8: i32) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + } } -/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_knot&expand=3231) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_pd&expand=5190) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_knot(a: __mmask16) -> __mmask16 { - transmute(a ^ 0b11111111_11111111) +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + let shuffle = match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) } -/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kandn_mask16&expand=3218) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_pd&expand=5191) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(not))] // generate normal and, not code instead of kandnw -pub unsafe fn _kandn_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { - _mm512_kand(_mm512_knot(a), b) -} - -/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kandn&expand=3216) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandw -pub unsafe fn _mm512_kandn(a: __mmask16, b: __mmask16) -> __mmask16 { - _mm512_kand(_mm512_knot(a), b) +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_pd(k: __mmask8, a: __m512d, b: __m512d, imm8: i32) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + let shuffle = match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + }; + + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) } -/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxnor_mask16&expand=3285) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i32&expand=5177) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(xor))] // generate normal xor, not code instead of kxnorw -pub unsafe fn _kxnor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { - _mm512_knot(_mm512_kxor(a, b)) +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] //should be vshufi32x4, but generate vshufi64x2 +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_i32x4(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let r: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(r) } -/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxnor&expand=3283) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i32x&expand=5175) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kandw -pub unsafe fn _mm512_kxnor(a: __mmask16, b: __mmask16) -> __mmask16 { - _mm512_knot(_mm512_kxor(a, b)) +#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_i32x4( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) } -/// Copy 16-bit mask a to k. +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm512_kmov&expand=3228) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i32&expand=5176) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kmovw -pub unsafe fn _mm512_kmov(a: __mmask16) -> __mmask16 { - let r: u16 = a; - transmute(r) -} - -/// Sets packed 32-bit integers in `dst` with the supplied values. -/// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set_ps( - e0: f32, - e1: f32, - e2: f32, - e3: f32, - e4: f32, - e5: f32, - e6: f32, - e7: f32, - e8: f32, - e9: f32, - e10: f32, - e11: f32, - e12: f32, - e13: f32, - e14: f32, - e15: f32, -) -> __m512 { - _mm512_setr_ps( - e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, - ) -} - -/// Sets packed 32-bit integers in `dst` with the supplied values in -/// reverse order. -/// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_setr_ps( - e0: f32, - e1: f32, - e2: f32, - e3: f32, - e4: f32, - e5: f32, - e6: f32, - e7: f32, - e8: f32, - e9: f32, - e10: f32, - e11: f32, - e12: f32, - e13: f32, - e14: f32, - e15: f32, -) -> __m512 { - let r = f32x16::new( - e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, - ); - transmute(r) -} - -/// Broadcast 64-bit float `a` to all elements of `dst`. -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_pd(a: f64) -> __m512d { - transmute(f64x8::splat(a)) -} - -/// Broadcast 32-bit float `a` to all elements of `dst`. -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_ps(a: f32) -> __m512 { - transmute(f32x16::splat(a)) -} - -/// Sets packed 32-bit integers in `dst` with the supplied values. -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set_epi32( - e15: i32, - e14: i32, - e13: i32, - e12: i32, - e11: i32, - e10: i32, - e9: i32, - e8: i32, - e7: i32, - e6: i32, - e5: i32, - e4: i32, - e3: i32, - e2: i32, - e1: i32, - e0: i32, +#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_i32x4( + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, ) -> __m512i { - _mm512_setr_epi32( - e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, - ) -} - -/// Broadcast 32-bit integer `a` to all elements of `dst`. -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_epi32(a: i32) -> __m512i { - transmute(i32x16::splat(a)) -} - -/// Broadcast 64-bit integer `a` to all elements of `dst`. -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set1_epi64(a: i64) -> __m512i { - transmute(i64x8::splat(a)) -} + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in a mask vector. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmplt_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_LT_OS) + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i64x2&expand=5183) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmplt_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_LT_OS) +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_i64x2(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + } } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnlt_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i64x&expand=5181) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnlt_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_NLT_US) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnlt_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnlt_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NLT_US) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmple_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_LE_OS) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmple_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_LE_OS) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnle_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnle_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_NLE_US) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnle_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnle_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NLE_US) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in a mask vector. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpeq_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_EQ_OQ) -} +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_i64x2( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; -/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_ps) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpeq_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_EQ_OQ) + transmute(simd_select_bitmask(k, shuffle, src.as_i64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for inequality, and store the results in a mask vector. +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i64&expand=5182) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpneq_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_NEQ_UQ) -} +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_i64x2( + k: __mmask8, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; -/// Compare packed single-precision (32-bit) floating-point elements in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_ps_mask) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpneq_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_NEQ_UQ) + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f32x4&expand=5165) #[inline] #[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] //should be vshuff32x4, but generate vshuff64x2 #[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmp_ps_mask(a: __m512, b: __m512, op: i32) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmpps( - a.as_f32x16(), - b.as_f32x16(), - $imm5, - neg_one, - _MM_FROUND_CUR_DIRECTION, +pub unsafe fn _mm512_shuffle_f32x4(a: __m512, b: __m512, imm8: i32) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], ) }; } - let r = constify_imm5!(op, call); - transmute(r) + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + } } -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f32&expand=5163) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_ps_mask(m: __mmask16, a: __m512, b: __m512, op: i32) -> __mmask16 { - macro_rules! call { - ($imm5:expr) => { - vcmpps( - a.as_f32x16(), - b.as_f32x16(), - $imm5, - m as i16, - _MM_FROUND_CUR_DIRECTION, +#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_f32x4( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + imm8: i32, +) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], ) }; } - let r = constify_imm5!(op, call); - transmute(r) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_ps_mask) -#[inline] -#[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_cmp_round_ps_mask(a: __m512, b: __m512, op: i32, sae: i32) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, neg_one, $imm4) + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } }; } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_ps_mask) -#[inline] -#[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_mask_cmp_round_ps_mask( - m: __mmask16, - a: __m512, - b: __m512, - op: i32, - sae: i32, -) -> __mmask16 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, m as i16, $imm4) + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } }; } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) -} - -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_ps_mask) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpord_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_ORD_Q) -} + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_ps_mask) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpord_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_ORD_Q) + transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_ps_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f32&expand=5164) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpunord_ps_mask(a: __m512, b: __m512) -> __mmask16 { - _mm512_cmp_ps_mask(a, b, _CMP_UNORD_Q) -} +#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_f32x4(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; -/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_ps_mask) -#[inline] -#[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpunord_ps_mask(m: __mmask16, a: __m512, b: __m512) -> __mmask16 { - _mm512_mask_cmp_ps_mask(m, a, b, _CMP_UNORD_Q) + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in a mask vector. +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f64x2&expand=5171) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmplt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_LT_OS) +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_f64x2(a: __m512d, b: __m512d, imm8: i32) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + } } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f64x2&expand=5169) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmplt_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_LT_OS) +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_f64x2( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnlt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f64x2&expand=5170) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnlt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_NLT_US) +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_f64x2( + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]) + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Extract 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from a, selected with imm8, and store the result in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnlt_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_extractf32x4_ps&expand=2442) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnlt_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NLT_US) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf32x4, imm8 = 3) +)] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_extractf32x4_ps(a: __m512, imm8: i32) -> __m128 { + assert!(imm8 >= 0 && imm8 <= 3); + match imm8 & 0x3 { + 0 => simd_shuffle4(a, _mm512_undefined_ps(), [0, 1, 2, 3]), + 1 => simd_shuffle4(a, _mm512_undefined_ps(), [4, 5, 6, 7]), + 2 => simd_shuffle4(a, _mm512_undefined_ps(), [8, 9, 10, 11]), + _ => simd_shuffle4(a, _mm512_undefined_ps(), [12, 13, 14, 15]), + } } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector. +/// Extract 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from a, selected with imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_extractf32x4_ps&expand=2443) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmple_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_LE_OS) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf32x4, imm8 = 3) +)] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_extractf32x4_ps( + src: __m128, + k: __mmask8, + a: __m512, + imm8: i32, +) -> __m128 { + assert!(imm8 >= 0 && imm8 <= 3); + let extract: __m128 = match imm8 & 0x3 { + 0 => simd_shuffle4(a, _mm512_undefined_ps(), [0, 1, 2, 3]), + 1 => simd_shuffle4(a, _mm512_undefined_ps(), [4, 5, 6, 7]), + 2 => simd_shuffle4(a, _mm512_undefined_ps(), [8, 9, 10, 11]), + _ => simd_shuffle4(a, _mm512_undefined_ps(), [12, 13, 14, 15]), + }; + transmute(simd_select_bitmask(k, extract.as_f32x4(), src.as_f32x4())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Extract 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from a, selected with imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_extractf32x4_ps&expand=2444) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmple_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_LE_OS) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf32x4, imm8 = 3) +)] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_extractf32x4_ps(k: __mmask8, a: __m512, imm8: i32) -> __m128 { + assert!(imm8 >= 0 && imm8 <= 3); + let extract: __m128 = match imm8 & 0x3 { + 0 => simd_shuffle4(a, _mm512_undefined_ps(), [0, 1, 2, 3]), + 1 => simd_shuffle4(a, _mm512_undefined_ps(), [4, 5, 6, 7]), + 2 => simd_shuffle4(a, _mm512_undefined_ps(), [8, 9, 10, 11]), + _ => simd_shuffle4(a, _mm512_undefined_ps(), [12, 13, 14, 15]), + }; + let zero = _mm_setzero_ps().as_f32x4(); + transmute(simd_select_bitmask(k, extract.as_f32x4(), zero)) } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector. +/// Extract 256 bits (composed of 4 packed 64-bit integers) from a, selected with imm8, and store the result in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpnle_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_extracti64x4_epi64&expand=2473) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpnle_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_NLE_US) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf64x4, imm8 = 1) //should be vextracti64x4 +)] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_extracti64x4_epi64(a: __m512i, imm8: i32) -> __m256i { + assert!(imm8 >= 0 && imm8 <= 1); + match imm8 & 0x1 { + 0 => simd_shuffle4(a, _mm512_set1_epi64(0), [0, 1, 2, 3]), + _ => simd_shuffle4(a, _mm512_set1_epi64(0), [4, 5, 6, 7]), + } } -/// Compare packed single-precision (32-bit) floating-point elements in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Extract 256 bits (composed of 4 packed 64-bit integers) from a, selected with imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpnle_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_extracti64x4_epi64&expand=2474) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpnle_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NLE_US) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextracti64x4, imm8 = 1) +)] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_extracti64x4_epi64( + src: __m256i, + k: __mmask8, + a: __m512i, + imm8: i32, +) -> __m256i { + assert!(imm8 >= 0 && imm8 <= 1); + let extract = match imm8 & 0x1 { + 0 => simd_shuffle4(a, _mm512_set1_epi64(0), [0, 1, 2, 3]), + _ => simd_shuffle4(a, _mm512_set1_epi64(0), [4, 5, 6, 7]), + }; + transmute(simd_select_bitmask(k, extract, src.as_i64x4())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in a mask vector. +/// Extract 256 bits (composed of 4 packed 64-bit integers) from a, selected with imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_extracti64x4_epi64&expand=2475) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpeq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_EQ_OQ) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextracti64x4, imm8 = 1) +)] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_extracti64x4_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m256i { + assert!(imm8 >= 0 && imm8 <= 1); + let extract: __m256i = match imm8 & 0x1 { + 0 => simd_shuffle4(a, _mm512_set1_epi64(0), [0, 1, 2, 3]), + _ => simd_shuffle4(a, _mm512_set1_epi64(0), [4, 5, 6, 7]), + }; + let zero = _mm256_setzero_si256().as_i64x4(); + transmute(simd_select_bitmask(k, extract.as_i64x4(), zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Extract 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from a, selected with imm8, and store the result in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_extractf64x4_pd&expand=2454) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpeq_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_EQ_OQ) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf64x4, imm8 = 1) +)] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_extractf64x4_pd(a: __m512d, imm8: i32) -> __m256d { + assert!(imm8 >= 0 && imm8 <= 1); + match imm8 & 0x1 { + 0 => simd_shuffle4(a, _mm512_undefined_pd(), [0, 1, 2, 3]), + _ => simd_shuffle4(a, _mm512_undefined_pd(), [4, 5, 6, 7]), + } } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for inequality, and store the results in a mask vector. +/// Extract 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from a, selected with imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_extractf64x4_pd&expand=2455) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_cmpneq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_NEQ_UQ) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf64x4, imm8 = 1) +)] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_extractf64x4_pd( + src: __m256d, + k: __mmask8, + a: __m512d, + imm8: i32, +) -> __m256d { + assert!(imm8 >= 0 && imm8 <= 1); + let extract = match imm8 & 0x1 { + 0 => simd_shuffle4(a, _mm512_undefined_pd(), [0, 1, 2, 3]), + _ => simd_shuffle4(a, _mm512_undefined_pd(), [4, 5, 6, 7]), + }; + transmute(simd_select_bitmask(k, extract, src)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Extract 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from a, selected with imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_extractf64x4_pd&expand=2456) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp))] -pub unsafe fn _mm512_mask_cmpneq_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NEQ_UQ) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf64x4, imm8 = 1) +)] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_extractf64x4_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m256d { + assert!(imm8 >= 0 && imm8 <= 1); + let extract = match imm8 & 0x1 { + 0 => simd_shuffle4(a, _mm512_undefined_pd(), [0, 1, 2, 3]), + _ => simd_shuffle4(a, _mm512_undefined_pd(), [4, 5, 6, 7]), + }; + let zero = _mm256_setzero_pd(); + transmute(simd_select_bitmask(k, extract, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// Extract 128 bits (composed of 4 packed 32-bit integers) from a, selected with imm8, and store the result in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_extracti32x4_epi32&expand=2461) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmp_pd_mask(a: __m512d, b: __m512d, op: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmppd( - a.as_f64x8(), - b.as_f64x8(), - $imm5, - neg_one, - _MM_FROUND_CUR_DIRECTION, - ) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf32x4, imm8 = 3) //should be vextracti32x4 +)] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_extracti32x4_epi32(a: __m512i, imm8: i32) -> __m128i { + assert!(imm8 >= 0 && imm8 <= 3); + let a = a.as_i32x16(); + let undefined = _mm512_undefined_epi32().as_i32x16(); + let extract: i32x4 = match imm8 & 0x3 { + 0 => simd_shuffle4(a, undefined, [0, 1, 2, 3]), + 1 => simd_shuffle4(a, undefined, [4, 5, 6, 7]), + 2 => simd_shuffle4(a, undefined, [8, 9, 10, 11]), + _ => simd_shuffle4(a, undefined, [12, 13, 14, 15]), + }; + transmute(extract) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Extract 128 bits (composed of 4 packed 32-bit integers) from a, selected with imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_extracti32x4_epi32&expand=2462) #[inline] #[target_feature(enable = "avx512f")] +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextracti32x4, imm8 = 3) +)] #[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_pd_mask(m: __mmask8, a: __m512d, b: __m512d, op: i32) -> __mmask8 { - macro_rules! call { - ($imm5:expr) => { - vcmppd( - a.as_f64x8(), - b.as_f64x8(), - $imm5, - m as i8, - _MM_FROUND_CUR_DIRECTION, - ) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +pub unsafe fn _mm512_mask_extracti32x4_epi32( + src: __m128i, + k: __mmask8, + a: __m512i, + imm8: i32, +) -> __m128i { + assert!(imm8 >= 0 && imm8 <= 3); + let a = a.as_i32x16(); + let undefined = _mm512_undefined_epi32().as_i32x16(); + let extract: i32x4 = match imm8 & 0x3 { + 0 => simd_shuffle4(a, undefined, [0, 1, 2, 3]), + 1 => simd_shuffle4(a, undefined, [4, 5, 6, 7]), + 2 => simd_shuffle4(a, undefined, [8, 9, 10, 11]), + _ => simd_shuffle4(a, undefined, [12, 13, 14, 15]), + }; + transmute(simd_select_bitmask(k, extract, src.as_i32x4())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op. +/// Extract 128 bits (composed of 4 packed 32-bit integers) from a, selected with imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_extracti32x4_epi32&expand=2463) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_cmp_round_pd_mask(a: __m512d, b: __m512d, op: i32, sae: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, neg_one, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextracti32x4, imm8 = 3) +)] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_extracti32x4_epi32(k: __mmask8, a: __m512i, imm8: i32) -> __m128i { + assert!(imm8 >= 0 && imm8 <= 3); + let a = a.as_i32x16(); + let undefined = _mm512_undefined_epi32().as_i32x16(); + let extract: i32x4 = match imm8 & 0x3 { + 0 => simd_shuffle4(a, undefined, [0, 1, 2, 3]), + 1 => simd_shuffle4(a, undefined, [4, 5, 6, 7]), + 2 => simd_shuffle4(a, undefined, [8, 9, 10, 11]), + _ => simd_shuffle4(a, undefined, [12, 13, 14, 15]), + }; + let zero = _mm_setzero_si128().as_i32x4(); + transmute(simd_select_bitmask(k, extract, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_round_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_moveldup_ps&expand=3862) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm512_mask_cmp_round_pd_mask( - m: __mmask8, - a: __m512d, - b: __m512d, - op: i32, - sae: i32, -) -> __mmask8 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, m as i8, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_moveldup_ps(a: __m512) -> __m512 { + let r: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); transmute(r) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_moveldup_ps&expand=3860) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_ORD_Q) +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_mask_moveldup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + transmute(simd_select_bitmask(k, mov, src.as_f32x16())) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in a mask vector. +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveldup_ps&expand=3861) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpord_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_ORD_Q) +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_maskz_moveldup_ps(k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mov, zero)) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movehdup_ps&expand=3852) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_cmpunord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { - _mm512_cmp_pd_mask(a, b, _CMP_UNORD_Q) +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_movehdup_ps(a: __m512) -> __m512 { + let r: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + transmute(r) } -/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in a mask vector. +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpunord_pd_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movehdup&expand=3850) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vcmp, op = 0))] -pub unsafe fn _mm512_mask_cmpunord_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { - _mm512_mask_cmp_pd_mask(m, a, b, _CMP_UNORD_Q) +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_mask_movehdup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + transmute(simd_select_bitmask(k, mov, src.as_f32x16())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveh&expand=3851) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_ss_mask(a: __m128, b: __m128, op: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmpss(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_maskz_movehdup_ps(k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mov, zero)) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movedup_pd&expand=3843) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_ss_mask(m: __mmask8, a: __m128, b: __m128, op: i32) -> __mmask8 { - macro_rules! call { - ($imm5:expr) => { - vcmpss(a, b, $imm5, m as i8, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_movedup_pd(a: __m512d) -> __m512d { + let r: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); transmute(r) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movedup_pd&expand=3841) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_round_ss_mask(a: __m128, b: __m128, op: i32, sae: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpss(a, b, $imm5, neg_one, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_mask_movedup_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + transmute(simd_select_bitmask(k, mov, src.as_f64x8())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_ss_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_movedup_pd&expand=3842) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_round_ss_mask( - m: __mmask8, - a: __m128, - b: __m128, - op: i32, - sae: i32, -) -> __mmask8 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpss(a, b, $imm5, m as i8, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_maskz_movedup_pd(k: __mmask8, a: __m512d) -> __m512d { + let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mov, zero)) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Copy a to dst, then insert 128 bits (composed of 4 packed 32-bit integers) from b into dst at the location specified by imm8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_inserti32x4&expand=3174) #[inline] #[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] //should be vinserti32x4 #[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_sd_mask(a: __m128d, b: __m128d, op: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr) => { - vcmpsd(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +pub unsafe fn _mm512_inserti32x4(a: __m512i, b: __m128i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 3); + let a = a.as_i32x16(); + let b = _mm512_castsi128_si512(b).as_i32x16(); + let ret: i32x16 = match imm8 & 0b11 { + 0 => simd_shuffle16( + a, + b, + [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 1 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 2 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], + ), + _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), + }; + transmute(ret) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Copy a to tmp, then insert 128 bits (composed of 4 packed 32-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_inserti32x4&expand=3175) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_sd_mask(m: __mmask8, a: __m128d, b: __m128d, op: i32) -> __mmask8 { - macro_rules! call { - ($imm5:expr) => { - vcmpsd(a, b, $imm5, m as i8, _MM_FROUND_CUR_DIRECTION) - }; - } - let r = constify_imm5!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vinserti32x4, imm8 = 2))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_inserti32x4( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m128i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 3); + let a = a.as_i32x16(); + let b = _mm512_castsi128_si512(b).as_i32x16(); + let insert: i32x16 = match imm8 & 0b11 { + 0 => simd_shuffle16( + a, + b, + [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 1 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 2 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], + ), + _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), + }; + transmute(simd_select_bitmask(k, insert, src.as_i32x16())) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector. +/// Copy a to tmp, then insert 128 bits (composed of 4 packed 32-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_inserti32x4&expand=3176) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2, 3)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_cmp_round_sd_mask(a: __m128d, b: __m128d, op: i32, sae: i32) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpsd(a, b, $imm5, neg_one, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vinserti32x4, imm8 = 2))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_inserti32x4(k: __mmask16, a: __m512i, b: __m128i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 3); + let a = a.as_i32x16(); + let b = _mm512_castsi128_si512(b).as_i32x16(); + let insert = match imm8 & 0b11 { + 0 => simd_shuffle16( + a, + b, + [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 1 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 2 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], + ), + _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), + }; + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, insert, zero)) } -/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in a mask vector using zeromask m (the element is zeroed out when mask bit 0 is not set). +/// Copy a to dst, then insert 256 bits (composed of 4 packed 64-bit integers) from b into dst at the location specified by imm8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_sd_mask&expand=5236,755,757) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_inserti64x4&expand=3186) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3, 4)] -#[cfg_attr(test, assert_instr(vcmp, op = 0, sae = 4))] -pub unsafe fn _mm_mask_cmp_round_sd_mask( - m: __mmask8, - a: __m128d, - b: __m128d, - op: i32, - sae: i32, -) -> __mmask8 { - macro_rules! call { - ($imm5:expr, $imm4:expr) => { - vcmpsd(a, b, $imm5, m as i8, $imm4) - }; - } - let r = constify_imm5_sae!(op, sae, call); - transmute(r) +#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] //should be vinserti64x4 +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_inserti64x4(a: __m512i, b: __m256i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 1); + let b = _mm512_castsi256_si512(b); + match imm8 & 0b1 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), + _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), + } } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector. +/// Copy a to tmp, then insert 256 bits (composed of 4 packed 64-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_inserti64x4&expand=3187) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_lt(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vinserti64x4, imm8 = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_inserti64x4( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m256i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 1); + let b = _mm512_castsi256_si512(b); + let insert = match imm8 & 0b1 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), + _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), + }; + transmute(simd_select_bitmask(k, insert, src.as_i64x8())) } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Copy a to tmp, then insert 256 bits (composed of 4 packed 64-bit integers) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_inserti64x4&expand=3188) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmplt_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vinserti64x4, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_inserti64x4(k: __mmask8, a: __m512i, b: __m256i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 1); + let b = _mm512_castsi256_si512(b); + let insert = match imm8 & 0b1 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), + _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), + }; + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, insert, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Copy a to dst, then insert 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from b into dst at the location specified by imm8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_insertf32x4&expand=3155) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_gt(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_insertf32x4(a: __m512, b: __m128, imm8: i32) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 3); + let b = _mm512_castps128_ps512(b); + match imm8 & 0b11 { + 0 => simd_shuffle16( + a, + b, + [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 1 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 2 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], + ), + _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), + } } -/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Copy a to tmp, then insert 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_insertf32x4&expand=3156) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpgt_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_insertf32x4( + src: __m512, + k: __mmask16, + a: __m512, + b: __m128, + imm8: i32, +) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 3); + let b = _mm512_castps128_ps512(b); + let insert = match imm8 & 0b11 { + 0 => simd_shuffle16( + a, + b, + [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 1 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 2 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], + ), + _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), + }; + transmute(simd_select_bitmask(k, insert, src.as_f32x16())) } -/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Copy a to tmp, then insert 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_insertf32x4&expand=3157) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_le(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vinsertf32x4, imm8 = 2))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_insertf32x4(k: __mmask16, a: __m512, b: __m128, imm8: i32) -> __m512 { + assert!(imm8 >= 0 && imm8 <= 3); + let b = _mm512_castps128_ps512(b); + let insert = match imm8 & 0b11 { + 0 => simd_shuffle16( + a, + b, + [16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 1 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15], + ), + 2 => simd_shuffle16( + a, + b, + [0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15], + ), + _ => simd_shuffle16(a, b, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19]), + }; + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, insert, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Copy a to dst, then insert 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from b into dst at the location specified by imm8. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_insertf64x4&expand=3167) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmple_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_insertf64x4(a: __m512d, b: __m256d, imm8: i32) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 1); + let b = _mm512_castpd256_pd512(b); + match imm8 & 0b1 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), + _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), + } } -/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Copy a to tmp, then insert 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_insertf64x4&expand=3168) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ge(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_insertf64x4( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m256d, + imm8: i32, +) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 1); + let b = _mm512_castpd256_pd512(b); + let insert = match imm8 & 0b1 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), + _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), + }; + transmute(simd_select_bitmask(k, insert, src.as_f64x8())) } -/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Copy a to tmp, then insert 256 bits (composed of 4 packed double-precision (64-bit) floating-point elements) from b into tmp at the location specified by imm8. Store tmp to dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_insertf64x4&expand=3169) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpge_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vinsertf64x4, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_insertf64x4(k: __mmask8, a: __m512d, b: __m256d, imm8: i32) -> __m512d { + assert!(imm8 >= 0 && imm8 <= 1); + let b = _mm512_castpd256_pd512(b); + let insert = match imm8 & 0b1 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 4, 5, 6, 7]), + _ => simd_shuffle8(a, b, [0, 1, 2, 3, 8, 9, 10, 11]), + }; + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, insert, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in a mask vector. +/// Unpack and interleave 32-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_epi32&expand=6021) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_eq(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vunpckhps))] //should be vpunpckhdq +pub unsafe fn _mm512_unpackhi_epi32(a: __m512i, b: __m512i) -> __m512i { + let a = a.as_i32x16(); + let b = b.as_i32x16(); + let r: i32x16 = simd_shuffle16( + a, + b, + [ + 2, + 18, + 3, + 19, + 2 + 4, + 18 + 4, + 3 + 4, + 19 + 4, + 2 + 8, + 18 + 8, + 3 + 8, + 19 + 8, + 2 + 12, + 18 + 12, + 3 + 12, + 19 + 12, + ], + ); + transmute(r) } -/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave 32-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_epi32&expand=6019) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpeq_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vpunpckhdq))] +pub unsafe fn _mm512_mask_unpackhi_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let unpackhi = _mm512_unpackhi_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i32x16())) } -/// Compare packed unsigned 32-bit integers in a and b for inequality, and store the results in a mask vector. +/// Unpack and interleave 32-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epu32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_epi32&expand=6020) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ne(a.as_u32x16(), b.as_u32x16())) +#[cfg_attr(test, assert_instr(vpunpckhdq))] +pub unsafe fn _mm512_maskz_unpackhi_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let unpackhi = _mm512_unpackhi_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave 64-bit integers from the high half of each 128-bit lane in a and b, and +/// store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epu32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_epi64&expand=6030) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epu32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpneq_epu32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vunpckhpd))] //should be vpunpckhqdq +pub unsafe fn _mm512_unpackhi_epi64(a: __m512i, b: __m512i) -> __m512i { + simd_shuffle8(a, b, [1, 9, 1 + 2, 9 + 2, 1 + 4, 9 + 4, 1 + 6, 9 + 6]) } -/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by op. +/// Unpack and interleave 64-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_epi64&expand=6028) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epu32_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) -} - -/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). -/// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu32_mask) -#[inline] -#[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epu32_mask( - m: __mmask16, +#[cfg_attr(test, assert_instr(vpunpckhqdq))] +pub unsafe fn _mm512_mask_unpackhi_epi64( + src: __m512i, + k: __mmask8, a: __m512i, b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask16 { - macro_rules! call { - ($imm3:expr) => { - vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, m as i16) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +) -> __m512i { + let unpackhi = _mm512_unpackhi_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i64x8())) } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector. +/// Unpack and interleave 64-bit integers from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_epi64&expand=6029) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_lt(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vpunpckhqdq))] +pub unsafe fn _mm512_maskz_unpackhi_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let unpackhi = _mm512_unpackhi_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave single-precision (32-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_ps&expand=6060) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmplt_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vunpckhps))] +pub unsafe fn _mm512_unpackhi_ps(a: __m512, b: __m512) -> __m512 { + simd_shuffle16( + a, + b, + [ + 2, + 18, + 3, + 19, + 2 + 4, + 18 + 4, + 3 + 4, + 19 + 4, + 2 + 8, + 18 + 8, + 3 + 8, + 19 + 8, + 2 + 12, + 18 + 12, + 3 + 12, + 19 + 12, + ], + ) } -/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Unpack and interleave single-precision (32-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_ps&expand=6058) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_gt(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vunpckhps))] +pub unsafe fn _mm512_mask_unpackhi_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let unpackhi = _mm512_unpackhi_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, unpackhi, src.as_f32x16())) } -/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave single-precision (32-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_ps&expand=6059) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpgt_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vunpckhps))] +pub unsafe fn _mm512_maskz_unpackhi_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let unpackhi = _mm512_unpackhi_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Unpack and interleave double-precision (64-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpackhi_pd&expand=6048) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_le(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vunpckhpd))] +pub unsafe fn _mm512_unpackhi_pd(a: __m512d, b: __m512d) -> __m512d { + simd_shuffle8(a, b, [1, 9, 1 + 2, 9 + 2, 1 + 4, 9 + 4, 1 + 6, 9 + 6]) } -/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave double-precision (64-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpackhi_pd&expand=6046) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmple_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vunpckhpd))] +pub unsafe fn _mm512_mask_unpackhi_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, +) -> __m512d { + let unpackhi = _mm512_unpackhi_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, unpackhi, src.as_f64x8())) } -/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Unpack and interleave double-precision (64-bit) floating-point elements from the high half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpackhi_pd&expand=6047) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ge(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vunpckhpd))] +pub unsafe fn _mm512_maskz_unpackhi_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let unpackhi = _mm512_unpackhi_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave 32-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_epi32&expand=6078) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpge_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vunpcklps))] //should be vpunpckldq +pub unsafe fn _mm512_unpacklo_epi32(a: __m512i, b: __m512i) -> __m512i { + let a = a.as_i32x16(); + let b = b.as_i32x16(); + let r: i32x16 = simd_shuffle16( + a, + b, + [ + 0, + 16, + 1, + 17, + 0 + 4, + 16 + 4, + 1 + 4, + 17 + 4, + 0 + 8, + 16 + 8, + 1 + 8, + 17 + 8, + 0 + 12, + 16 + 12, + 1 + 12, + 17 + 12, + ], + ); + transmute(r) } -/// Compare packed signed 32-bit integers in a and b for equality, and store the results in a mask vector. +/// Unpack and interleave 32-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_epi32&expand=6076) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_eq(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vpunpckldq))] +pub unsafe fn _mm512_mask_unpacklo_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let unpackhi = _mm512_unpacklo_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i32x16())) } -/// Compare packed signed 32-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave 32-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_epi32&expand=6077) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpeq_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vpunpckldq))] +pub unsafe fn _mm512_maskz_unpacklo_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let unpackhi = _mm512_unpacklo_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed signed 32-bit integers in a and b for inequality, and store the results in a mask vector. +/// Unpack and interleave 64-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_epi64&expand=6087) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { - simd_bitmask::(simd_ne(a.as_i32x16(), b.as_i32x16())) +#[cfg_attr(test, assert_instr(vunpcklpd))] //should be vpunpcklqdq +pub unsafe fn _mm512_unpacklo_epi64(a: __m512i, b: __m512i) -> __m512i { + simd_shuffle8(a, b, [0, 8, 0 + 2, 8 + 2, 0 + 4, 8 + 4, 0 + 6, 8 + 6]) } -/// Compare packed signed 32-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave 64-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epi32) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_epi64&expand=6085) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epi32_mask(m: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { - _mm512_cmpneq_epi32_mask(a, b) & m +#[cfg_attr(test, assert_instr(vpunpcklqdq))] +pub unsafe fn _mm512_mask_unpacklo_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, +) -> __m512i { + let unpackhi = _mm512_unpacklo_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, unpackhi, src.as_i64x8())) } -/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by op. +/// Unpack and interleave 64-bit integers from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_epi64&expand=6086) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epi32_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask16 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vpunpcklqdq))] +pub unsafe fn _mm512_maskz_unpacklo_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let unpackhi = _mm512_unpacklo_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave single-precision (32-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi32_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_ps&expand=6117) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epi32_mask( - m: __mmask16, - a: __m512i, - b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask16 { - macro_rules! call { - ($imm3:expr) => { - vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, m as i16) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +#[cfg_attr(test, assert_instr(vunpcklps))] +pub unsafe fn _mm512_unpacklo_ps(a: __m512, b: __m512) -> __m512 { + simd_shuffle16( + a, + b, + [ + 0, + 16, + 1, + 17, + 0 + 4, + 16 + 4, + 1 + 4, + 17 + 4, + 0 + 8, + 16 + 8, + 1 + 8, + 17 + 8, + 0 + 12, + 16 + 12, + 1 + 12, + 17 + 12, + ], + ) } -/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector. +/// Unpack and interleave single-precision (32-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_ps&expand=6115) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_lt(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vunpcklps))] +pub unsafe fn _mm512_mask_unpacklo_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let unpackhi = _mm512_unpacklo_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, unpackhi, src.as_f32x16())) } -/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave single-precision (32-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_ps&expand=6116) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmplt_epu64_mask(a, b) & m +#[cfg_attr(test, assert_instr(vunpcklps))] +pub unsafe fn _mm512_maskz_unpacklo_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let unpackhi = _mm512_unpacklo_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Unpack and interleave double-precision (64-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_unpacklo_pd&expand=6105) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_gt(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vunpcklpd))] +pub unsafe fn _mm512_unpacklo_pd(a: __m512d, b: __m512d) -> __m512d { + simd_shuffle8(a, b, [0, 8, 0 + 2, 8 + 2, 0 + 4, 8 + 4, 0 + 6, 8 + 6]) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Unpack and interleave double-precision (64-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_unpacklo_pd&expand=6103) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpgt_epu64_mask(a, b) & m -} +#[cfg_attr(test, assert_instr(vunpcklpd))] +pub unsafe fn _mm512_mask_unpacklo_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, +) -> __m512d { + let unpackhi = _mm512_unpacklo_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, unpackhi, src.as_f64x8())) +} -/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Unpack and interleave double-precision (64-bit) floating-point elements from the low half of each 128-bit lane in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_unpacklo_pd&expand=6104) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_le(a.as_u64x8(), b.as_u64x8())) +#[cfg_attr(test, assert_instr(vunpcklpd))] +pub unsafe fn _mm512_maskz_unpacklo_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let unpackhi = _mm512_unpacklo_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, unpackhi, zero)) } -/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m128 to type __m512; the upper 384 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps128_ps512&expand=621) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmple_epu64_mask(a, b) & m +pub unsafe fn _mm512_castps128_ps512(a: __m128) -> __m512 { + simd_shuffle16( + a, + _mm_set1_ps(-1.), + [0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], + ) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Cast vector of type __m256 to type __m512; the upper 256 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps256_ps512&expand=623) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ge(a.as_u64x8(), b.as_u64x8())) +pub unsafe fn _mm512_castps256_ps512(a: __m256) -> __m512 { + simd_shuffle16( + a, + _mm256_set1_ps(-1.), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8], + ) } -/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m128 to type __m512; the upper 384 bits of the result are zeroed. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_zextps128_ps512&expand=6196) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpge_epu64_mask(b, a) & m +pub unsafe fn _mm512_zextps128_ps512(a: __m128) -> __m512 { + simd_shuffle16( + a, + _mm_set1_ps(0.), + [0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], + ) } -/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in a mask vector. +/// Cast vector of type __m256 to type __m512; the upper 256 bits of the result are zeroed. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_zextps256_ps512&expand=6197) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_eq(a.as_u64x8(), b.as_u64x8())) +pub unsafe fn _mm512_zextps256_ps512(a: __m256) -> __m512 { + simd_shuffle16( + a, + _mm256_set1_ps(0.), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8], + ) } -/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m512 to type __m128. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps512_ps128&expand=624) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpeq_epu64_mask(a, b) & m +pub unsafe fn _mm512_castps512_ps128(a: __m512) -> __m128 { + simd_shuffle4(a, a, [0, 1, 2, 3]) } -/// Compare packed unsigned 64-bit integers in a and b for inequality, and store the results in a mask vector. +/// Cast vector of type __m512 to type __m256. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epu64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps512_ps256&expand=625) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ne(a.as_u64x8(), b.as_u64x8())) +pub unsafe fn _mm512_castps512_ps256(a: __m512) -> __m256 { + simd_shuffle8(a, a, [0, 1, 2, 3, 4, 5, 6, 7]) } -/// Compare packed unsigned 64-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m512 to type __m512d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epu64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps_pd&expand=616) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epu64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpneq_epu64_mask(a, b) & m +pub unsafe fn _mm512_castps_pd(a: __m512) -> __m512d { + transmute(a.as_m512()) } -/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by op. +/// Cast vector of type __m512 to type __m512i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castps_si512&expand=619) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epu64_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +pub unsafe fn _mm512_castps_si512(a: __m512) -> __m512i { + transmute(a.as_m512()) } -/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m128d to type __m512d; the upper 384 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epu64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd128_pd512&expand=609) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epu64_mask( - m: __mmask8, - a: __m512i, - b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask8 { - macro_rules! call { - ($imm3:expr) => { - vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, m as i8) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +pub unsafe fn _mm512_castpd128_pd512(a: __m128d) -> __m512d { + simd_shuffle8(a, _mm_set1_pd(-1.), [0, 1, 2, 2, 2, 2, 2, 2]) } -/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in a mask vector. +/// Cast vector of type __m256d to type __m512d; the upper 256 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd256_pd512&expand=611) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmplt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_lt(a.as_i64x8(), b.as_i64x8())) +pub unsafe fn _mm512_castpd256_pd512(a: __m256d) -> __m512d { + simd_shuffle8(a, _mm256_set1_pd(-1.), [0, 1, 2, 3, 4, 4, 4, 4]) } -/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m128d to type __m512d; the upper 384 bits of the result are zeroed. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmplt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_zextpd128_pd512&expand=6193) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmplt_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmplt_epi64_mask(a, b) & m +pub unsafe fn _mm512_zextpd128_pd512(a: __m128d) -> __m512d { + simd_shuffle8(a, _mm_set1_pd(0.), [0, 1, 2, 2, 2, 2, 2, 2]) } -/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in a mask vector. +/// Cast vector of type __m256d to type __m512d; the upper 256 bits of the result are zeroed. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpgt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_zextpd256_pd512&expand=6194) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpgt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_gt(a.as_i64x8(), b.as_i64x8())) +pub unsafe fn _mm512_zextpd256_pd512(a: __m256d) -> __m512d { + simd_shuffle8(a, _mm256_set1_pd(0.), [0, 1, 2, 3, 4, 4, 4, 4]) } -/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m512d to type __m128d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpgt_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd512_pd128&expand=612) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpgt_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpgt_epi64_mask(a, b) & m +pub unsafe fn _mm512_castpd512_pd128(a: __m512d) -> __m128d { + simd_shuffle2(a, a, [0, 1]) } -/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector. +/// Cast vector of type __m512d to type __m256d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmple_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd512_pd256&expand=613) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmple_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_le(a.as_i64x8(), b.as_i64x8())) +pub unsafe fn _mm512_castpd512_pd256(a: __m512d) -> __m256d { + simd_shuffle4(a, a, [0, 1, 2, 3]) } -/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m512d to type __m512. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmple_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd_ps&expand=604) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmple_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmple_epi64_mask(a, b) & m +pub unsafe fn _mm512_castpd_ps(a: __m512d) -> __m512 { + transmute(a.as_m512d()) } -/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector. +/// Cast vector of type __m512d to type __m512i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpge_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castpd_si512&expand=607) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpge_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ge(a.as_i64x8(), b.as_i64x8())) +pub unsafe fn _mm512_castpd_si512(a: __m512d) -> __m512i { + transmute(a.as_m512d()) } -/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m128i to type __m512i; the upper 384 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpge_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi128_si512&expand=629) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpge_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpge_epi64_mask(b, a) & m +pub unsafe fn _mm512_castsi128_si512(a: __m128i) -> __m512i { + simd_shuffle8(a, _mm_set1_epi64x(-1), [0, 1, 2, 2, 2, 2, 2, 2]) } -/// Compare packed signed 64-bit integers in a and b for equality, and store the results in a mask vector. +/// Cast vector of type __m256i to type __m512i; the upper 256 bits of the result are undefined. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpeq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi256_si512&expand=633) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpeq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_eq(a.as_i64x8(), b.as_i64x8())) +pub unsafe fn _mm512_castsi256_si512(a: __m256i) -> __m512i { + simd_shuffle8(a, _mm256_set1_epi64x(-1), [0, 1, 2, 3, 4, 4, 4, 4]) } -/// Compare packed signed 64-bit integers in a and b for equality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m128i to type __m512i; the upper 384 bits of the result are zeroed. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpeq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_zextsi128_si512&expand=6199) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpeq_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpeq_epi64_mask(a, b) & m +pub unsafe fn _mm512_zextsi128_si512(a: __m128i) -> __m512i { + simd_shuffle8(a, _mm_set1_epi64x(0), [0, 1, 2, 2, 2, 2, 2, 2]) } -/// Compare packed signed 64-bit integers in a and b for inequality, and store the results in a mask vector. +/// Cast vector of type __m256i to type __m512i; the upper 256 bits of the result are zeroed. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmpneq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_zextsi256_si512&expand=6200) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_cmpneq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { - simd_bitmask::<__m512i, _>(simd_ne(a.as_i64x8(), b.as_i64x8())) +pub unsafe fn _mm512_zextsi256_si512(a: __m256i) -> __m512i { + simd_shuffle8(a, _mm256_set1_epi64x(0), [0, 1, 2, 3, 4, 4, 4, 4]) } -/// Compare packed signed 64-bit integers in a and b for inequality, and store the results in a mask vector k -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m512i to type __m128i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmpneq_epi64) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_si128&expand=636) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vpcmp))] -pub unsafe fn _mm512_mask_cmpneq_epi64_mask(m: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { - _mm512_cmpneq_epi64_mask(a, b) & m +pub unsafe fn _mm512_castsi512_si128(a: __m512i) -> __m128i { + simd_shuffle2(a, a, [0, 1]) } -/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by op. +/// Cast vector of type __m512i to type __m256i. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_si256&expand=637) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(2)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_cmp_epi64_mask(a: __m512i, b: __m512i, op: _MM_CMPINT_ENUM) -> __mmask8 { - let neg_one = -1; - macro_rules! call { - ($imm3:expr) => { - vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +pub unsafe fn _mm512_castsi512_si256(a: __m512i) -> __m256i { + simd_shuffle4(a, a, [0, 1, 2, 3]) } -/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by op, -/// using zeromask m (elements are zeroed out when the corresponding mask bit is not set). +/// Cast vector of type __m512i to type __m512. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,1063&text=_mm512_mask_cmp_epi64_mask) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_ps&expand=635) #[inline] #[target_feature(enable = "avx512f")] -#[rustc_args_required_const(3)] -#[cfg_attr(test, assert_instr(vpcmp, op = 0))] -pub unsafe fn _mm512_mask_cmp_epi64_mask( - m: __mmask8, - a: __m512i, - b: __m512i, - op: _MM_CMPINT_ENUM, -) -> __mmask8 { - macro_rules! call { - ($imm3:expr) => { - vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, m as i8) - }; - } - let r = constify_imm3!(op, call); - transmute(r) +pub unsafe fn _mm512_castsi512_ps(a: __m512i) -> __m512 { + transmute(a) } -/// Returns vector of type `__m512d` with undefined elements. +/// Cast vector of type __m512i to type __m512d. This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_castsi512_pd&expand=634) #[inline] #[target_feature(enable = "avx512f")] -// This intrinsic has no corresponding instruction. -pub unsafe fn _mm512_undefined_pd() -> __m512d { - _mm512_set1_pd(0.0) +pub unsafe fn _mm512_castsi512_pd(a: __m512i) -> __m512d { + transmute(a) } -/// Returns vector of type `__m512` with undefined elements. +/// Broadcast the low packed 32-bit integer from a to all elements of dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastd_epi32&expand=545) #[inline] #[target_feature(enable = "avx512f")] -// This intrinsic has no corresponding instruction. -pub unsafe fn _mm512_undefined_ps() -> __m512 { - _mm512_set1_ps(0.0) +#[cfg_attr(test, assert_instr(vbroadcast))] //should be vpbroadcastd +pub unsafe fn _mm512_broadcastd_epi32(a: __m128i) -> __m512i { + let a = _mm512_castsi128_si512(a).as_i32x16(); + let ret: i32x16 = simd_shuffle16(a, a, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + transmute(ret) } -/// Loads 512-bits (composed of 8 packed double-precision (64-bit) -/// floating-point elements) from memory into result. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Broadcast the low packed 32-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastd_epi32&expand=546) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -pub unsafe fn _mm512_loadu_pd(mem_addr: *const f64) -> __m512d { - ptr::read_unaligned(mem_addr as *const __m512d) +#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastd +pub unsafe fn _mm512_mask_broadcastd_epi32(src: __m512i, k: __mmask16, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastd_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, broadcast, src.as_i32x16())) } -/// Stores 512-bits (composed of 8 packed double-precision (64-bit) -/// floating-point elements) from `a` into memory. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Broadcast the low packed 32-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastd_epi32&expand=547) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -pub unsafe fn _mm512_storeu_pd(mem_addr: *mut f64, a: __m512d) { - ptr::write_unaligned(mem_addr as *mut __m512d, a); +#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastd +pub unsafe fn _mm512_maskz_broadcastd_epi32(k: __mmask16, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastd_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, broadcast, zero)) } -/// Loads 512-bits (composed of 16 packed single-precision (32-bit) -/// floating-point elements) from memory into result. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Broadcast the low packed 64-bit integer from a to all elements of dst. /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastq_epi64&expand=560) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -pub unsafe fn _mm512_loadu_ps(mem_addr: *const f32) -> __m512 { - ptr::read_unaligned(mem_addr as *const __m512) +#[cfg_attr(test, assert_instr(vbroadcas))] //should be vpbroadcastq +pub unsafe fn _mm512_broadcastq_epi64(a: __m128i) -> __m512i { + simd_shuffle8(a, a, [0, 0, 0, 0, 0, 0, 0, 0]) } -/// Stores 512-bits (composed of 16 packed single-precision (32-bit) -/// floating-point elements) from `a` into memory. -/// `mem_addr` does not need to be aligned on any particular boundary. +/// Broadcast the low packed 64-bit integer from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). /// -/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_ps) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastq_epi64&expand=561) #[inline] #[target_feature(enable = "avx512f")] -#[cfg_attr(test, assert_instr(vmovups))] -#[stable(feature = "simd_x86", since = "1.27.0")] -pub unsafe fn _mm512_storeu_ps(mem_addr: *mut f32, a: __m512) { - ptr::write_unaligned(mem_addr as *mut __m512, a); +#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastq +pub unsafe fn _mm512_mask_broadcastq_epi64(src: __m512i, k: __mmask8, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastq_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, broadcast, src.as_i64x8())) } -/// Sets packed 64-bit integers in `dst` with the supplied values in -/// reverse order. +/// Broadcast the low packed 64-bit integer from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). /// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastq_epi64&expand=562) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_setr_pd( - e0: f64, - e1: f64, - e2: f64, - e3: f64, - e4: f64, - e5: f64, - e6: f64, - e7: f64, -) -> __m512d { - let r = f64x8::new(e0, e1, e2, e3, e4, e5, e6, e7); - transmute(r) +#[cfg_attr(test, assert_instr(vpbroadcast))] //should be vpbroadcastq +pub unsafe fn _mm512_maskz_broadcastq_epi64(k: __mmask8, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcastq_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, broadcast, zero)) } -/// Sets packed 64-bit integers in `dst` with the supplied values. +/// Broadcast the low single-precision (32-bit) floating-point element from a to all elements of dst. /// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_pd) +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastss_ps&expand=578) #[inline] #[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set_pd( - e0: f64, - e1: f64, - e2: f64, - e3: f64, - e4: f64, - e5: f64, - e6: f64, - e7: f64, -) -> __m512d { - _mm512_setr_pd(e7, e6, e5, e4, e3, e2, e1, e0) +#[cfg_attr(test, assert_instr(vbroadcastss))] +pub unsafe fn _mm512_broadcastss_ps(a: __m128) -> __m512 { + simd_shuffle16(a, a, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) } -/// Equal -pub const _MM_CMPINT_EQ: _MM_CMPINT_ENUM = 0x00; -/// Less-than -pub const _MM_CMPINT_LT: _MM_CMPINT_ENUM = 0x01; -/// Less-than-or-equal -pub const _MM_CMPINT_LE: _MM_CMPINT_ENUM = 0x02; -/// False -pub const _MM_CMPINT_FALSE: _MM_CMPINT_ENUM = 0x03; -/// Not-equal -pub const _MM_CMPINT_NE: _MM_CMPINT_ENUM = 0x04; -/// Not less-than -pub const _MM_CMPINT_NLT: _MM_CMPINT_ENUM = 0x05; -/// Not less-than-or-equal -pub const _MM_CMPINT_NLE: _MM_CMPINT_ENUM = 0x06; -/// True -pub const _MM_CMPINT_TRUE: _MM_CMPINT_ENUM = 0x07; +/// Broadcast the low single-precision (32-bit) floating-point element from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastss_ps&expand=579) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcastss))] +pub unsafe fn _mm512_mask_broadcastss_ps(src: __m512, k: __mmask16, a: __m128) -> __m512 { + let broadcast = _mm512_broadcastss_ps(a).as_f32x16(); + transmute(simd_select_bitmask(k, broadcast, src.as_f32x16())) +} -/// interval [1, 2) -pub const _MM_MANT_NORM_1_2: _MM_MANTISSA_NORM_ENUM = 0x00; -/// interval [0.5, 2) -pub const _MM_MANT_NORM_P5_2: _MM_MANTISSA_NORM_ENUM = 0x01; -/// interval [0.5, 1) -pub const _MM_MANT_NORM_P5_1: _MM_MANTISSA_NORM_ENUM = 0x02; -/// interval [0.75, 1.5) -pub const _MM_MANT_NORM_P75_1P5: _MM_MANTISSA_NORM_ENUM = 0x03; +/// Broadcast the low single-precision (32-bit) floating-point element from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastss_ps&expand=580) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcastss))] +pub unsafe fn _mm512_maskz_broadcastss_ps(k: __mmask16, a: __m128) -> __m512 { + let broadcast = _mm512_broadcastss_ps(a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} -/// sign = sign(SRC) -pub const _MM_MANT_SIGN_SRC: _MM_MANTISSA_SIGN_ENUM = 0x00; -/// sign = 0 -pub const _MM_MANT_SIGN_ZERO: _MM_MANTISSA_SIGN_ENUM = 0x01; -/// DEST = NaN if sign(SRC) = 1 -pub const _MM_MANT_SIGN_NAN: _MM_MANTISSA_SIGN_ENUM = 0x02; +/// Broadcast the low double-precision (64-bit) floating-point element from a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcastsd_pd&expand=567) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcastsd))] +pub unsafe fn _mm512_broadcastsd_pd(a: __m128d) -> __m512d { + simd_shuffle8(a, a, [1, 1, 1, 1, 1, 1, 1, 1]) +} -pub const _MM_PERM_AAAA: _MM_PERM_ENUM = 0x00; -pub const _MM_PERM_AAAB: _MM_PERM_ENUM = 0x01; -pub const _MM_PERM_AAAC: _MM_PERM_ENUM = 0x02; -pub const _MM_PERM_AAAD: _MM_PERM_ENUM = 0x03; -pub const _MM_PERM_AABA: _MM_PERM_ENUM = 0x04; -pub const _MM_PERM_AABB: _MM_PERM_ENUM = 0x05; -pub const _MM_PERM_AABC: _MM_PERM_ENUM = 0x06; -pub const _MM_PERM_AABD: _MM_PERM_ENUM = 0x07; -pub const _MM_PERM_AACA: _MM_PERM_ENUM = 0x08; -pub const _MM_PERM_AACB: _MM_PERM_ENUM = 0x09; -pub const _MM_PERM_AACC: _MM_PERM_ENUM = 0x0A; -pub const _MM_PERM_AACD: _MM_PERM_ENUM = 0x0B; -pub const _MM_PERM_AADA: _MM_PERM_ENUM = 0x0C; -pub const _MM_PERM_AADB: _MM_PERM_ENUM = 0x0D; -pub const _MM_PERM_AADC: _MM_PERM_ENUM = 0x0E; -pub const _MM_PERM_AADD: _MM_PERM_ENUM = 0x0F; -pub const _MM_PERM_ABAA: _MM_PERM_ENUM = 0x10; -pub const _MM_PERM_ABAB: _MM_PERM_ENUM = 0x11; -pub const _MM_PERM_ABAC: _MM_PERM_ENUM = 0x12; -pub const _MM_PERM_ABAD: _MM_PERM_ENUM = 0x13; -pub const _MM_PERM_ABBA: _MM_PERM_ENUM = 0x14; -pub const _MM_PERM_ABBB: _MM_PERM_ENUM = 0x15; -pub const _MM_PERM_ABBC: _MM_PERM_ENUM = 0x16; -pub const _MM_PERM_ABBD: _MM_PERM_ENUM = 0x17; -pub const _MM_PERM_ABCA: _MM_PERM_ENUM = 0x18; -pub const _MM_PERM_ABCB: _MM_PERM_ENUM = 0x19; -pub const _MM_PERM_ABCC: _MM_PERM_ENUM = 0x1A; -pub const _MM_PERM_ABCD: _MM_PERM_ENUM = 0x1B; -pub const _MM_PERM_ABDA: _MM_PERM_ENUM = 0x1C; -pub const _MM_PERM_ABDB: _MM_PERM_ENUM = 0x1D; -pub const _MM_PERM_ABDC: _MM_PERM_ENUM = 0x1E; -pub const _MM_PERM_ABDD: _MM_PERM_ENUM = 0x1F; -pub const _MM_PERM_ACAA: _MM_PERM_ENUM = 0x20; -pub const _MM_PERM_ACAB: _MM_PERM_ENUM = 0x21; -pub const _MM_PERM_ACAC: _MM_PERM_ENUM = 0x22; -pub const _MM_PERM_ACAD: _MM_PERM_ENUM = 0x23; -pub const _MM_PERM_ACBA: _MM_PERM_ENUM = 0x24; -pub const _MM_PERM_ACBB: _MM_PERM_ENUM = 0x25; -pub const _MM_PERM_ACBC: _MM_PERM_ENUM = 0x26; -pub const _MM_PERM_ACBD: _MM_PERM_ENUM = 0x27; -pub const _MM_PERM_ACCA: _MM_PERM_ENUM = 0x28; -pub const _MM_PERM_ACCB: _MM_PERM_ENUM = 0x29; -pub const _MM_PERM_ACCC: _MM_PERM_ENUM = 0x2A; -pub const _MM_PERM_ACCD: _MM_PERM_ENUM = 0x2B; -pub const _MM_PERM_ACDA: _MM_PERM_ENUM = 0x2C; -pub const _MM_PERM_ACDB: _MM_PERM_ENUM = 0x2D; -pub const _MM_PERM_ACDC: _MM_PERM_ENUM = 0x2E; -pub const _MM_PERM_ACDD: _MM_PERM_ENUM = 0x2F; -pub const _MM_PERM_ADAA: _MM_PERM_ENUM = 0x30; -pub const _MM_PERM_ADAB: _MM_PERM_ENUM = 0x31; -pub const _MM_PERM_ADAC: _MM_PERM_ENUM = 0x32; -pub const _MM_PERM_ADAD: _MM_PERM_ENUM = 0x33; -pub const _MM_PERM_ADBA: _MM_PERM_ENUM = 0x34; -pub const _MM_PERM_ADBB: _MM_PERM_ENUM = 0x35; -pub const _MM_PERM_ADBC: _MM_PERM_ENUM = 0x36; -pub const _MM_PERM_ADBD: _MM_PERM_ENUM = 0x37; -pub const _MM_PERM_ADCA: _MM_PERM_ENUM = 0x38; -pub const _MM_PERM_ADCB: _MM_PERM_ENUM = 0x39; -pub const _MM_PERM_ADCC: _MM_PERM_ENUM = 0x3A; -pub const _MM_PERM_ADCD: _MM_PERM_ENUM = 0x3B; -pub const _MM_PERM_ADDA: _MM_PERM_ENUM = 0x3C; -pub const _MM_PERM_ADDB: _MM_PERM_ENUM = 0x3D; -pub const _MM_PERM_ADDC: _MM_PERM_ENUM = 0x3E; -pub const _MM_PERM_ADDD: _MM_PERM_ENUM = 0x3F; -pub const _MM_PERM_BAAA: _MM_PERM_ENUM = 0x40; -pub const _MM_PERM_BAAB: _MM_PERM_ENUM = 0x41; -pub const _MM_PERM_BAAC: _MM_PERM_ENUM = 0x42; -pub const _MM_PERM_BAAD: _MM_PERM_ENUM = 0x43; -pub const _MM_PERM_BABA: _MM_PERM_ENUM = 0x44; -pub const _MM_PERM_BABB: _MM_PERM_ENUM = 0x45; -pub const _MM_PERM_BABC: _MM_PERM_ENUM = 0x46; -pub const _MM_PERM_BABD: _MM_PERM_ENUM = 0x47; -pub const _MM_PERM_BACA: _MM_PERM_ENUM = 0x48; -pub const _MM_PERM_BACB: _MM_PERM_ENUM = 0x49; -pub const _MM_PERM_BACC: _MM_PERM_ENUM = 0x4A; -pub const _MM_PERM_BACD: _MM_PERM_ENUM = 0x4B; -pub const _MM_PERM_BADA: _MM_PERM_ENUM = 0x4C; -pub const _MM_PERM_BADB: _MM_PERM_ENUM = 0x4D; -pub const _MM_PERM_BADC: _MM_PERM_ENUM = 0x4E; -pub const _MM_PERM_BADD: _MM_PERM_ENUM = 0x4F; -pub const _MM_PERM_BBAA: _MM_PERM_ENUM = 0x50; -pub const _MM_PERM_BBAB: _MM_PERM_ENUM = 0x51; -pub const _MM_PERM_BBAC: _MM_PERM_ENUM = 0x52; -pub const _MM_PERM_BBAD: _MM_PERM_ENUM = 0x53; -pub const _MM_PERM_BBBA: _MM_PERM_ENUM = 0x54; -pub const _MM_PERM_BBBB: _MM_PERM_ENUM = 0x55; -pub const _MM_PERM_BBBC: _MM_PERM_ENUM = 0x56; -pub const _MM_PERM_BBBD: _MM_PERM_ENUM = 0x57; -pub const _MM_PERM_BBCA: _MM_PERM_ENUM = 0x58; -pub const _MM_PERM_BBCB: _MM_PERM_ENUM = 0x59; -pub const _MM_PERM_BBCC: _MM_PERM_ENUM = 0x5A; -pub const _MM_PERM_BBCD: _MM_PERM_ENUM = 0x5B; -pub const _MM_PERM_BBDA: _MM_PERM_ENUM = 0x5C; -pub const _MM_PERM_BBDB: _MM_PERM_ENUM = 0x5D; -pub const _MM_PERM_BBDC: _MM_PERM_ENUM = 0x5E; -pub const _MM_PERM_BBDD: _MM_PERM_ENUM = 0x5F; -pub const _MM_PERM_BCAA: _MM_PERM_ENUM = 0x60; -pub const _MM_PERM_BCAB: _MM_PERM_ENUM = 0x61; -pub const _MM_PERM_BCAC: _MM_PERM_ENUM = 0x62; -pub const _MM_PERM_BCAD: _MM_PERM_ENUM = 0x63; -pub const _MM_PERM_BCBA: _MM_PERM_ENUM = 0x64; -pub const _MM_PERM_BCBB: _MM_PERM_ENUM = 0x65; -pub const _MM_PERM_BCBC: _MM_PERM_ENUM = 0x66; -pub const _MM_PERM_BCBD: _MM_PERM_ENUM = 0x67; -pub const _MM_PERM_BCCA: _MM_PERM_ENUM = 0x68; -pub const _MM_PERM_BCCB: _MM_PERM_ENUM = 0x69; -pub const _MM_PERM_BCCC: _MM_PERM_ENUM = 0x6A; -pub const _MM_PERM_BCCD: _MM_PERM_ENUM = 0x6B; -pub const _MM_PERM_BCDA: _MM_PERM_ENUM = 0x6C; -pub const _MM_PERM_BCDB: _MM_PERM_ENUM = 0x6D; -pub const _MM_PERM_BCDC: _MM_PERM_ENUM = 0x6E; -pub const _MM_PERM_BCDD: _MM_PERM_ENUM = 0x6F; -pub const _MM_PERM_BDAA: _MM_PERM_ENUM = 0x70; -pub const _MM_PERM_BDAB: _MM_PERM_ENUM = 0x71; -pub const _MM_PERM_BDAC: _MM_PERM_ENUM = 0x72; -pub const _MM_PERM_BDAD: _MM_PERM_ENUM = 0x73; -pub const _MM_PERM_BDBA: _MM_PERM_ENUM = 0x74; -pub const _MM_PERM_BDBB: _MM_PERM_ENUM = 0x75; -pub const _MM_PERM_BDBC: _MM_PERM_ENUM = 0x76; -pub const _MM_PERM_BDBD: _MM_PERM_ENUM = 0x77; -pub const _MM_PERM_BDCA: _MM_PERM_ENUM = 0x78; -pub const _MM_PERM_BDCB: _MM_PERM_ENUM = 0x79; -pub const _MM_PERM_BDCC: _MM_PERM_ENUM = 0x7A; -pub const _MM_PERM_BDCD: _MM_PERM_ENUM = 0x7B; -pub const _MM_PERM_BDDA: _MM_PERM_ENUM = 0x7C; -pub const _MM_PERM_BDDB: _MM_PERM_ENUM = 0x7D; -pub const _MM_PERM_BDDC: _MM_PERM_ENUM = 0x7E; -pub const _MM_PERM_BDDD: _MM_PERM_ENUM = 0x7F; -pub const _MM_PERM_CAAA: _MM_PERM_ENUM = 0x80; -pub const _MM_PERM_CAAB: _MM_PERM_ENUM = 0x81; -pub const _MM_PERM_CAAC: _MM_PERM_ENUM = 0x82; -pub const _MM_PERM_CAAD: _MM_PERM_ENUM = 0x83; -pub const _MM_PERM_CABA: _MM_PERM_ENUM = 0x84; -pub const _MM_PERM_CABB: _MM_PERM_ENUM = 0x85; -pub const _MM_PERM_CABC: _MM_PERM_ENUM = 0x86; -pub const _MM_PERM_CABD: _MM_PERM_ENUM = 0x87; -pub const _MM_PERM_CACA: _MM_PERM_ENUM = 0x88; -pub const _MM_PERM_CACB: _MM_PERM_ENUM = 0x89; -pub const _MM_PERM_CACC: _MM_PERM_ENUM = 0x8A; -pub const _MM_PERM_CACD: _MM_PERM_ENUM = 0x8B; -pub const _MM_PERM_CADA: _MM_PERM_ENUM = 0x8C; -pub const _MM_PERM_CADB: _MM_PERM_ENUM = 0x8D; -pub const _MM_PERM_CADC: _MM_PERM_ENUM = 0x8E; -pub const _MM_PERM_CADD: _MM_PERM_ENUM = 0x8F; -pub const _MM_PERM_CBAA: _MM_PERM_ENUM = 0x90; -pub const _MM_PERM_CBAB: _MM_PERM_ENUM = 0x91; -pub const _MM_PERM_CBAC: _MM_PERM_ENUM = 0x92; -pub const _MM_PERM_CBAD: _MM_PERM_ENUM = 0x93; -pub const _MM_PERM_CBBA: _MM_PERM_ENUM = 0x94; -pub const _MM_PERM_CBBB: _MM_PERM_ENUM = 0x95; -pub const _MM_PERM_CBBC: _MM_PERM_ENUM = 0x96; -pub const _MM_PERM_CBBD: _MM_PERM_ENUM = 0x97; -pub const _MM_PERM_CBCA: _MM_PERM_ENUM = 0x98; -pub const _MM_PERM_CBCB: _MM_PERM_ENUM = 0x99; -pub const _MM_PERM_CBCC: _MM_PERM_ENUM = 0x9A; -pub const _MM_PERM_CBCD: _MM_PERM_ENUM = 0x9B; -pub const _MM_PERM_CBDA: _MM_PERM_ENUM = 0x9C; -pub const _MM_PERM_CBDB: _MM_PERM_ENUM = 0x9D; -pub const _MM_PERM_CBDC: _MM_PERM_ENUM = 0x9E; -pub const _MM_PERM_CBDD: _MM_PERM_ENUM = 0x9F; -pub const _MM_PERM_CCAA: _MM_PERM_ENUM = 0xA0; -pub const _MM_PERM_CCAB: _MM_PERM_ENUM = 0xA1; -pub const _MM_PERM_CCAC: _MM_PERM_ENUM = 0xA2; -pub const _MM_PERM_CCAD: _MM_PERM_ENUM = 0xA3; -pub const _MM_PERM_CCBA: _MM_PERM_ENUM = 0xA4; +/// Broadcast the low double-precision (64-bit) floating-point element from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcastsd_pd&expand=568) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcastsd))] +pub unsafe fn _mm512_mask_broadcastsd_pd(src: __m512d, k: __mmask8, a: __m128d) -> __m512d { + let broadcast = _mm512_broadcastsd_pd(a).as_f64x8(); + transmute(simd_select_bitmask(k, broadcast, src.as_f64x8())) +} + +/// Broadcast the low double-precision (64-bit) floating-point element from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcastsd_pd&expand=569) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcastsd))] +pub unsafe fn _mm512_maskz_broadcastsd_pd(k: __mmask8, a: __m128d) -> __m512d { + let broadcast = _mm512_broadcastsd_pd(a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the 4 packed 32-bit integers from a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_i32x4&expand=510) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcasti32x4, linux: vshuf +pub unsafe fn _mm512_broadcast_i32x4(a: __m128i) -> __m512i { + let a = _mm512_castsi128_si512(a).as_i32x16(); + let ret: i32x16 = simd_shuffle16(a, a, [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]); + transmute(ret) +} + +/// Broadcast the 4 packed 32-bit integers from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_i32x4&expand=511) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcasti32x4, linux: vshuf +pub unsafe fn _mm512_mask_broadcast_i32x4(src: __m512i, k: __mmask16, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcast_i32x4(a).as_i32x16(); + transmute(simd_select_bitmask(k, broadcast, src.as_i32x16())) +} + +/// Broadcast the 4 packed 32-bit integers from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_i32x4&expand=512) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcasti32x4, linux: vshuf +pub unsafe fn _mm512_maskz_broadcast_i32x4(k: __mmask16, a: __m128i) -> __m512i { + let broadcast = _mm512_broadcast_i32x4(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the 4 packed 64-bit integers from a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_i64x4&expand=522) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcasti64x4, linux: vperm +pub unsafe fn _mm512_broadcast_i64x4(a: __m256i) -> __m512i { + simd_shuffle8(a, a, [0, 1, 2, 3, 0, 1, 2, 3]) +} + +/// Broadcast the 4 packed 64-bit integers from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_i64x4&expand=523) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcasti64x4, linux: vperm +pub unsafe fn _mm512_mask_broadcast_i64x4(src: __m512i, k: __mmask8, a: __m256i) -> __m512i { + let broadcast = _mm512_broadcast_i64x4(a).as_i64x8(); + transmute(simd_select_bitmask(k, broadcast, src.as_i64x8())) +} + +/// Broadcast the 4 packed 64-bit integers from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_i64x4&expand=524) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcasti64x4, linux: vperm +pub unsafe fn _mm512_maskz_broadcast_i64x4(k: __mmask8, a: __m256i) -> __m512i { + let broadcast = _mm512_broadcast_i64x4(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the 4 packed single-precision (32-bit) floating-point elements from a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_f32x4&expand=483) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcastf32x4, linux: vshuf +pub unsafe fn _mm512_broadcast_f32x4(a: __m128) -> __m512 { + simd_shuffle16(a, a, [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]) +} + +/// Broadcast the 4 packed single-precision (32-bit) floating-point elements from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_f32x4&expand=484) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcastf32x4, linux: vshu +pub unsafe fn _mm512_mask_broadcast_f32x4(src: __m512, k: __mmask16, a: __m128) -> __m512 { + let broadcast = _mm512_broadcast_f32x4(a).as_f32x16(); + transmute(simd_select_bitmask(k, broadcast, src.as_f32x16())) +} + +/// Broadcast the 4 packed single-precision (32-bit) floating-point elements from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_f32x4&expand=485) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcastf32x4, linux: vshu +pub unsafe fn _mm512_maskz_broadcast_f32x4(k: __mmask16, a: __m128) -> __m512 { + let broadcast = _mm512_broadcast_f32x4(a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Broadcast the 4 packed double-precision (64-bit) floating-point elements from a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_broadcast_f64x4&expand=495) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcastf64x4, linux: vperm +pub unsafe fn _mm512_broadcast_f64x4(a: __m256d) -> __m512d { + simd_shuffle8(a, a, [0, 1, 2, 3, 0, 1, 2, 3]) +} + +/// Broadcast the 4 packed double-precision (64-bit) floating-point elements from a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_broadcast_f64x4&expand=496) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcastf64x4, linux: vper +pub unsafe fn _mm512_mask_broadcast_f64x4(src: __m512d, k: __mmask8, a: __m256d) -> __m512d { + let broadcast = _mm512_broadcast_f64x4(a).as_f64x8(); + transmute(simd_select_bitmask(k, broadcast, src.as_f64x8())) +} + +/// Broadcast the 4 packed double-precision (64-bit) floating-point elements from a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_broadcast_f64x4&expand=497) +#[inline] +#[target_feature(enable = "avx512f")] //msvc: vbroadcastf64x4, linux: vper +pub unsafe fn _mm512_maskz_broadcast_f64x4(k: __mmask8, a: __m256d) -> __m512d { + let broadcast = _mm512_broadcast_f64x4(a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, broadcast, zero)) +} + +/// Blend packed 32-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_epi32&expand=435) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovdqa32))] //should be vpblendmd +pub unsafe fn _mm512_mask_blend_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + transmute(simd_select_bitmask(k, b.as_i32x16(), a.as_i32x16())) +} + +/// Blend packed 64-bit integers from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_epi64&expand=438) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovdqa64))] //should be vpblendmq +pub unsafe fn _mm512_mask_blend_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + transmute(simd_select_bitmask(k, b.as_i64x8(), a.as_i64x8())) +} + +/// Blend packed single-precision (32-bit) floating-point elements from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_ps&expand=451) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vpblendmps +pub unsafe fn _mm512_mask_blend_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + transmute(simd_select_bitmask(k, b.as_f32x16(), a.as_f32x16())) +} + +/// Blend packed double-precision (64-bit) floating-point elements from a and b using control mask k, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_blend_pd&expand=446) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovapd))] //should be vpblendmpd +pub unsafe fn _mm512_mask_blend_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + transmute(simd_select_bitmask(k, b.as_f64x8(), a.as_f64x8())) +} + +/// Concatenate a and b into a 128-byte immediate result, shift the result right by imm8 32-bit elements, and store the low 64 bytes (16 elements) in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_alignr_epi32&expand=245) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(valignd, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_alignr_epi32(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let a = a.as_i32x16(); + let b = b.as_i32x16(); + let imm8: i32 = imm8 % 16; + let r: i32x16 = match imm8 { + 0 => simd_shuffle16( + a, + b, + [ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ], + ), + 1 => simd_shuffle16( + a, + b, + [ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, + ], + ), + 2 => simd_shuffle16( + a, + b, + [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1], + ), + 3 => simd_shuffle16( + a, + b, + [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2], + ), + 4 => simd_shuffle16( + a, + b, + [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3], + ), + 5 => simd_shuffle16( + a, + b, + [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4], + ), + 6 => simd_shuffle16( + a, + b, + [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5], + ), + 7 => simd_shuffle16( + a, + b, + [23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6], + ), + 8 => simd_shuffle16( + a, + b, + [24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7], + ), + 9 => simd_shuffle16( + a, + b, + [25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8], + ), + 10 => simd_shuffle16(a, b, [26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + 11 => simd_shuffle16(a, b, [27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + 12 => simd_shuffle16(a, b, [28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]), + 13 => simd_shuffle16(a, b, [29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), + 14 => simd_shuffle16(a, b, [30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]), + _ => simd_shuffle16(a, b, [31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), + }; + transmute(r) +} + +/// Concatenate a and b into a 128-byte immediate result, shift the result right by imm8 32-bit elements, and store the low 64 bytes (16 elements) in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_alignr_epi32&expand=246) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(valignd, imm8 = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_alignr_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let a = a.as_i32x16(); + let b = b.as_i32x16(); + let imm8: i32 = imm8 % 16; + let r: i32x16 = match imm8 { + 0 => simd_shuffle16( + a, + b, + [ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ], + ), + 1 => simd_shuffle16( + a, + b, + [ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, + ], + ), + 2 => simd_shuffle16( + a, + b, + [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1], + ), + 3 => simd_shuffle16( + a, + b, + [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2], + ), + 4 => simd_shuffle16( + a, + b, + [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3], + ), + 5 => simd_shuffle16( + a, + b, + [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4], + ), + 6 => simd_shuffle16( + a, + b, + [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5], + ), + 7 => simd_shuffle16( + a, + b, + [23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6], + ), + 8 => simd_shuffle16( + a, + b, + [24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7], + ), + 9 => simd_shuffle16( + a, + b, + [25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8], + ), + 10 => simd_shuffle16(a, b, [26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + 11 => simd_shuffle16(a, b, [27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + 12 => simd_shuffle16(a, b, [28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]), + 13 => simd_shuffle16(a, b, [29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), + 14 => simd_shuffle16(a, b, [30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]), + _ => simd_shuffle16(a, b, [31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), + }; + transmute(simd_select_bitmask(k, r, src.as_i32x16())) +} + +/// Concatenate a and b into a 128-byte immediate result, shift the result right by imm8 32-bit elements, and stores the low 64 bytes (16 elements) in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_alignr_epi32&expand=247) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(valignd, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_alignr_epi32( + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let a = a.as_i32x16(); + let b = b.as_i32x16(); + let imm8: i32 = imm8 % 16; + let r: i32x16 = match imm8 { + 0 => simd_shuffle16( + a, + b, + [ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ], + ), + 1 => simd_shuffle16( + a, + b, + [ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, + ], + ), + 2 => simd_shuffle16( + a, + b, + [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1], + ), + 3 => simd_shuffle16( + a, + b, + [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2], + ), + 4 => simd_shuffle16( + a, + b, + [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3], + ), + 5 => simd_shuffle16( + a, + b, + [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4], + ), + 6 => simd_shuffle16( + a, + b, + [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5], + ), + 7 => simd_shuffle16( + a, + b, + [23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6], + ), + 8 => simd_shuffle16( + a, + b, + [24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7], + ), + 9 => simd_shuffle16( + a, + b, + [25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8], + ), + 10 => simd_shuffle16(a, b, [26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + 11 => simd_shuffle16(a, b, [27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + 12 => simd_shuffle16(a, b, [28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]), + 13 => simd_shuffle16(a, b, [29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), + 14 => simd_shuffle16(a, b, [30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]), + _ => simd_shuffle16(a, b, [31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), + }; + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Concatenate a and b into a 128-byte immediate result, shift the result right by imm8 64-bit elements, and store the low 64 bytes (8 elements) in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_alignr_epi64&expand=254) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(valignq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_alignr_epi64(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8: i32 = imm8 % 8; + let r: i64x8 = match imm8 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 12, 13, 14, 15]), + 1 => simd_shuffle8(a, b, [9, 10, 11, 12, 13, 14, 15, 0]), + 2 => simd_shuffle8(a, b, [10, 11, 12, 13, 14, 15, 0, 1]), + 3 => simd_shuffle8(a, b, [11, 12, 13, 14, 15, 0, 1, 2]), + 4 => simd_shuffle8(a, b, [12, 13, 14, 15, 0, 1, 2, 3]), + 5 => simd_shuffle8(a, b, [13, 14, 15, 0, 1, 2, 3, 4]), + 6 => simd_shuffle8(a, b, [14, 15, 0, 1, 2, 3, 4, 5]), + _ => simd_shuffle8(a, b, [15, 0, 1, 2, 3, 4, 5, 6]), + }; + transmute(r) +} + +/// Concatenate a and b into a 128-byte immediate result, shift the result right by imm8 64-bit elements, and store the low 64 bytes (8 elements) in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_alignr_epi64&expand=255) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(valignq, imm8 = 1))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_alignr_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8: i32 = imm8 % 8; + let r: i64x8 = match imm8 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 12, 13, 14, 15]), + 1 => simd_shuffle8(a, b, [9, 10, 11, 12, 13, 14, 15, 0]), + 2 => simd_shuffle8(a, b, [10, 11, 12, 13, 14, 15, 0, 1]), + 3 => simd_shuffle8(a, b, [11, 12, 13, 14, 15, 0, 1, 2]), + 4 => simd_shuffle8(a, b, [12, 13, 14, 15, 0, 1, 2, 3]), + 5 => simd_shuffle8(a, b, [13, 14, 15, 0, 1, 2, 3, 4]), + 6 => simd_shuffle8(a, b, [14, 15, 0, 1, 2, 3, 4, 5]), + _ => simd_shuffle8(a, b, [15, 0, 1, 2, 3, 4, 5, 6]), + }; + transmute(simd_select_bitmask(k, r, src.as_i64x8())) +} + +/// Concatenate a and b into a 128-byte immediate result, shift the result right by imm8 64-bit elements, and stores the low 64 bytes (8 elements) in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_alignr_epi64&expand=256) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(valignq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_alignr_epi64(k: __mmask8, a: __m512i, b: __m512i, imm8: i32) -> __m512i { + assert!(imm8 >= 0 && imm8 <= 255); + let imm8: i32 = imm8 % 8; + let r: i64x8 = match imm8 { + 0 => simd_shuffle8(a, b, [8, 9, 10, 11, 12, 13, 14, 15]), + 1 => simd_shuffle8(a, b, [9, 10, 11, 12, 13, 14, 15, 0]), + 2 => simd_shuffle8(a, b, [10, 11, 12, 13, 14, 15, 0, 1]), + 3 => simd_shuffle8(a, b, [11, 12, 13, 14, 15, 0, 1, 2]), + 4 => simd_shuffle8(a, b, [12, 13, 14, 15, 0, 1, 2, 3]), + 5 => simd_shuffle8(a, b, [13, 14, 15, 0, 1, 2, 3, 4]), + 6 => simd_shuffle8(a, b, [14, 15, 0, 1, 2, 3, 4, 5]), + _ => simd_shuffle8(a, b, [15, 0, 1, 2, 3, 4, 5, 6]), + }; + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi32&expand=272) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] //should be vpandd, but generate vpandq +pub unsafe fn _mm512_and_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i32x16(), b.as_i32x16())) +} + +/// Performs element-by-element bitwise AND between packed 32-bit integer elements of v2 and v3, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi32&expand=273) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_mask_and_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, and, src.as_i32x16())) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_epi32&expand=274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_maskz_and_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, and, zero)) +} + +/// Compute the bitwise AND of 512 bits (composed of packed 64-bit integers) in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi64&expand=279) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_and_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise AND of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi64&expand=280) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_mask_and_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, and, src.as_i64x8())) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_Epi32&expand=274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_maskz_and_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, and, zero)) +} + +/// Compute the bitwise AND of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_si512&expand=302) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_and_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi32&expand=4042) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi32&expand=4040) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpord))] +pub unsafe fn _mm512_mask_or_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, or, src.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi32&expand=4041) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpord))] +pub unsafe fn _mm512_maskz_or_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, or, zero)) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the resut in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi64&expand=4051) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi64&expand=4049) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_mask_or_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, or, src.as_i64x8())) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi64&expand=4050) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_maskz_or_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, or, zero)) +} + +/// Compute the bitwise OR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_si512&expand=4072) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi32&expand=6142) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi32&expand=6140) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxord))] +pub unsafe fn _mm512_mask_xor_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, xor, src.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi32&expand=6141) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxord))] +pub unsafe fn _mm512_maskz_xor_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, xor, zero)) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi64&expand=6151) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi64&expand=6149) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_mask_xor_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, xor, src.as_i64x8())) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi64&expand=6150) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_maskz_xor_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, xor, zero)) +} + +/// Compute the bitwise XOR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_si512&expand=6172) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise NOT of packed 32-bit integers in a and then AND with b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_andnot_epi32&expand=310) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandnq))] //should be vpandnd +pub unsafe fn _mm512_andnot_epi32(a: __m512i, b: __m512i) -> __m512i { + _mm512_and_epi32(_mm512_xor_epi32(a, _mm512_set1_epi32(u32::MAX as i32)), b) +} + +/// Compute the bitwise NOT of packed 32-bit integers in a and then AND with b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_andnot_epi32&expand=311) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandnd))] +pub unsafe fn _mm512_mask_andnot_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let andnot = _mm512_andnot_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, andnot, src.as_i32x16())) +} + +/// Compute the bitwise NOT of packed 32-bit integers in a and then AND with b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_andnot_epi32&expand=312) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandnd))] +pub unsafe fn _mm512_maskz_andnot_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let andnot = _mm512_andnot_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, andnot, zero)) +} + +/// Compute the bitwise NOT of 512 bits (composed of packed 64-bit integers) in a and then AND with b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_andnot_epi64&expand=317) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandnq))] //should be vpandnd +pub unsafe fn _mm512_andnot_epi64(a: __m512i, b: __m512i) -> __m512i { + _mm512_and_epi64(_mm512_xor_epi64(a, _mm512_set1_epi64(u64::MAX as i64)), b) +} + +/// Compute the bitwise NOT of packed 64-bit integers in a and then AND with b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_andnot_epi64&expand=318) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandnq))] +pub unsafe fn _mm512_mask_andnot_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, +) -> __m512i { + let andnot = _mm512_andnot_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, andnot, src.as_i64x8())) +} + +/// Compute the bitwise NOT of packed 64-bit integers in a and then AND with b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_andnot_epi64&expand=319) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandnq))] +pub unsafe fn _mm512_maskz_andnot_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let andnot = _mm512_andnot_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, andnot, zero)) +} + +/// Compute the bitwise NOT of 512 bits (representing integer data) in a and then AND with b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_andnot_si512&expand=340) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandnq))] +pub unsafe fn _mm512_andnot_si512(a: __m512i, b: __m512i) -> __m512i { + _mm512_and_epi64(_mm512_xor_epi64(a, _mm512_set1_epi64(u64::MAX as i64)), b) +} + +/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kand_mask16&expand=3212) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw +pub unsafe fn _kand_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a & b) +} + +/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kand&expand=3210) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kand(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a & b) +} + +/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kor_mask16&expand=3239) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw +pub unsafe fn _kor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a | b) +} + +/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kor&expand=3237) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw +pub unsafe fn _mm512_kor(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a | b) +} + +/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxor_mask16&expand=3291) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw +pub unsafe fn _kxor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a ^ b) +} + +/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxor&expand=3289) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw +pub unsafe fn _mm512_kxor(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a ^ b) +} + +/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=knot_mask16&expand=3233) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _knot_mask16(a: __mmask16) -> __mmask16 { + transmute(a ^ 0b11111111_11111111) +} + +/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_knot&expand=3231) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_knot(a: __mmask16) -> __mmask16 { + transmute(a ^ 0b11111111_11111111) +} + +/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kandn_mask16&expand=3218) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(not))] // generate normal and, not code instead of kandnw +pub unsafe fn _kandn_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_kand(_mm512_knot(a), b) +} + +/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kandn&expand=3216) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kandn(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_kand(_mm512_knot(a), b) +} + +/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxnor_mask16&expand=3285) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor, not code instead of kxnorw +pub unsafe fn _kxnor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_knot(_mm512_kxor(a, b)) +} + +/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxnor&expand=3283) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kxnor(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_knot(_mm512_kxor(a, b)) +} + +/// Copy 16-bit mask a to k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm512_kmov&expand=3228) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kmovw +pub unsafe fn _mm512_kmov(a: __mmask16) -> __mmask16 { + let r: u16 = a; + transmute(r) +} + +/// Converts integer mask into bitmask, storing the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_int2mask&expand=3189) +#[inline] +#[target_feature(enable = "avx512f")] // generate normal and code instead of kmovw +pub unsafe fn _mm512_int2mask(mask: i32) -> __mmask16 { + let r: u16 = mask as u16; + transmute(r) +} + +/// Converts bit mask k1 into an integer value, storing the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2int&expand=3544) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kmovw +pub unsafe fn _mm512_mask2int(k1: __mmask16) -> i32 { + let r: i32 = k1 as i32; + transmute(r) +} + +/// Unpack and interleave 8 bits from masks a and b, and store the 16-bit result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kunpackb&expand=3280) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kunpckbw +pub unsafe fn _mm512_kunpackb(a: __mmask16, b: __mmask16) -> __mmask16 { + let a = a & 0b00000000_11111111; + let b = b & 0b11111111_00000000; + transmute(a | b) +} + +/// Performs bitwise OR between k1 and k2, storing the result in dst. CF flag is set if dst consists of all 1's. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kortestc&expand=3247) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(cmp))] // generate normal and code instead of kortestw +pub unsafe fn _mm512_kortestc(a: __mmask16, b: __mmask16) -> i32 { + let r = a | b; + if r == 0b11111111_11111111 { + 1 + } else { + 0 + } +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, producing intermediate 32-bit values, and set the corresponding bit in result mask k if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_test_epi32_mask&expand=5890) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestmd))] +pub unsafe fn _mm512_test_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + let and = _mm512_and_epi32(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpneq_epi32_mask(and, zero) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, producing intermediate 32-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_test_epi32_mask&expand=5889) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestmd))] +pub unsafe fn _mm512_mask_test_epi32_mask(k: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + let and = _mm512_and_epi32(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpneq_epi32_mask(k, and, zero) +} + +/// Compute the bitwise AND of packed 64-bit integers in a and b, producing intermediate 64-bit values, and set the corresponding bit in result mask k if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_test_epi64_mask&expand=5896) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestmq))] +pub unsafe fn _mm512_test_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + let and = _mm512_and_epi64(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpneq_epi64_mask(and, zero) +} + +/// Compute the bitwise AND of packed 64-bit integers in a and b, producing intermediate 64-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is non-zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_test_epi64_mask&expand=5895) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestmq))] +pub unsafe fn _mm512_mask_test_epi64_mask(k: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + let and = _mm512_and_epi64(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpneq_epi64_mask(k, and, zero) +} + +/// Compute the bitwise NAND of packed 32-bit integers in a and b, producing intermediate 32-bit values, and set the corresponding bit in result mask k if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_testn_epi32_mask&expand=5921) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestnmd))] +pub unsafe fn _mm512_testn_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + let and = _mm512_and_epi32(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpeq_epi32_mask(and, zero) +} + +/// Compute the bitwise NAND of packed 32-bit integers in a and b, producing intermediate 32-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_testn_epi32_mask&expand=5920) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestnmd))] +pub unsafe fn _mm512_mask_testn_epi32_mask(k: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + let and = _mm512_and_epi32(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpeq_epi32_mask(k, and, zero) +} + +/// Compute the bitwise NAND of packed 64-bit integers in a and b, producing intermediate 64-bit values, and set the corresponding bit in result mask k if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_testn_epi64_mask&expand=5927) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestnmq))] +pub unsafe fn _mm512_testn_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + let and = _mm512_and_epi64(a, b); + let zero = _mm512_setzero_si512(); + _mm512_cmpeq_epi64_mask(and, zero) +} + +/// Compute the bitwise NAND of packed 64-bit integers in a and b, producing intermediate 64-bit values, and set the corresponding bit in result mask k (subject to writemask k) if the intermediate value is zero. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_testn_epi64_mask&expand=5926) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vptestnmq))] +pub unsafe fn _mm512_mask_testn_epi64_mask(k: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + let and = _mm512_and_epi64(a, b); + let zero = _mm512_setzero_si512(); + _mm512_mask_cmpeq_epi64_mask(k, and, zero) +} + +/// Store 512-bits (composed of 16 packed single-precision (32-bit) floating-point elements) from a into memory using a non-temporal memory hint. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_stream_ps&expand=5671) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovntps))] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe fn _mm512_stream_ps(mem_addr: *mut f32, a: __m512) { + intrinsics::nontemporal_store(mem_addr as *mut __m512, a); +} + +/// Store 512-bits (composed of 8 packed double-precision (64-bit) floating-point elements) from a into memory using a non-temporal memory hint. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_stream_pd&expand=5667) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovntps))] //should be vmovntpd +#[allow(clippy::cast_ptr_alignment)] +pub unsafe fn _mm512_stream_pd(mem_addr: *mut f64, a: __m512d) { + intrinsics::nontemporal_store(mem_addr as *mut __m512d, a); +} + +/// Store 512-bits of integer data from a into memory using a non-temporal memory hint. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_stream_si512&expand=5675) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovntps))] //should be vmovntdq +#[allow(clippy::cast_ptr_alignment)] +pub unsafe fn _mm512_stream_si512(mem_addr: *mut i64, a: __m512i) { + intrinsics::nontemporal_store(mem_addr as *mut __m512i, a); +} + +/// Sets packed 32-bit integers in `dst` with the supplied values. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_ps( + e0: f32, + e1: f32, + e2: f32, + e3: f32, + e4: f32, + e5: f32, + e6: f32, + e7: f32, + e8: f32, + e9: f32, + e10: f32, + e11: f32, + e12: f32, + e13: f32, + e14: f32, + e15: f32, +) -> __m512 { + _mm512_setr_ps( + e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0, + ) +} + +/// Sets packed 32-bit integers in `dst` with the supplied values in +/// reverse order. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr_ps( + e0: f32, + e1: f32, + e2: f32, + e3: f32, + e4: f32, + e5: f32, + e6: f32, + e7: f32, + e8: f32, + e9: f32, + e10: f32, + e11: f32, + e12: f32, + e13: f32, + e14: f32, + e15: f32, +) -> __m512 { + let r = f32x16::new( + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, + ); + transmute(r) +} + +/// Broadcast 64-bit float `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_pd(a: f64) -> __m512d { + transmute(f64x8::splat(a)) +} + +/// Broadcast 32-bit float `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_ps(a: f32) -> __m512 { + transmute(f32x16::splat(a)) +} + +/// Sets packed 32-bit integers in `dst` with the supplied values. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_epi32( + e15: i32, + e14: i32, + e13: i32, + e12: i32, + e11: i32, + e10: i32, + e9: i32, + e8: i32, + e7: i32, + e6: i32, + e5: i32, + e4: i32, + e3: i32, + e2: i32, + e1: i32, + e0: i32, +) -> __m512i { + _mm512_setr_epi32( + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, + ) +} + +/// Broadcast 8-bit integer a to all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set1_epi8&expand=4972) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_epi8(a: i8) -> __m512i { + transmute(i8x64::splat(a)) +} + +/// Broadcast the low packed 16-bit integer from a to all all elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set1_epi16&expand=4944) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_epi16(a: i16) -> __m512i { + transmute(i16x32::splat(a)) +} + +/// Broadcast 32-bit integer `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_epi32(a: i32) -> __m512i { + transmute(i32x16::splat(a)) +} + +/// Broadcast 32-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_set1_epi32&expand=4951) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcastd))] +pub unsafe fn _mm512_mask_set1_epi32(src: __m512i, k: __mmask16, a: i32) -> __m512i { + let r = _mm512_set1_epi32(a).as_i32x16(); + transmute(simd_select_bitmask(k, r, src.as_i32x16())) +} + +/// Broadcast 32-bit integer a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_set1_epi32&expand=4952) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcastd))] +pub unsafe fn _mm512_maskz_set1_epi32(k: __mmask16, a: i32) -> __m512i { + let r = _mm512_set1_epi32(a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Broadcast 64-bit integer `a` to all elements of `dst`. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set1_epi64(a: i64) -> __m512i { + transmute(i64x8::splat(a)) +} + +/// Broadcast 64-bit integer a to all elements of dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_set1_epi64&expand=4959) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcastq))] +pub unsafe fn _mm512_mask_set1_epi64(src: __m512i, k: __mmask8, a: i64) -> __m512i { + let r = _mm512_set1_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, r, src.as_i64x8())) +} + +/// Broadcast 64-bit integer a to all elements of dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_set1_epi64&expand=4960) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcastq))] +pub unsafe fn _mm512_maskz_set1_epi64(k: __mmask8, a: i64) -> __m512i { + let r = _mm512_set1_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Set packed 64-bit integers in dst with the repeated 4 element sequence. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_set4_epi64&expand=4983) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set4_epi64(d: i64, c: i64, b: i64, a: i64) -> __m512i { + let r = i64x8::new(d, c, b, a, d, c, b, a); + transmute(r) +} + +/// Set packed 64-bit integers in dst with the repeated 4 element sequence in reverse order. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_setr4_epi64&expand=5010) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr4_epi64(d: i64, c: i64, b: i64, a: i64) -> __m512i { + let r = i64x8::new(a, b, c, d, a, b, c, d); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmplt_ps_mask&expand=1074) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmplt_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_LT_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmplt_ps_mask&expand=1075) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmplt_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_LT_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for not-less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmpnlt_ps_mask&expand=1154) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnlt_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_NLT_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for not-less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmpnlt_ps_mask&expand=1155) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnlt_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_NLT_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmple_ps_mask&expand=1013) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmple_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_LE_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmple_ps_mask&expand=1014) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmple_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_LE_OS) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for not-less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmpnle_ps_mask&expand=1146) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnle_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_NLE_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for not-less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmpnle_ps_mask&expand=1147) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnle_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_NLE_US) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmpeq_ps_mask&expand=828) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpeq_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_EQ_OQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmpeq_ps_mask&expand=829) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpeq_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_EQ_OQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmpneq_ps_mask&expand=1130) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpneq_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_NEQ_UQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmpneq_ps_mask&expand=1131) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpneq_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_NEQ_UQ) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmp_ps_mask&expand=749) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_ps_mask(a: __m512, b: __m512, imm8: i32) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmpps( + a.as_f32x16(), + b.as_f32x16(), + $imm5, + neg_one, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmp_ps_mask&expand=750) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_ps_mask(k1: __mmask16, a: __m512, b: __m512, imm8: i32) -> __mmask16 { + macro_rules! call { + ($imm5:expr) => { + vcmpps( + a.as_f32x16(), + b.as_f32x16(), + $imm5, + k1 as i16, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cmp_round_ps_mask&expand=753) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm512_cmp_round_ps_mask(a: __m512, b: __m512, imm8: i32, sae: i32) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cmp_round_ps_mask&expand=754) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm512_mask_cmp_round_ps_mask( + m: __mmask16, + a: __m512, + b: __m512, + imm8: i32, + sae: i32, +) -> __mmask16 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpps(a.as_f32x16(), b.as_f32x16(), $imm5, m as i16, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpord_ps_mask&expand=1162) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpord_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_ORD_Q) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if neither is NaN, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpord_ps_mask&expand=1163) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpord_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_ORD_Q) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_ps_mask&expand=1170) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpunord_ps_mask(a: __m512, b: __m512) -> __mmask16 { + _mm512_cmp_ps_mask(a, b, _CMP_UNORD_Q) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b to see if either is NaN, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_ps_mask&expand=1171) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpunord_ps_mask(k1: __mmask16, a: __m512, b: __m512) -> __mmask16 { + _mm512_mask_cmp_ps_mask(k1, a, b, _CMP_UNORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_pd_mask&expand=1071) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmplt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_LT_OS) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_pd_mask&expand=1072) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmplt_pd_mask(k1: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(k1, a, b, _CMP_LT_OS) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for not-less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnlt_pd_mask&expand=1151) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnlt_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_NLT_US) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for not-less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnlt_pd_mask&expand=1152) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnlt_pd_mask(m: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(m, a, b, _CMP_NLT_US) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_pd_mask&expand=1010) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmple_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_LE_OS) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_pd_mask&expand=1011) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmple_pd_mask(k1: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(k1, a, b, _CMP_LE_OS) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for not-less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnle_pd_mask&expand=1143) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpnle_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_NLE_US) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for not-less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnle_pd_mask&expand=1144) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpnle_pd_mask(k1: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(k1, a, b, _CMP_NLE_US) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_pd_mask&expand=822) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpeq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_EQ_OQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_pd_mask&expand=823) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpeq_pd_mask(k1: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(k1, a, b, _CMP_EQ_OQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_pd_mask&expand=1127) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpneq_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_NEQ_UQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_pd_mask&expand=1128) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpneq_pd_mask(k1: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(k1, a, b, _CMP_NEQ_UQ) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_pd_mask&expand=741) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_pd_mask(a: __m512d, b: __m512d, imm8: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmppd( + a.as_f64x8(), + b.as_f64x8(), + $imm5, + neg_one, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_pd_mask&expand=742) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_pd_mask(k1: __mmask8, a: __m512d, b: __m512d, imm8: i32) -> __mmask8 { + macro_rules! call { + ($imm5:expr) => { + vcmppd( + a.as_f64x8(), + b.as_f64x8(), + $imm5, + k1 as i8, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_round_pd_mask&expand=751) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm512_cmp_round_pd_mask(a: __m512d, b: __m512d, imm8: i32, sae: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_round_pd_mask&expand=752) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm512_mask_cmp_round_pd_mask( + k1: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, + sae: i32, +) -> __mmask8 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmppd(a.as_f64x8(), b.as_f64x8(), $imm5, k1 as i8, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpord_pd_mask&expand=1159) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_ORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if neither is NaN, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpord_pd_mask&expand=1160) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpord_pd_mask(k1: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(k1, a, b, _CMP_ORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_pd_mask&expand=1167) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_cmpunord_pd_mask(a: __m512d, b: __m512d) -> __mmask8 { + _mm512_cmp_pd_mask(a, b, _CMP_UNORD_Q) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b to see if either is NaN, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_pd_mask&expand=1168) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp))] +pub unsafe fn _mm512_mask_cmpunord_pd_mask(k1: __mmask8, a: __m512d, b: __m512d) -> __mmask8 { + _mm512_mask_cmp_pd_mask(k1, a, b, _CMP_UNORD_Q) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_ss_mask&expand=763) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm_cmp_ss_mask(a: __m128, b: __m128, imm8: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmpss(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k using zeromask k1 (the element is zeroed out when mask bit 0 is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_ss_mask&expand=764) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm_mask_cmp_ss_mask(k1: __mmask8, a: __m128, b: __m128, imm8: i32) -> __mmask8 { + macro_rules! call { + ($imm5:expr) => { + vcmpss(a, b, $imm5, k1 as i8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_ss_mask&expand=757) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm_cmp_round_ss_mask(a: __m128, b: __m128, imm8: i32, sae: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpss(a, b, $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k using zeromask k1 (the element is zeroed out when mask bit 0 is not seti).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_ss_mask&expand=758) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm_mask_cmp_round_ss_mask( + k1: __mmask8, + a: __m128, + b: __m128, + imm8: i32, + sae: i32, +) -> __mmask8 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpss(a, b, $imm5, k1 as i8, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare the lower double-precision (64-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_sd_mask&expand=760) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm_cmp_sd_mask(a: __m128d, b: __m128d, imm8: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr) => { + vcmpsd(a, b, $imm5, neg_one, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare the lower double-precision (64-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k using zeromask k1 (the element is zeroed out when mask bit 0 is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_sd_mask&expand=761) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0))] +pub unsafe fn _mm_mask_cmp_sd_mask(k1: __mmask8, a: __m128d, b: __m128d, imm8: i32) -> __mmask8 { + macro_rules! call { + ($imm5:expr) => { + vcmpsd(a, b, $imm5, k1 as i8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm5!(imm8, call); + transmute(r) +} + +/// Compare the lower double-precision (64-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_sd_mask&expand=755) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2, 3)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm_cmp_round_sd_mask(a: __m128d, b: __m128d, imm8: i32, sae: i32) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpsd(a, b, $imm5, neg_one, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare the lower double-precision (64-bit) floating-point element in a and b based on the comparison operand specified by imm8, and store the result in mask vector k using zeromask k1 (the element is zeroed out when mask bit 0 is not set).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_sd_mask&expand=756) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3, 4)] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 0, sae = 4))] +pub unsafe fn _mm_mask_cmp_round_sd_mask( + k1: __mmask8, + a: __m128d, + b: __m128d, + imm8: i32, + sae: i32, +) -> __mmask8 { + macro_rules! call { + ($imm5:expr, $imm4:expr) => { + vcmpsd(a, b, $imm5, k1 as i8, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epu32_mask&expand=1056) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_lt(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu32_mask&expand=1057) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epu32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmplt_epu32_mask(a, b) & k1 +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu32_mask&expand=933) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_gt(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu32_mask&expand=934) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epu32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpgt_epu32_mask(a, b) & k1 +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu32_mask&expand=995) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_le(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu32_mask&expand=996) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epu32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmple_epu32_mask(a, b) & k1 +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu32_mask&expand=873) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ge(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu32_mask&expand=874) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epu32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpge_epu32_mask(a, b) & k1 +} + +/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu32_mask&expand=807) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_eq(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu32_mask&expand=808) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epu32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpeq_epu32_mask(a, b) & k1 +} + +/// Compare packed unsigned 32-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu32_mask&expand=1112) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epu32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ne(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu32_mask&expand=1113) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epu32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpneq_epu32_mask(a, b) & k1 +} + +/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu32_mask&expand=721) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epu32_mask(a: __m512i, b: __m512i, imm8: _MM_CMPINT_ENUM) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed unsigned 32-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu32_mask&expand=722) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epu32_mask( + k1: __mmask16, + a: __m512i, + b: __m512i, + imm8: _MM_CMPINT_ENUM, +) -> __mmask16 { + macro_rules! call { + ($imm3:expr) => { + vpcmpud(a.as_i32x16(), b.as_i32x16(), $imm3, k1 as i16) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 32-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi32_mask&expand=1029) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_lt(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi32_mask&expand=1031) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epi32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmplt_epi32_mask(a, b) & k1 +} + +/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi32_mask&expand=905) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_gt(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi32_mask&expand=906) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epi32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpgt_epi32_mask(a, b) & k1 +} + +/// Compare packed signed 32-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi32_mask&expand=971) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_le(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi32_mask&expand=972) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epi32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmple_epi32_mask(a, b) & k1 +} + +/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi32_mask&expand=849) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ge(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi32_mask&expand=850) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epi32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpge_epi32_mask(a, b) & k1 +} + +/// Compare packed 32-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi32_mask&expand=779) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_eq(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed 32-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi32_mask&expand=780) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epi32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpeq_epi32_mask(a, b) & k1 +} + +/// Compare packed 32-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi32_mask&expand=1088) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epi32_mask(a: __m512i, b: __m512i) -> __mmask16 { + simd_bitmask::(simd_ne(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed 32-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi32_mask&expand=1089) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epi32_mask(k1: __mmask16, a: __m512i, b: __m512i) -> __mmask16 { + _mm512_cmpneq_epi32_mask(a, b) & k1 +} + +/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi32_mask&expand=697) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epi32_mask(a: __m512i, b: __m512i, imm8: _MM_CMPINT_ENUM) -> __mmask16 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, neg_one) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 32-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi32_mask&expand=698) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epi32_mask( + k1: __mmask16, + a: __m512i, + b: __m512i, + imm8: _MM_CMPINT_ENUM, +) -> __mmask16 { + macro_rules! call { + ($imm3:expr) => { + vpcmpd(a.as_i32x16(), b.as_i32x16(), $imm3, k1 as i16) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epu64_mask&expand=1062) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_lt(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu64_mask&expand=1063) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epu64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmplt_epu64_mask(a, b) & k1 +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu64_mask&expand=939) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_gt(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu64_mask&expand=940) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epu64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpgt_epu64_mask(a, b) & k1 +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu64_mask&expand=1001) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_le(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu64_mask&expand=1002) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epu64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmple_epu64_mask(a, b) & k1 +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu64_mask&expand=879) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ge(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu64_mask&expand=880) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epu64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpge_epu64_mask(b, a) & k1 +} + +/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu64_mask&expand=813) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_eq(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu64_mask&expand=814) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epu64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpeq_epu64_mask(a, b) & k1 +} + +/// Compare packed unsigned 64-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu64_mask&expand=1118) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ne(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu64_mask&expand=1119) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epu64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpneq_epu64_mask(a, b) & k1 +} + +/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu64_mask&expand=727) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epu64_mask(a: __m512i, b: __m512i, imm8: _MM_CMPINT_ENUM) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed unsigned 64-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu64_mask&expand=728) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epu64_mask( + k1: __mmask8, + a: __m512i, + b: __m512i, + imm8: _MM_CMPINT_ENUM, +) -> __mmask8 { + macro_rules! call { + ($imm3:expr) => { + vpcmpuq(a.as_i64x8(), b.as_i64x8(), $imm3, k1 as i8) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi64_mask&expand=1037) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmplt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_lt(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for less-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi64_mask&expand=1038) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmplt_epi64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmplt_epi64_mask(a, b) & k1 +} + +/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi64_mask&expand=913) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpgt_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_gt(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for greater-than, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi64_mask&expand=914) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpgt_epi64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpgt_epi64_mask(a, b) & k1 +} + +/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi64_mask&expand=977) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmple_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_le(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for less-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi64_mask&expand=978) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmple_epi64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmple_epi64_mask(a, b) & k1 +} + +/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi64_mask&expand=855) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpge_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ge(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for greater-than-or-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi64_mask&expand=856) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpge_epi64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpge_epi64_mask(b, a) & k1 +} + +/// Compare packed 64-bit integers in a and b for equality, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi64_mask&expand=787) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpeq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_eq(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed 64-bit integers in a and b for equality, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi64_mask&expand=788) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpeq_epi64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpeq_epi64_mask(a, b) & k1 +} + +/// Compare packed signed 64-bit integers in a and b for not-equal, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi64_mask&expand=1094) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_cmpneq_epi64_mask(a: __m512i, b: __m512i) -> __mmask8 { + simd_bitmask::<__m512i, _>(simd_ne(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b for not-equal, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi64_mask&expand=1095) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpcmp))] +pub unsafe fn _mm512_mask_cmpneq_epi64_mask(k1: __mmask8, a: __m512i, b: __m512i) -> __mmask8 { + _mm512_cmpneq_epi64_mask(a, b) & k1 +} + +/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi64_mask&expand=703) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(2)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_cmp_epi64_mask(a: __m512i, b: __m512i, imm8: _MM_CMPINT_ENUM) -> __mmask8 { + let neg_one = -1; + macro_rules! call { + ($imm3:expr) => { + vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, neg_one) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Compare packed signed 64-bit integers in a and b based on the comparison operand specified by imm8, and store the results in mask vector k using zeromask k1 (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi64_mask&expand=704) +#[inline] +#[target_feature(enable = "avx512f")] +#[rustc_args_required_const(3)] +#[cfg_attr(test, assert_instr(vpcmp, imm8 = 0))] +pub unsafe fn _mm512_mask_cmp_epi64_mask( + k1: __mmask8, + a: __m512i, + b: __m512i, + imm8: _MM_CMPINT_ENUM, +) -> __mmask8 { + macro_rules! call { + ($imm3:expr) => { + vpcmpq(a.as_i64x8(), b.as_i64x8(), $imm3, k1 as i8) + }; + } + let r = constify_imm3!(imm8, call); + transmute(r) +} + +/// Reduce the packed 32-bit integers in a by addition. Returns the sum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_add_epi32&expand=4556) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_add_epi32(a: __m512i) -> i32 { + simd_reduce_add_unordered(a.as_i32x16()) +} + +/// Reduce the packed 32-bit integers in a by addition using mask k. Returns the sum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_add_epi32&expand=4555) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_add_epi32(k: __mmask16, a: __m512i) -> i32 { + simd_reduce_add_unordered(simd_select_bitmask( + k, + a.as_i32x16(), + _mm512_setzero_si512().as_i32x16(), + )) +} + +/// Reduce the packed 64-bit integers in a by addition. Returns the sum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_add_epi64&expand=4558) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_add_epi64(a: __m512i) -> i64 { + simd_reduce_add_unordered(a.as_i64x8()) +} + +/// Reduce the packed 64-bit integers in a by addition using mask k. Returns the sum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_add_epi64&expand=4557) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_add_epi64(k: __mmask8, a: __m512i) -> i64 { + simd_reduce_add_unordered(simd_select_bitmask( + k, + a.as_i64x8(), + _mm512_setzero_si512().as_i64x8(), + )) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by addition. Returns the sum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_add_ps&expand=4562) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_add_ps(a: __m512) -> f32 { + simd_reduce_add_unordered(a.as_f32x16()) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by addition using mask k. Returns the sum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_add_ps&expand=4561) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_add_ps(k: __mmask16, a: __m512) -> f32 { + simd_reduce_add_unordered(simd_select_bitmask( + k, + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + )) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by addition. Returns the sum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_add_pd&expand=4560) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_add_pd(a: __m512d) -> f64 { + simd_reduce_add_unordered(a.as_f64x8()) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by addition using mask k. Returns the sum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_add_pd&expand=4559) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_add_pd(k: __mmask8, a: __m512d) -> f64 { + simd_reduce_add_unordered(simd_select_bitmask( + k, + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + )) +} + +/// Reduce the packed 32-bit integers in a by multiplication. Returns the product of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_mul_epi32&expand=4600) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_mul_epi32(a: __m512i) -> i32 { + simd_reduce_mul_unordered(a.as_i32x16()) +} + +/// Reduce the packed 32-bit integers in a by multiplication using mask k. Returns the product of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_mul_epi32&expand=4599) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_mul_epi32(k: __mmask16, a: __m512i) -> i32 { + simd_reduce_mul_unordered(simd_select_bitmask( + k, + a.as_i32x16(), + _mm512_set1_epi32(1).as_i32x16(), + )) +} + +/// Reduce the packed 64-bit integers in a by multiplication. Returns the product of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_mul_epi64&expand=4602) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_mul_epi64(a: __m512i) -> i64 { + simd_reduce_mul_unordered(a.as_i64x8()) +} + +/// Reduce the packed 64-bit integers in a by multiplication using mask k. Returns the product of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_mul_epi64&expand=4601) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_mul_epi64(k: __mmask8, a: __m512i) -> i64 { + simd_reduce_mul_unordered(simd_select_bitmask( + k, + a.as_i64x8(), + _mm512_set1_epi64(1).as_i64x8(), + )) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by multiplication. Returns the product of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_mul_ps&expand=4606) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_mul_ps(a: __m512) -> f32 { + simd_reduce_mul_unordered(a.as_f32x16()) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by multiplication using mask k. Returns the product of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_mul_ps&expand=4605) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_mul_ps(k: __mmask16, a: __m512) -> f32 { + simd_reduce_mul_unordered(simd_select_bitmask( + k, + a.as_f32x16(), + _mm512_set1_ps(1.).as_f32x16(), + )) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by multiplication. Returns the product of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_mul_pd&expand=4604) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_mul_pd(a: __m512d) -> f64 { + simd_reduce_mul_unordered(a.as_f64x8()) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by multiplication using mask k. Returns the product of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_mul_pd&expand=4603) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_mul_pd(k: __mmask8, a: __m512d) -> f64 { + simd_reduce_mul_unordered(simd_select_bitmask( + k, + a.as_f64x8(), + _mm512_set1_pd(1.).as_f64x8(), + )) +} + +/// Reduce the packed signed 32-bit integers in a by maximum. Returns the maximum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_max_epi32&expand=4576) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_max_epi32(a: __m512i) -> i32 { + simd_reduce_max(a.as_i32x16()) +} + +/// Reduce the packed signed 32-bit integers in a by maximum using mask k. Returns the maximum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_max_epi32&expand=4575) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_max_epi32(k: __mmask16, a: __m512i) -> i32 { + simd_reduce_max(simd_select_bitmask( + k, + a.as_i32x16(), + _mm512_undefined_epi32().as_i32x16(), + )) +} + +/// Reduce the packed signed 64-bit integers in a by maximum. Returns the maximum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_max_epi64&expand=4578) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_max_epi64(a: __m512i) -> i64 { + simd_reduce_max(a.as_i64x8()) +} + +/// Reduce the packed signed 64-bit integers in a by maximum using mask k. Returns the maximum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_max_epi64&expand=4577) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_max_epi64(k: __mmask8, a: __m512i) -> i64 { + simd_reduce_max(simd_select_bitmask( + k, + a.as_i64x8(), + _mm512_set1_epi64(0).as_i64x8(), + )) +} + +/// Reduce the packed unsigned 32-bit integers in a by maximum. Returns the maximum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_max_epu32&expand=4580) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_max_epu32(a: __m512i) -> u32 { + simd_reduce_max(a.as_u32x16()) +} + +/// Reduce the packed unsigned 32-bit integers in a by maximum using mask k. Returns the maximum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_max_epu32&expand=4579) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_max_epu32(k: __mmask16, a: __m512i) -> u32 { + simd_reduce_max(simd_select_bitmask( + k, + a.as_u32x16(), + _mm512_undefined_epi32().as_u32x16(), + )) +} + +/// Reduce the packed unsigned 64-bit integers in a by maximum. Returns the maximum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_max_epu64&expand=4582) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_max_epu64(a: __m512i) -> u64 { + simd_reduce_max(a.as_u64x8()) +} + +/// Reduce the packed unsigned 64-bit integers in a by maximum using mask k. Returns the maximum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_max_epu64&expand=4581) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_max_epu64(k: __mmask8, a: __m512i) -> u64 { + simd_reduce_max(simd_select_bitmask( + k, + a.as_u64x8(), + _mm512_set1_epi64(0).as_u64x8(), + )) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by maximum. Returns the maximum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_max_ps&expand=4586) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_max_ps(a: __m512) -> f32 { + simd_reduce_max(a.as_f32x16()) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by maximum using mask k. Returns the maximum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_max_ps&expand=4585) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_max_ps(k: __mmask16, a: __m512) -> f32 { + simd_reduce_max(simd_select_bitmask( + k, + a.as_f32x16(), + _mm512_undefined_ps().as_f32x16(), + )) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by maximum. Returns the maximum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_max_pd&expand=4584) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_max_pd(a: __m512d) -> f64 { + simd_reduce_max(a.as_f64x8()) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by maximum using mask k. Returns the maximum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_max_pd&expand=4583) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_max_pd(k: __mmask8, a: __m512d) -> f64 { + simd_reduce_max(simd_select_bitmask( + k, + a.as_f64x8(), + _mm512_undefined_pd().as_f64x8(), + )) +} + +/// Reduce the packed signed 32-bit integers in a by minimum. Returns the minimum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_min_epi32&expand=4588) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_min_epi32(a: __m512i) -> i32 { + simd_reduce_min(a.as_i32x16()) +} + +/// Reduce the packed signed 32-bit integers in a by maximum using mask k. Returns the minimum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_min_epi32&expand=4587) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_min_epi32(k: __mmask16, a: __m512i) -> i32 { + simd_reduce_min(simd_select_bitmask( + k, + a.as_i32x16(), + _mm512_undefined_epi32().as_i32x16(), + )) +} + +/// Reduce the packed signed 64-bit integers in a by minimum. Returns the minimum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_min_epi64&expand=4590) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_min_epi64(a: __m512i) -> i64 { + simd_reduce_min(a.as_i64x8()) +} + +/// Reduce the packed signed 64-bit integers in a by maximum using mask k. Returns the minimum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_min_epi64&expand=4589) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_min_epi64(k: __mmask8, a: __m512i) -> i64 { + simd_reduce_min(simd_select_bitmask( + k, + a.as_i64x8(), + _mm512_set1_epi64(0).as_i64x8(), + )) +} + +/// Reduce the packed unsigned 32-bit integers in a by minimum. Returns the minimum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_min_epu32&expand=4592) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_min_epu32(a: __m512i) -> u32 { + simd_reduce_min(a.as_u32x16()) +} + +/// Reduce the packed unsigned 32-bit integers in a by maximum using mask k. Returns the minimum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_min_epu32&expand=4591) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_min_epu32(k: __mmask16, a: __m512i) -> u32 { + simd_reduce_min(simd_select_bitmask( + k, + a.as_u32x16(), + _mm512_undefined_epi32().as_u32x16(), + )) +} + +/// Reduce the packed unsigned 64-bit integers in a by minimum. Returns the minimum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_min_epu64&expand=4594) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_min_epu64(a: __m512i) -> u64 { + simd_reduce_min(a.as_u64x8()) +} + +/// Reduce the packed signed 64-bit integers in a by maximum using mask k. Returns the minimum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_min_epi64&expand=4589) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_min_epu64(k: __mmask8, a: __m512i) -> u64 { + simd_reduce_min(simd_select_bitmask( + k, + a.as_u64x8(), + _mm512_set1_epi64(0).as_u64x8(), + )) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by minimum. Returns the minimum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_min_ps&expand=4598) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_min_ps(a: __m512) -> f32 { + simd_reduce_min(a.as_f32x16()) +} + +/// Reduce the packed single-precision (32-bit) floating-point elements in a by maximum using mask k. Returns the minimum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_min_ps&expand=4597) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_min_ps(k: __mmask16, a: __m512) -> f32 { + simd_reduce_min(simd_select_bitmask( + k, + a.as_f32x16(), + _mm512_undefined_ps().as_f32x16(), + )) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by minimum. Returns the minimum of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_min_pd&expand=4596) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_min_pd(a: __m512d) -> f64 { + simd_reduce_min(a.as_f64x8()) +} + +/// Reduce the packed double-precision (64-bit) floating-point elements in a by maximum using mask k. Returns the minimum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_min_pd&expand=4595) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_min_pd(k: __mmask8, a: __m512d) -> f64 { + simd_reduce_min(simd_select_bitmask( + k, + a.as_f64x8(), + _mm512_undefined_pd().as_f64x8(), + )) +} + +/// Reduce the packed 32-bit integers in a by bitwise AND. Returns the bitwise AND of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_and_epi32&expand=4564) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_and_epi32(a: __m512i) -> i32 { + simd_reduce_and(a.as_i32x16()) +} + +/// Reduce the packed 32-bit integers in a by bitwise AND using mask k. Returns the bitwise AND of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_and_epi32&expand=4563) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_and_epi32(k: __mmask16, a: __m512i) -> i32 { + simd_reduce_and(simd_select_bitmask( + k, + a.as_i32x16(), + _mm512_set1_epi32( + 1 << 0 + | 1 << 1 + | 1 << 2 + | 1 << 3 + | 1 << 4 + | 1 << 5 + | 1 << 6 + | 1 << 7 + | 1 << 8 + | 1 << 9 + | 1 << 10 + | 1 << 11 + | 1 << 12 + | 1 << 13 + | 1 << 14 + | 1 << 15, + ) + .as_i32x16(), + )) +} + +/// Reduce the packed 64-bit integers in a by bitwise AND. Returns the bitwise AND of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_and_epi64&expand=4566) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_and_epi64(a: __m512i) -> i64 { + simd_reduce_and(a.as_i64x8()) +} + +/// Reduce the packed 64-bit integers in a by addition using mask k. Returns the sum of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_add_epi64&expand=4557) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_and_epi64(k: __mmask8, a: __m512i) -> i64 { + simd_reduce_and(simd_select_bitmask( + k, + a.as_i64x8(), + _mm512_set1_epi64(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7) + .as_i64x8(), + )) +} + +/// Reduce the packed 32-bit integers in a by bitwise OR. Returns the bitwise OR of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_or_epi32&expand=4608) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_or_epi32(a: __m512i) -> i32 { + simd_reduce_or(a.as_i32x16()) +} + +/// Reduce the packed 32-bit integers in a by bitwise OR using mask k. Returns the bitwise OR of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_or_epi32&expand=4607) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_or_epi32(k: __mmask16, a: __m512i) -> i32 { + simd_reduce_or(simd_select_bitmask( + k, + a.as_i32x16(), + _mm512_setzero_si512().as_i32x16(), + )) +} + +/// Reduce the packed 64-bit integers in a by bitwise OR. Returns the bitwise OR of all elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_reduce_or_epi64&expand=4610) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_reduce_or_epi64(a: __m512i) -> i64 { + simd_reduce_or(a.as_i64x8()) +} + +/// Reduce the packed 64-bit integers in a by bitwise OR using mask k. Returns the bitwise OR of all active elements in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_reduce_or_epi64&expand=4609) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_reduce_or_epi64(k: __mmask8, a: __m512i) -> i64 { + simd_reduce_or(simd_select_bitmask( + k, + a.as_i64x8(), + _mm512_setzero_si512().as_i64x8(), + )) +} + +/// Returns vector of type `__m512d` with undefined elements. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_pd) +#[inline] +#[target_feature(enable = "avx512f")] +// This intrinsic has no corresponding instruction. +pub unsafe fn _mm512_undefined_pd() -> __m512d { + _mm512_set1_pd(0.0) +} + +/// Returns vector of type `__m512` with undefined elements. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_ps) +#[inline] +#[target_feature(enable = "avx512f")] +// This intrinsic has no corresponding instruction. +pub unsafe fn _mm512_undefined_ps() -> __m512 { + _mm512_set1_ps(0.0) +} + +/// Return vector of type __m512i with undefined elements. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_undefined_epi32&expand=5995) +#[inline] +#[target_feature(enable = "avx512f")] +// This intrinsic has no corresponding instruction. +pub unsafe fn _mm512_undefined_epi32() -> __m512i { + _mm512_set1_epi32(0) +} + +/// Return vector of type __m512 with undefined elements. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_undefined&expand=5994) +#[inline] +#[target_feature(enable = "avx512f")] +// This intrinsic has no corresponding instruction. +pub unsafe fn _mm512_undefined() -> __m512 { + _mm512_set1_ps(0.0) +} + +/// Load 512-bits (composed of 16 packed 32-bit integers) from memory into dst. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_loadu_epi32&expand=3377) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu32 +pub unsafe fn _mm512_loadu_epi32(mem_addr: *const i32) -> __m512i { + ptr::read_unaligned(mem_addr as *const __m512i) +} + +/// Store 512-bits (composed of 16 packed 32-bit integers) from a into memory. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_storeu_epi32&expand=5628) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu32 +pub unsafe fn _mm512_storeu_epi32(mem_addr: *mut i32, a: __m512i) { + ptr::write_unaligned(mem_addr as *mut __m512i, a); +} + +/// Load 512-bits (composed of 8 packed 64-bit integers) from memory into dst. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_loadu_epi64&expand=3386) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu64 +pub unsafe fn _mm512_loadu_epi64(mem_addr: *const i64) -> __m512i { + ptr::read_unaligned(mem_addr as *const __m512i) +} + +/// Store 512-bits (composed of 8 packed 64-bit integers) from a into memory. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_storeu_epi64&expand=5634) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu64 +pub unsafe fn _mm512_storeu_epi64(mem_addr: *mut i64, a: __m512i) { + ptr::write_unaligned(mem_addr as *mut __m512i, a); +} + +/// Load 512-bits of integer data from memory into dst. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_loadu_si512&expand=3420) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu32 +pub unsafe fn _mm512_loadu_si512(mem_addr: *const i32) -> __m512i { + ptr::read_unaligned(mem_addr as *const __m512i) +} + +/// Store 512-bits of integer data from a into memory. mem_addr does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_storeu_si512&expand=5657) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] //should be vmovdqu32 +pub unsafe fn _mm512_storeu_si512(mem_addr: *mut i32, a: __m512i) { + ptr::write_unaligned(mem_addr as *mut __m512i, a); +} + +/// Loads 512-bits (composed of 8 packed double-precision (64-bit) +/// floating-point elements) from memory into result. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +pub unsafe fn _mm512_loadu_pd(mem_addr: *const f64) -> __m512d { + ptr::read_unaligned(mem_addr as *const __m512d) +} + +/// Stores 512-bits (composed of 8 packed double-precision (64-bit) +/// floating-point elements) from `a` into memory. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_pd) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +pub unsafe fn _mm512_storeu_pd(mem_addr: *mut f64, a: __m512d) { + ptr::write_unaligned(mem_addr as *mut __m512d, a); +} + +/// Loads 512-bits (composed of 16 packed single-precision (32-bit) +/// floating-point elements) from memory into result. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +pub unsafe fn _mm512_loadu_ps(mem_addr: *const f32) -> __m512 { + ptr::read_unaligned(mem_addr as *const __m512) +} + +/// Stores 512-bits (composed of 16 packed single-precision (32-bit) +/// floating-point elements) from `a` into memory. +/// `mem_addr` does not need to be aligned on any particular boundary. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_ps) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovups))] +#[stable(feature = "simd_x86", since = "1.27.0")] +pub unsafe fn _mm512_storeu_ps(mem_addr: *mut f32, a: __m512) { + ptr::write_unaligned(mem_addr as *mut __m512, a); +} + +/// Load 512-bits of integer data from memory into dst. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_load_si512&expand=3345) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovdqa32 +pub unsafe fn _mm512_load_si512(mem_addr: *const i32) -> __m512i { + ptr::read(mem_addr as *const __m512i) +} + +/// Store 512-bits of integer data from a into memory. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_store_si512&expand=5598) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovdqa32 +pub unsafe fn _mm512_store_si512(mem_addr: *mut i32, a: __m512i) { + ptr::write(mem_addr as *mut __m512i, a); +} + +/// Load 512-bits (composed of 16 packed 32-bit integers) from memory into dst. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_load_epi32&expand=3304) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovdqa32 +pub unsafe fn _mm512_load_epi32(mem_addr: *const i32) -> __m512i { + ptr::read(mem_addr as *const __m512i) +} + +/// Store 512-bits (composed of 16 packed 32-bit integers) from a into memory. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_store_epi32&expand=5569) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovdqa32 +pub unsafe fn _mm512_store_epi32(mem_addr: *mut i32, a: __m512i) { + ptr::write(mem_addr as *mut __m512i, a); +} + +/// Load 512-bits (composed of 8 packed 64-bit integers) from memory into dst. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_load_epi64&expand=3313) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovdqa64 +pub unsafe fn _mm512_load_epi64(mem_addr: *const i64) -> __m512i { + ptr::read(mem_addr as *const __m512i) +} + +/// Store 512-bits (composed of 8 packed 64-bit integers) from a into memory. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_store_epi64&expand=5575) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovdqa64 +pub unsafe fn _mm512_store_epi64(mem_addr: *mut i64, a: __m512i) { + ptr::write(mem_addr as *mut __m512i, a); +} + +/// Load 512-bits (composed of 16 packed single-precision (32-bit) floating-point elements) from memory into dst. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_load_ps&expand=3336) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] +pub unsafe fn _mm512_load_ps(mem_addr: *const f32) -> __m512 { + ptr::read(mem_addr as *const __m512) +} + +/// Store 512-bits of integer data from a into memory. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_store_ps&expand=5592) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] +pub unsafe fn _mm512_store_ps(mem_addr: *mut f32, a: __m512) { + ptr::write(mem_addr as *mut __m512, a); +} + +/// Load 512-bits (composed of 8 packed double-precision (64-bit) floating-point elements) from memory into dst. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_load_pd&expand=3326) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovapd +pub unsafe fn _mm512_load_pd(mem_addr: *const f64) -> __m512d { + ptr::read(mem_addr as *const __m512d) +} + +/// Store 512-bits (composed of 8 packed double-precision (64-bit) floating-point elements) from a into memory. mem_addr must be aligned on a 64-byte boundary or a general-protection exception may be generated. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_store_pd&expand=5585) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovaps))] //should be vmovapd +pub unsafe fn _mm512_store_pd(mem_addr: *mut f64, a: __m512d) { + ptr::write(mem_addr as *mut __m512d, a); +} + +/// Set packed double-precision (64-bit) floating-point elements in dst with the supplied values in reverse order. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_pd&expand=5002) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_setr_pd( + e0: f64, + e1: f64, + e2: f64, + e3: f64, + e4: f64, + e5: f64, + e6: f64, + e7: f64, +) -> __m512d { + let r = f64x8::new(e0, e1, e2, e3, e4, e5, e6, e7); + transmute(r) +} + +/// Set packed double-precision (64-bit) floating-point elements in dst with the supplied values. +/// +/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_pd&expand=4924) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_set_pd( + e0: f64, + e1: f64, + e2: f64, + e3: f64, + e4: f64, + e5: f64, + e6: f64, + e7: f64, +) -> __m512d { + _mm512_setr_pd(e7, e6, e5, e4, e3, e2, e1, e0) +} + +/// Move the lower single-precision (32-bit) floating-point element from b to the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_move_ss&expand=3832) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovss))] +pub unsafe fn _mm_mask_move_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + let extractsrc: f32 = simd_extract(src, 0); + let mut mov: f32 = extractsrc; + if (k & 0b00000001) != 0 { + mov = simd_extract(b, 0); + } + let r = simd_insert(a, 0, mov); + transmute(r) +} + +/// Move the lower single-precision (32-bit) floating-point element from b to the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_move_ss&expand=3833) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovss))] +pub unsafe fn _mm_maskz_move_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + let mut mov: f32 = 0.; + if (k & 0b00000001) != 0 { + mov = simd_extract(b, 0); + } + let r = simd_insert(a, 0, mov); + transmute(r) +} + +/// Move the lower double-precision (64-bit) floating-point element from b to the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_move_sd&expand=3829) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsd))] +pub unsafe fn _mm_mask_move_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let extractsrc: f64 = simd_extract(src, 0); + let mut mov: f64 = extractsrc; + if (k & 0b00000001) != 0 { + mov = simd_extract(b, 0); + } + let r = simd_insert(a, 0, mov); + transmute(r) +} + +/// Move the lower double-precision (64-bit) floating-point element from b to the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_move_sd&expand=3830) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsd))] +pub unsafe fn _mm_maskz_move_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let mut mov: f64 = 0.; + if (k & 0b00000001) != 0 { + mov = simd_extract(b, 0); + } + let r = simd_insert(a, 0, mov); + transmute(r) +} + +/// Add the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_add_ss&expand=159) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddss))] +pub unsafe fn _mm_mask_add_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + let extractsrc: f32 = simd_extract(src, 0); + let mut add: f32 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta + extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Add the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_add_ss&expand=160) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddss))] +pub unsafe fn _mm_maskz_add_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + let mut add: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta + extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Add the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_add_sd&expand=155) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddsd))] +pub unsafe fn _mm_mask_add_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let extractsrc: f64 = simd_extract(src, 0); + let mut add: f64 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta + extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Add the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_add_sd&expand=156) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddsd))] +pub unsafe fn _mm_maskz_add_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let mut add: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta + extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Subtract the lower single-precision (32-bit) floating-point element in b from the lower single-precision (32-bit) floating-point element in a, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sub_ss&expand=5750) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubss))] +pub unsafe fn _mm_mask_sub_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + let extractsrc: f32 = simd_extract(src, 0); + let mut add: f32 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta - extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Subtract the lower single-precision (32-bit) floating-point element in b from the lower single-precision (32-bit) floating-point element in a, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sub_ss&expand=5751) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubss))] +pub unsafe fn _mm_maskz_sub_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + let mut add: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta - extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Subtract the lower double-precision (64-bit) floating-point element in b from the lower double-precision (64-bit) floating-point element in a, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sub_sd&expand=5746) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubsd))] +pub unsafe fn _mm_mask_sub_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let extractsrc: f64 = simd_extract(src, 0); + let mut add: f64 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta - extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Subtract the lower double-precision (64-bit) floating-point element in b from the lower double-precision (64-bit) floating-point element in a, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sub_sd&expand=5747) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubsd))] +pub unsafe fn _mm_maskz_sub_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let mut add: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta - extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_mul_ss&expand=3950) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulss))] +pub unsafe fn _mm_mask_mul_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + let extractsrc: f32 = simd_extract(src, 0); + let mut add: f32 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta * extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_mul_ss&expand=3951) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulss))] +pub unsafe fn _mm_maskz_mul_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + let mut add: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta * extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_mul_sd&expand=3947) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulsd))] +pub unsafe fn _mm_mask_mul_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let extractsrc: f64 = simd_extract(src, 0); + let mut add: f64 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta * extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_mul_sd&expand=3948) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulsd))] +pub unsafe fn _mm_maskz_mul_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let mut add: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta * extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Divide the lower single-precision (32-bit) floating-point element in a by the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_div_ss&expand=2181) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivss))] +pub unsafe fn _mm_mask_div_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + let extractsrc: f32 = simd_extract(src, 0); + let mut add: f32 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta / extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Divide the lower single-precision (32-bit) floating-point element in a by the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_div_ss&expand=2182) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivss))] +pub unsafe fn _mm_maskz_div_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + let mut add: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + add = extracta / extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Divide the lower double-precision (64-bit) floating-point element in a by the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_div_sd&expand=2178) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivsd))] +pub unsafe fn _mm_mask_div_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let extractsrc: f64 = simd_extract(src, 0); + let mut add: f64 = extractsrc; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta / extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Divide the lower double-precision (64-bit) floating-point element in a by the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_div_sd&expand=2179) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivsd))] +pub unsafe fn _mm_maskz_div_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + let mut add: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + add = extracta / extractb; + } + let r = simd_insert(a, 0, add); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_max_ss&expand=3672) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxss))] +pub unsafe fn _mm_mask_max_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vmaxss( + a.as_f32x4(), + b.as_f32x4(), + src.as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_max_ss&expand=3673) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxss))] +pub unsafe fn _mm_maskz_max_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vmaxss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_max_sd&expand=3669) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxsd))] +pub unsafe fn _mm_mask_max_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vmaxsd( + a.as_f64x2(), + b.as_f64x2(), + src.as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_max_sd&expand=3670) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxsd))] +pub unsafe fn _mm_maskz_max_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vmaxsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_min_ss&expand=3786) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminss))] +pub unsafe fn _mm_mask_min_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vminss( + a.as_f32x4(), + b.as_f32x4(), + src.as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_min_ss&expand=3787) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminss))] +pub unsafe fn _mm_maskz_min_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vminss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_min_sd&expand=3783) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminsd))] +pub unsafe fn _mm_mask_min_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vminsd( + a.as_f64x2(), + b.as_f64x2(), + src.as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_min_sd&expand=3784) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminsd))] +pub unsafe fn _mm_maskz_min_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vminsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compute the square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sqrt_ss&expand=5387) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtss))] +pub unsafe fn _mm_mask_sqrt_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vsqrtss( + a.as_f32x4(), + b.as_f32x4(), + src.as_f32x4(), + k, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + )) +} + +/// Compute the square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sqrt_ss&expand=5388) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtss))] +pub unsafe fn _mm_maskz_sqrt_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vsqrtss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + )) +} + +/// Compute the square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sqrt_sd&expand=5384) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtsd))] +pub unsafe fn _mm_mask_sqrt_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vsqrtsd( + a.as_f64x2(), + b.as_f64x2(), + src.as_f64x2(), + k, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + )) +} + +/// Compute the square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sqrt_sd&expand=5385) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtsd))] +pub unsafe fn _mm_maskz_sqrt_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vsqrtsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + )) +} + +/// Compute the approximate reciprocal square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_rsqrt14_ss&expand=4825) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14ss))] +pub unsafe fn _mm_rsqrt14_ss(a: __m128, b: __m128) -> __m128 { + transmute(vrsqrt14ss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + )) +} + +/// Compute the approximate reciprocal square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_rsqrt14_ss&expand=4823) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14ss))] +pub unsafe fn _mm_mask_rsqrt14_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vrsqrt14ss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k)) +} + +/// Compute the approximate reciprocal square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_rsqrt14_ss&expand=4824) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14ss))] +pub unsafe fn _mm_maskz_rsqrt14_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vrsqrt14ss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + )) +} + +/// Compute the approximate reciprocal square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_rsqrt14_sd&expand=4822) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14sd))] +pub unsafe fn _mm_rsqrt14_sd(a: __m128d, b: __m128d) -> __m128d { + transmute(vrsqrt14sd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + )) +} + +/// Compute the approximate reciprocal square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_rsqrt14_sd&expand=4820) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14sd))] +pub unsafe fn _mm_mask_rsqrt14_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vrsqrt14sd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k)) +} + +/// Compute the approximate reciprocal square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_rsqrt14_sd&expand=4821) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14sd))] +pub unsafe fn _mm_maskz_rsqrt14_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vrsqrt14sd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + )) +} + +/// Compute the approximate reciprocal of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_rcp14_ss&expand=4508) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14ss))] +pub unsafe fn _mm_rcp14_ss(a: __m128, b: __m128) -> __m128 { + transmute(vrcp14ss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + )) +} + +/// Compute the approximate reciprocal of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_rcp14_ss&expand=4506) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14ss))] +pub unsafe fn _mm_mask_rcp14_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vrcp14ss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k)) +} + +/// Compute the approximate reciprocal of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_rcp14_ss&expand=4507) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14ss))] +pub unsafe fn _mm_maskz_rcp14_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vrcp14ss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + )) +} + +/// Compute the approximate reciprocal of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_rcp14_sd&expand=4505) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14sd))] +pub unsafe fn _mm_rcp14_sd(a: __m128d, b: __m128d) -> __m128d { + transmute(vrcp14sd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + )) +} + +/// Compute the approximate reciprocal of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_rcp14_sd&expand=4503) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14sd))] +pub unsafe fn _mm_mask_rcp14_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vrcp14sd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k)) +} + +/// Compute the approximate reciprocal of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_rcp14_sd&expand=4504) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14sd))] +pub unsafe fn _mm_maskz_rcp14_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vrcp14sd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + )) +} + +/// Convert the exponent of the lower single-precision (32-bit) floating-point element in b to a single-precision (32-bit) floating-point number representing the integer exponent, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getexp_ss&expand=2862) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpss))] +pub unsafe fn _mm_getexp_ss(a: __m128, b: __m128) -> __m128 { + transmute(vgetexpss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + _MM_FROUND_NO_EXC, + )) +} + +/// Convert the exponent of the lower single-precision (32-bit) floating-point element in b to a single-precision (32-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getexp_ss&expand=2863) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpss))] +pub unsafe fn _mm_mask_getexp_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vgetexpss( + a.as_f32x4(), + b.as_f32x4(), + src.as_f32x4(), + k, + _MM_FROUND_NO_EXC, + )) +} + +/// Convert the exponent of the lower single-precision (32-bit) floating-point element in b to a single-precision (32-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getexp_ss&expand=2864) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpss))] +pub unsafe fn _mm_maskz_getexp_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vgetexpss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + _MM_FROUND_NO_EXC, + )) +} + +/// Convert the exponent of the lower double-precision (64-bit) floating-point element in b to a double-precision (64-bit) floating-point number representing the integer exponent, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getexp_sd&expand=2859) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpsd))] +pub unsafe fn _mm_getexp_sd(a: __m128d, b: __m128d) -> __m128d { + transmute(vgetexpsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + _MM_FROUND_NO_EXC, + )) +} + +/// Convert the exponent of the lower double-precision (64-bit) floating-point element in b to a double-precision (64-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getexp_sd&expand=2860) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpsd))] +pub unsafe fn _mm_mask_getexp_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vgetexpsd( + a.as_f64x2(), + b.as_f64x2(), + src.as_f64x2(), + k, + _MM_FROUND_NO_EXC, + )) +} + +/// Convert the exponent of the lower double-precision (64-bit) floating-point element in b to a double-precision (64-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getexp_sd&expand=2861) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpsd))] +pub unsafe fn _mm_maskz_getexp_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vgetexpsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + _MM_FROUND_NO_EXC, + )) +} + +/// Normalize the mantissas of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getmant_ss&expand=2898) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantss, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm_getmant_ss( + a: __m128, + b: __m128, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m128 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr) => { + vgetmantss( + a.as_f32x4(), + b.as_f32x4(), + $imm2 << 2 | $imm4_1, + _mm_setzero_ps().as_f32x4(), + 0b1, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getmant_ss&expand=2899) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantss, norm = 0, sign = 0))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_mask_getmant_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m128 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr) => { + vgetmantss( + a.as_f32x4(), + b.as_f32x4(), + $imm2 << 2 | $imm4_1, + src.as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getmant_ss&expand=2900) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantss, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm_maskz_getmant_ss( + k: __mmask8, + a: __m128, + b: __m128, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m128 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr) => { + vgetmantss( + a.as_f32x4(), + b.as_f32x4(), + $imm2 << 2 | $imm4_1, + _mm_setzero_ps().as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getmant_sd&expand=2895) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantsd, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm_getmant_sd( + a: __m128d, + b: __m128d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m128d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr) => { + vgetmantsd( + a.as_f64x2(), + b.as_f64x2(), + $imm2 << 2 | $imm4_1, + _mm_setzero_pd().as_f64x2(), + 0b1, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getmant_sd&expand=2896) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantsd, norm = 0, sign = 0))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_mask_getmant_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m128d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr) => { + vgetmantsd( + a.as_f64x2(), + b.as_f64x2(), + $imm2 << 2 | $imm4_1, + src.as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getmant_sd&expand=2897) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantsd, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm_maskz_getmant_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m128d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr) => { + vgetmantsd( + a.as_f64x2(), + b.as_f64x2(), + $imm2 << 2 | $imm4_1, + _mm_setzero_pd().as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Round the lower single-precision (32-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_roundscale_ss&expand=4802) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscaless, imm8 = 255))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_roundscale_ss(a: __m128, b: __m128, imm8: i32) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let zero = _mm_setzero_ps().as_f32x4(); + macro_rules! call { + ($imm8:expr) => { + vrndscaless(a, b, zero, 0b11111111, $imm8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Round the lower single-precision (32-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_roundscale_ss&expand=4800) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscaless, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_roundscale_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + imm8: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let src = src.as_f32x4(); + macro_rules! call { + ($imm8:expr) => { + vrndscaless(a, b, src, k, $imm8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Round the lower single-precision (32-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_roundscale_ss&expand=4801) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscaless, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_roundscale_ss(k: __mmask8, a: __m128, b: __m128, imm8: i32) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let zero = _mm_setzero_ps().as_f32x4(); + macro_rules! call { + ($imm8:expr) => { + vrndscaless(a, b, zero, k, $imm8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Round the lower double-precision (64-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_roundscale_sd&expand=4799) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscalesd, imm8 = 255))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_roundscale_sd(a: __m128d, b: __m128d, imm8: i32) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let zero = _mm_setzero_pd().as_f64x2(); + macro_rules! call { + ($imm8:expr) => { + vrndscalesd(a, b, zero, 0b11111111, $imm8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Round the lower double-precision (64-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_roundscale_sd&expand=4797) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscalesd, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_roundscale_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + imm8: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let src = src.as_f64x2(); + macro_rules! call { + ($imm8:expr) => { + vrndscalesd(a, b, src, k, $imm8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Round the lower double-precision (64-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_roundscale_sd&expand=4798) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscalesd, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_roundscale_sd(k: __mmask8, a: __m128d, b: __m128d, imm8: i32) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let zero = _mm_setzero_pd().as_f64x2(); + macro_rules! call { + ($imm8:expr) => { + vrndscalesd(a, b, zero, k, $imm8, _MM_FROUND_CUR_DIRECTION) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_scalef_ss&expand=4901) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefss))] +pub unsafe fn _mm_scalef_ss(a: __m128, b: __m128) -> __m128 { + transmute(vscalefss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_scalef_ss&expand=4899) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefss))] +pub unsafe fn _mm_mask_scalef_ss(src: __m128, k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vscalefss( + a.as_f32x4(), + b.as_f32x4(), + src.as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_scalef_ss&expand=4900) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefss))] +pub unsafe fn _mm_maskz_scalef_ss(k: __mmask8, a: __m128, b: __m128) -> __m128 { + transmute(vscalefss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_scalef_sd&expand=4898) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefsd))] +pub unsafe fn _mm_scalef_sd(a: __m128d, b: __m128d) -> __m128d { + transmute(vscalefsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_scalef_sd&expand=4896) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefsd))] +pub unsafe fn _mm_mask_scalef_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vscalefsd( + a.as_f64x2(), + b.as_f64x2(), + src.as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_scalef_sd&expand=4897) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefsd))] +pub unsafe fn _mm_maskz_scalef_sd(k: __mmask8, a: __m128d, b: __m128d) -> __m128d { + transmute(vscalefsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmadd_ss&expand=2582) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213ss))] +pub unsafe fn _mm_mask_fmadd_ss(a: __m128, k: __mmask8, b: __m128, c: __m128) -> __m128 { + let mut fmadd: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + fmadd = vfmadd132ss(fmadd, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmadd_ss&expand=2584) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213ss))] +pub unsafe fn _mm_maskz_fmadd_ss(k: __mmask8, a: __m128, b: __m128, c: __m128) -> __m128 { + let mut fmadd: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + fmadd = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmadd_ss&expand=2583) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213ss))] +pub unsafe fn _mm_mask3_fmadd_ss(a: __m128, b: __m128, c: __m128, k: __mmask8) -> __m128 { + let mut fmadd: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + fmadd = vfmadd132ss(extracta, extractb, fmadd, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmadd_sd&expand=2578) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213sd))] +pub unsafe fn _mm_mask_fmadd_sd(a: __m128d, k: __mmask8, b: __m128d, c: __m128d) -> __m128d { + let mut fmadd: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + fmadd = vfmadd132sd(fmadd, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmadd_sd&expand=2580) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213sd))] +pub unsafe fn _mm_maskz_fmadd_sd(k: __mmask8, a: __m128d, b: __m128d, c: __m128d) -> __m128d { + let mut fmadd: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + fmadd = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmadd_sd&expand=2579) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213sd))] +pub unsafe fn _mm_mask3_fmadd_sd(a: __m128d, b: __m128d, c: __m128d, k: __mmask8) -> __m128d { + let mut fmadd: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + fmadd = vfmadd132sd(extracta, extractb, fmadd, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmsub_ss&expand=2668) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213ss))] +pub unsafe fn _mm_mask_fmsub_ss(a: __m128, k: __mmask8, b: __m128, c: __m128) -> __m128 { + let mut fmsub: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + fmsub = vfmadd132ss(fmsub, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmsub_ss&expand=2670) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213ss))] +pub unsafe fn _mm_maskz_fmsub_ss(k: __mmask8, a: __m128, b: __m128, c: __m128) -> __m128 { + let mut fmsub: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + fmsub = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmsub_ss&expand=2669) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213ss))] +pub unsafe fn _mm_mask3_fmsub_ss(a: __m128, b: __m128, c: __m128, k: __mmask8) -> __m128 { + let mut fmsub: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc = -fmsub; + fmsub = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmsub_sd&expand=2664) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213sd))] +pub unsafe fn _mm_mask_fmsub_sd(a: __m128d, k: __mmask8, b: __m128d, c: __m128d) -> __m128d { + let mut fmsub: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + fmsub = vfmadd132sd(fmsub, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmsub_sd&expand=2666) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213sd))] +pub unsafe fn _mm_maskz_fmsub_sd(k: __mmask8, a: __m128d, b: __m128d, c: __m128d) -> __m128d { + let mut fmsub: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + fmsub = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmsub_sd&expand=2665) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213sd))] +pub unsafe fn _mm_mask3_fmsub_sd(a: __m128d, b: __m128d, c: __m128d, k: __mmask8) -> __m128d { + let mut fmsub: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc = -fmsub; + fmsub = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmadd_ss&expand=2748) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213ss))] +pub unsafe fn _mm_mask_fnmadd_ss(a: __m128, k: __mmask8, b: __m128, c: __m128) -> __m128 { + let mut fnmadd: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmadd; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + fnmadd = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmadd_ss&expand=2750) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213ss))] +pub unsafe fn _mm_maskz_fnmadd_ss(k: __mmask8, a: __m128, b: __m128, c: __m128) -> __m128 { + let mut fnmadd: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + fnmadd = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmadd_ss&expand=2749) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213ss))] +pub unsafe fn _mm_mask3_fnmadd_ss(a: __m128, b: __m128, c: __m128, k: __mmask8) -> __m128 { + let mut fnmadd: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + fnmadd = vfmadd132ss(extracta, extractb, fnmadd, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmadd_sd&expand=2744) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213sd))] +pub unsafe fn _mm_mask_fnmadd_sd(a: __m128d, k: __mmask8, b: __m128d, c: __m128d) -> __m128d { + let mut fnmadd: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmadd; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + fnmadd = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmadd_sd&expand=2746) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213sd))] +pub unsafe fn _mm_maskz_fnmadd_sd(k: __mmask8, a: __m128d, b: __m128d, c: __m128d) -> __m128d { + let mut fnmadd: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + fnmadd = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmadd_sd&expand=2745) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213sd))] +pub unsafe fn _mm_mask3_fnmadd_sd(a: __m128d, b: __m128d, c: __m128d, k: __mmask8) -> __m128d { + let mut fnmadd: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + fnmadd = vfmadd132sd(extracta, extractb, fnmadd, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmsub_ss&expand=2796) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213ss))] +pub unsafe fn _mm_mask_fnmsub_ss(a: __m128, k: __mmask8, b: __m128, c: __m128) -> __m128 { + let mut fnmsub: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmsub; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + fnmsub = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmsub_ss&expand=2798) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213ss))] +pub unsafe fn _mm_maskz_fnmsub_ss(k: __mmask8, a: __m128, b: __m128, c: __m128) -> __m128 { + let mut fnmsub: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + fnmsub = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmsub_ss&expand=2797) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213ss))] +pub unsafe fn _mm_mask3_fnmsub_ss(a: __m128, b: __m128, c: __m128, k: __mmask8) -> __m128 { + let mut fnmsub: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc = -fnmsub; + fnmsub = vfmadd132ss(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmsub_sd&expand=2792) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213sd))] +pub unsafe fn _mm_mask_fnmsub_sd(a: __m128d, k: __mmask8, b: __m128d, c: __m128d) -> __m128d { + let mut fnmsub: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmsub; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + fnmsub = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmsub_sd&expand=2794) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213sd))] +pub unsafe fn _mm_maskz_fnmsub_sd(k: __mmask8, a: __m128d, b: __m128d, c: __m128d) -> __m128d { + let mut fnmsub: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + fnmsub = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmsub_sd&expand=2793) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213sd))] +pub unsafe fn _mm_mask3_fnmsub_sd(a: __m128d, b: __m128d, c: __m128d, k: __mmask8) -> __m128d { + let mut fnmsub: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc = -fnmsub; + fnmsub = vfmadd132sd(extracta, extractb, extractc, _MM_FROUND_CUR_DIRECTION); + } + let r = simd_insert(c, 0, fnmsub); + transmute(r) +} + +/// Add the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_ss&expand=151) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_add_round_ss(a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vaddss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Add the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_add_round_ss&expand=152) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_add_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vaddss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Add the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_ss&expand=153) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_add_round_ss(k: __mmask8, a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vaddss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Add the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_sd&expand=148) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddsd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_add_round_sd(a: __m128d, b: __m128d, rounding: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vaddsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Add the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_add_round_Sd&expand=149) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddsd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_add_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vaddsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Add the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_sd&expand=150) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddsd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_add_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vaddsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Subtract the lower single-precision (32-bit) floating-point element in b from the lower single-precision (32-bit) floating-point element in a, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sub_round_ss&expand=5745) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_sub_round_ss(a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vsubss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Subtract the lower single-precision (32-bit) floating-point element in b from the lower single-precision (32-bit) floating-point element in a, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sub_round_ss&expand=5743) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_sub_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vsubss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Subtract the lower single-precision (32-bit) floating-point element in b from the lower single-precision (32-bit) floating-point element in a, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sub_round_ss&expand=5744) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_sub_round_ss(k: __mmask8, a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vsubss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Subtract the lower double-precision (64-bit) floating-point element in b from the lower double-precision (64-bit) floating-point element in a, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sub_round_sd&expand=5742) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubsd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_sub_round_sd(a: __m128d, b: __m128d, rounding: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vsubsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Subtract the lower double-precision (64-bit) floating-point element in b from the lower double-precision (64-bit) floating-point element in a, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sub_round_sd&expand=5740) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubsd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_sub_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vsubsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Subtract the lower double-precision (64-bit) floating-point element in b from the lower double-precision (64-bit) floating-point element in a, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sub_round_sd&expand=5741) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubsd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_sub_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vsubsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Multiply the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_round_ss&expand=3946) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_mul_round_ss(a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vmulss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Multiply the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_mul_round_ss&expand=3944) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_mul_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vmulss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Multiply the lower single-precision (32-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_mul_round_ss&expand=3945) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_mul_round_ss(k: __mmask8, a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vmulss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Multiply the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_round_sd&expand=3943) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulsd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_mul_round_sd(a: __m128d, b: __m128d, rounding: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vmulsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Multiply the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_mul_round_sd&expand=3941) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulsd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_mul_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vmulsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Multiply the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_mul_round_sd&expand=3942) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulsd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_mul_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vmulsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Divide the lower single-precision (32-bit) floating-point element in a by the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_div_round_ss&expand=2174) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_div_round_ss(a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vdivss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Divide the lower single-precision (32-bit) floating-point element in a by the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_div_round_ss&expand=2175) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_div_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vdivss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Divide the lower single-precision (32-bit) floating-point element in a by the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_div_round_ss&expand=2176) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_div_round_ss(k: __mmask8, a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vdivss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Divide the lower double-precision (64-bit) floating-point element in a by the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_div_round_sd&expand=2171) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivsd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_div_round_sd(a: __m128d, b: __m128d, rounding: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vdivsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Divide the lower double-precision (64-bit) floating-point element in a by the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_div_round_sd&expand=2172) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivsd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_div_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vdivsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Divide the lower double-precision (64-bit) floating-point element in a by the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_div_round_sd&expand=2173) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivsd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_div_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vdivsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the maximum value in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_max_round_ss&expand=3668) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxss, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_max_round_ss(a: __m128, b: __m128, sae: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vmaxss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_max_ss&expand=3672) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxss, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_max_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + sae: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vmaxss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_max_round_ss&expand=3667) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxss, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_max_round_ss(k: __mmask8, a: __m128, b: __m128, sae: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vmaxss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the maximum value in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_max_round_sd&expand=3665) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxsd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_max_round_sd(a: __m128d, b: __m128d, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vmaxsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_max_round_sd&expand=3663) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxsd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_max_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + sae: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vmaxsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the maximum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_max_sd&expand=3670) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxsd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_max_round_sd(k: __mmask8, a: __m128d, b: __m128d, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vmaxsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the minimum value in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_min_round_ss&expand=3782) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminss, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_min_round_ss(a: __m128, b: __m128, sae: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vminss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_min_round_Ss&expand=3780) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminss, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_min_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + sae: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vminss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower single-precision (32-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_min_round_ss&expand=3781) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminss, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_min_round_ss(k: __mmask8, a: __m128, b: __m128, sae: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vminss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the minimum value in the lower element of dst , and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_min_round_sd&expand=3779) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminsd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_min_round_sd(a: __m128d, b: __m128d, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vminsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_min_round_sd&expand=3777) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminsd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_min_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + sae: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vminsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compare the lower double-precision (64-bit) floating-point elements in a and b, store the minimum value in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_min_round_Sd&expand=3778) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminsd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_min_round_sd(k: __mmask8, a: __m128d, b: __m128d, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vminsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_sae!(sae, call)) +} + +/// Compute the square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sqrt_round_ss&expand=5383) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_sqrt_round_ss(a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vsqrtss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Compute the square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sqrt_round_ss&expand=5381) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_sqrt_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vsqrtss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Compute the square root of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sqrt_round_ss&expand=5382) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_sqrt_round_ss(k: __mmask8, a: __m128, b: __m128, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vsqrtss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Compute the square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sqrt_round_sd&expand=5380) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtsd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_sqrt_round_sd(a: __m128d, b: __m128d, rounding: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vsqrtsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Compute the square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_sqrt_round_sd&expand=5378) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtsd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_sqrt_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vsqrtsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Compute the square root of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_sqrt_round_sd&expand=5379) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtsd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_sqrt_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vsqrtsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + transmute(constify_imm4_round!(rounding, call)) +} + +/// Convert the exponent of the lower single-precision (32-bit) floating-point element in b to a single-precision (32-bit) floating-point number representing the integer exponent, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getexp_round_ss&expand=2856) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpss, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_getexp_round_ss(a: __m128, b: __m128, sae: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vgetexpss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of the lower single-precision (32-bit) floating-point element in b to a single-precision (32-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getexp_round_ss&expand=2857) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpss, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_getexp_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + sae: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vgetexpss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of the lower single-precision (32-bit) floating-point element in b to a single-precision (32-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getexp_round_ss&expand=2858) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpss, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_getexp_round_ss(k: __mmask8, a: __m128, b: __m128, sae: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vgetexpss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of the lower double-precision (64-bit) floating-point element in b to a double-precision (64-bit) floating-point number representing the integer exponent, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getexp_round_sd&expand=2853) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpsd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_getexp_round_sd(a: __m128d, b: __m128d, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vgetexpsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of the lower double-precision (64-bit) floating-point element in b to a double-precision (64-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getexp_round_sd&expand=2854) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpsd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_getexp_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + sae: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vgetexpsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of the lower double-precision (64-bit) floating-point element in b to a double-precision (64-bit) floating-point number representing the integer exponent, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates floor(log2(x)) for the lower element.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getexp_round_sd&expand=2855) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpsd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_getexp_round_sd(k: __mmask8, a: __m128d, b: __m128d, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vgetexpsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Normalize the mantissas of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getmant_round_ss&expand=2892) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantss, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm_getmant_round_ss( + a: __m128, + b: __m128, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m128 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantss( + a.as_f32x4(), + b.as_f32x4(), + $imm2 << 2 | $imm4_1, + _mm_setzero_ps().as_f32x4(), + 0b1, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getmant_round_ss&expand=2893) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantss, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(4, 5, 6)] +pub unsafe fn _mm_mask_getmant_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m128 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantss( + a.as_f32x4(), + b.as_f32x4(), + $imm2 << 2 | $imm4_1, + src.as_f32x4(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of the lower single-precision (32-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getmant_round_ss&expand=2894) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantss, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm_maskz_getmant_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m128 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantss( + a.as_f32x4(), + b.as_f32x4(), + $imm2 << 2 | $imm4_1, + _mm_setzero_ps().as_f32x4(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_getmant_round_sd&expand=2889) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantsd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm_getmant_round_sd( + a: __m128d, + b: __m128d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m128d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantsd( + a.as_f64x2(), + b.as_f64x2(), + $imm2 << 2 | $imm4_1, + _mm_setzero_pd().as_f64x2(), + 0b1, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_getmant_round_sd&expand=2890) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantsd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(4, 5, 6)] +pub unsafe fn _mm_mask_getmant_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m128d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantsd( + a.as_f64x2(), + b.as_f64x2(), + $imm2 << 2 | $imm4_1, + src.as_f64x2(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of the lower double-precision (64-bit) floating-point element in b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign.\ +/// The mantissa is normalized to the interval specified by interv, which can take the following values:\ +/// _MM_MANT_NORM_1_2 // interval [1, 2)\ +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2)\ +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1)\ +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5)\ +/// The sign is determined by sc which can take the following values:\ +/// _MM_MANT_SIGN_src // sign = sign(src)\ +/// _MM_MANT_SIGN_zero // sign = 0\ +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_getmant_round_sd&expand=2891) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantsd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm_maskz_getmant_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m128d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantsd( + a.as_f64x2(), + b.as_f64x2(), + $imm2 << 2 | $imm4_1, + _mm_setzero_pd().as_f64x2(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Round the lower single-precision (32-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_roundscale_round_ss&expand=4796) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscaless, imm8 = 0, sae = 8))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm_roundscale_round_ss(a: __m128, b: __m128, imm8: i32, sae: i32) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let zero = _mm_setzero_ps().as_f32x4(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscaless(a, b, zero, 0b11111111, $imm8, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) +} + +/// Round the lower single-precision (32-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_roundscale_round_ss&expand=4794) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscaless, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_mask_roundscale_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + imm8: i32, + sae: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let src = src.as_f32x4(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscaless(a, b, src, k, $imm8, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) +} + +/// Round the lower single-precision (32-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_roundscale_round_ss&expand=4795) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscaless, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm_maskz_roundscale_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + imm8: i32, + sae: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let zero = _mm_setzero_ps().as_f32x4(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscaless(a, b, zero, k, $imm8, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) +} + +/// Round the lower double-precision (64-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_roundscale_round_sd&expand=4793) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscalesd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm_roundscale_round_sd(a: __m128d, b: __m128d, imm8: i32, sae: i32) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let zero = _mm_setzero_pd().as_f64x2(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscalesd(a, b, zero, 0b11111111, $imm8, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) +} + +/// Round the lower double-precision (64-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_roundscale_round_sd&expand=4791) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscalesd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_mask_roundscale_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + imm8: i32, + sae: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let src = src.as_f64x2(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscalesd(a, b, src, k, $imm8, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) +} + +/// Round the lower double-precision (64-bit) floating-point element in b to the number of fraction bits specified by imm8, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Rounding is done according to the imm8\[2:0\] parameter, which can be one of:\ +/// _MM_FROUND_TO_NEAREST_INT // round to nearest\ +/// _MM_FROUND_TO_NEG_INF // round down\ +/// _MM_FROUND_TO_POS_INF // round up\ +/// _MM_FROUND_TO_ZERO // truncate\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_roundscale_round_sd&expand=4792) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrndscalesd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm_maskz_roundscale_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + imm8: i32, + sae: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let zero = _mm_setzero_pd().as_f64x2(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vrndscalesd(a, b, zero, k, $imm8, $imm4) + }; + } + let r = constify_imm8_roundscale!(imm8, sae, call); + transmute(r) +} + +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_scalef_round_ss&expand=4895) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_scalef_round_ss(a: __m128, b: __m128, rounding: i32) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let zero = _mm_setzero_ps().as_f32x4(); + macro_rules! call { + ($imm4:expr) => { + vscalefss(a, b, zero, 0b11111111, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_scalef_round_ss&expand=4893) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_scalef_round_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vscalefss(a.as_f32x4(), b.as_f32x4(), src.as_f32x4(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Scale the packed single-precision (32-bit) floating-point elements in a using values from b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_scalef_round_ss&expand=4894) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_scalef_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vscalefss( + a.as_f32x4(), + b.as_f32x4(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_scalef_round_sd&expand=4892) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefsd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_scalef_round_sd(a: __m128d, b: __m128d, rounding: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vscalefsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_scalef_round_sd&expand=4890) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefsd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_scalef_round_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vscalefsd(a.as_f64x2(), b.as_f64x2(), src.as_f64x2(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Scale the packed double-precision (64-bit) floating-point elements in a using values from b, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_scalef_round_sd&expand=4891) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vscalefsd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_scalef_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + rounding: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vscalefsd( + a.as_f64x2(), + b.as_f64x2(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fmadd_round_ss&expand=2573) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213ss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fmadd_round_ss(a: __m128, b: __m128, c: __m128, rounding: i32) -> __m128 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmadd_round_ss&expand=2574) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fmadd_round_ss( + a: __m128, + k: __mmask8, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fmadd: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(fmadd, extractb, extractc, $imm4) + }; + } + fmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmadd_round_ss&expand=2576) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fmadd_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fmadd: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmadd_round_ss&expand=2575) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fmadd_round_ss( + a: __m128, + b: __m128, + c: __m128, + k: __mmask8, + rounding: i32, +) -> __m128 { + let mut fmadd: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, fmadd, $imm4) + }; + } + fmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fmadd_round_sd&expand=2569) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213sd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fmadd_round_sd(a: __m128d, b: __m128d, c: __m128d, rounding: i32) -> __m128d { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmadd_round_sd&expand=2570) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fmadd_round_sd( + a: __m128d, + k: __mmask8, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fmadd: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(fmadd, extractb, extractc, $imm4) + }; + } + fmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmadd_round_sd&expand=2572) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fmadd_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fmadd: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmadd_round_Sd&expand=2571) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fmadd_round_sd( + a: __m128d, + b: __m128d, + c: __m128d, + k: __mmask8, + rounding: i32, +) -> __m128d { + let mut fmadd: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, fmadd, $imm4) + }; + } + fmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fmsub_round_ss&expand=2659) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213ss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fmsub_round_ss(a: __m128, b: __m128, c: __m128, rounding: i32) -> __m128 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmsub_round_ss&expand=2660) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fmsub_round_ss( + a: __m128, + k: __mmask8, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fmsub: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(fmsub, extractb, extractc, $imm4) + }; + } + fmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmsub_round_ss&expand=2662) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fmsub_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fmsub: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmsub_round_ss&expand=2661) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fmsub_round_ss( + a: __m128, + b: __m128, + c: __m128, + k: __mmask8, + rounding: i32, +) -> __m128 { + let mut fmsub: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extractb: f32 = simd_extract(b, 0); + let extractc = -fmsub; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fmsub_round_sd&expand=2655) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213sd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fmsub_round_sd(a: __m128d, b: __m128d, c: __m128d, rounding: i32) -> __m128d { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fmsub_round_sd&expand=2656) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fmsub_round_sd( + a: __m128d, + k: __mmask8, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fmsub: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(fmsub, extractb, extractc, $imm4) + }; + } + fmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fmsub_round_sd&expand=2658) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fmsub_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fmsub: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fmsub_round_sd&expand=2657) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmsub213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fmsub_round_sd( + a: __m128d, + b: __m128d, + c: __m128d, + k: __mmask8, + rounding: i32, +) -> __m128d { + let mut fmsub: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extractb: f64 = simd_extract(b, 0); + let extractc = -fmsub; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fnmadd_round_ss&expand=2739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213ss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fnmadd_round_ss(a: __m128, b: __m128, c: __m128, rounding: i32) -> __m128 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmadd_round_ss&expand=2740) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fnmadd_round_ss( + a: __m128, + k: __mmask8, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fnmadd: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmadd; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fnmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmadd_round_ss&expand=2742) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fnmadd_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fnmadd: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fnmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmadd_round_ss&expand=2741) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fnmadd_round_ss( + a: __m128, + b: __m128, + c: __m128, + k: __mmask8, + rounding: i32, +) -> __m128 { + let mut fnmadd: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, fnmadd, $imm4) + }; + } + fnmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fnmadd_round_sd&expand=2735) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213sd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fnmadd_round_sd(a: __m128d, b: __m128d, c: __m128d, rounding: i32) -> __m128d { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmadd_round_sd&expand=2736) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fnmadd_round_sd( + a: __m128d, + k: __mmask8, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fnmadd: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmadd; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fnmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmadd_round_sd&expand=2738) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fnmadd_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fnmadd: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fnmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and add the negated intermediate result to the lower element in c. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmadd_round_Sd&expand=2737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmadd213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fnmadd_round_sd( + a: __m128d, + b: __m128d, + c: __m128d, + k: __mmask8, + rounding: i32, +) -> __m128d { + let mut fnmadd: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, fnmadd, $imm4) + }; + } + fnmadd = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fnmadd); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, subtract the lower element in c from the negated intermediate result, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fnmsub_round_ss&expand=2787) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213ss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fnmsub_round_ss(a: __m128, b: __m128, c: __m128, rounding: i32) -> __m128 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmsub_round_ss&expand=2788) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fnmsub_round_ss( + a: __m128, + k: __mmask8, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fnmsub: f32 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmsub; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fnmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmsub_round_ss&expand=2790) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fnmsub_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + c: __m128, + rounding: i32, +) -> __m128 { + let mut fnmsub: f32 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc: f32 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fnmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower single-precision (32-bit) floating-point elements in a and b, subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper 3 packed elements from c to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmsub_round_ss&expand=2789) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fnmsub_round_ss( + a: __m128, + b: __m128, + c: __m128, + k: __mmask8, + rounding: i32, +) -> __m128 { + let mut fnmsub: f32 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f32 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f32 = simd_extract(b, 0); + let extractc = -fnmsub; + macro_rules! call { + ($imm4:expr) => { + vfmadd132ss(extracta, extractb, extractc, $imm4) + }; + } + fnmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fnmsub_round_sd&expand=2783) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213sd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fnmsub_round_sd(a: __m128d, b: __m128d, c: __m128d, rounding: i32) -> __m128d { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fnmsub_round_sd&expand=2784) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fnmsub_round_sd( + a: __m128d, + k: __mmask8, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fnmsub: f64 = simd_extract(a, 0); + if (k & 0b00000001) != 0 { + let extracta = -fnmsub; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fnmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fnmsub_round_sd&expand=2786) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fnmsub_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + c: __m128d, + rounding: i32, +) -> __m128d { + let mut fnmsub: f64 = 0.; + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc: f64 = simd_extract(c, 0); + let extractc = -extractc; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fnmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(a, 0, fnmsub); + transmute(r) +} + +/// Multiply the lower double-precision (64-bit) floating-point elements in a and b, and subtract the lower element in c from the negated intermediate result. Store the result in the lower element of dst using writemask k (the element is copied from c when mask bit 0 is not set), and copy the upper element from c to the upper element of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask3_fnmsub_round_sd&expand=2785) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfnmsub213sd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask3_fnmsub_round_sd( + a: __m128d, + b: __m128d, + c: __m128d, + k: __mmask8, + rounding: i32, +) -> __m128d { + let mut fnmsub: f64 = simd_extract(c, 0); + if (k & 0b00000001) != 0 { + let extracta: f64 = simd_extract(a, 0); + let extracta = -extracta; + let extractb: f64 = simd_extract(b, 0); + let extractc = -fnmsub; + macro_rules! call { + ($imm4:expr) => { + vfmadd132sd(extracta, extractb, extractc, $imm4) + }; + } + fnmsub = constify_imm4_round!(rounding, call); + } + let r = simd_insert(c, 0, fnmsub); + transmute(r) +} + +/// Fix up the lower single-precision (32-bit) floating-point elements in a and b using the lower 32-bit integer in c, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fixupimm_ss&expand=2517) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmss, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fixupimm_ss(a: __m128, b: __m128, c: __m128i, imm8: i32) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let c = c.as_i32x4(); + macro_rules! call { + ($imm8:expr) => { + vfixupimmss(a, b, c, $imm8, 0b11111111, _MM_FROUND_CUR_DIRECTION) + }; + } + let fixupimm = constify_imm8_sae!(imm8, call); + let fixupimm: f32 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower single-precision (32-bit) floating-point elements in a and b using the lower 32-bit integer in c, store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fixupimm_ss&expand=2518) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmss, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fixupimm_ss( + a: __m128, + k: __mmask8, + b: __m128, + c: __m128i, + imm8: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let c = c.as_i32x4(); + macro_rules! call { + ($imm8:expr) => { + vfixupimmss(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) + }; + } + let fixupimm = constify_imm8_sae!(imm8, call); + let fixupimm: f32 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower single-precision (32-bit) floating-point elements in a and b using the lower 32-bit integer in c, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fixupimm_ss&expand=2519) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmss, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fixupimm_ss( + k: __mmask8, + a: __m128, + b: __m128, + c: __m128i, + imm8: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let c = c.as_i32x4(); + macro_rules! call { + ($imm8:expr) => { + vfixupimmssz(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) + }; + } + let fixupimm = constify_imm8_sae!(imm8, call); + let fixupimm: f32 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower double-precision (64-bit) floating-point elements in a and b using the lower 64-bit integer in c, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fixupimm_sd&expand=2514) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmsd, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_fixupimm_sd(a: __m128d, b: __m128d, c: __m128i, imm8: i32) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let c = c.as_i64x2(); + macro_rules! call { + ($imm8:expr) => { + vfixupimmsd(a, b, c, $imm8, 0b11111111, _MM_FROUND_CUR_DIRECTION) + }; + } + let fixupimm = constify_imm8_sae!(imm8, call); + let fixupimm: f64 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower double-precision (64-bit) floating-point elements in a and b using the lower 64-bit integer in c, store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fixupimm_sd&expand=2515) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmsd, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_fixupimm_sd( + a: __m128d, + k: __mmask8, + b: __m128d, + c: __m128i, + imm8: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let c = c.as_i64x2(); + macro_rules! call { + ($imm8:expr) => { + vfixupimmsd(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) + }; + } + let fixupimm = constify_imm8_sae!(imm8, call); + let fixupimm: f64 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower double-precision (64-bit) floating-point elements in a and b using the lower 64-bit integer in c, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. imm8 is used to set the required flags reporting. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fixupimm_sd&expand=2516) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmsd, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_maskz_fixupimm_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + c: __m128i, + imm8: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let c = c.as_i64x2(); + macro_rules! call { + ($imm8:expr) => { + vfixupimmsdz(a, b, c, $imm8, k, _MM_FROUND_CUR_DIRECTION) + }; + } + let fixupimm = constify_imm8_sae!(imm8, call); + let fixupimm: f64 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower single-precision (32-bit) floating-point elements in a and b using the lower 32-bit integer in c, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. imm8 is used to set the required flags reporting.\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fixupimm_round_ss&expand=2511) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmss, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm_fixupimm_round_ss( + a: __m128, + b: __m128, + c: __m128i, + imm8: i32, + sae: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let c = c.as_i32x4(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vfixupimmss(a, b, c, $imm8, 0b11111111, $imm4) + }; + } + let fixupimm = constify_imm8_roundscale!(imm8, sae, call); + let fixupimm: f32 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower single-precision (32-bit) floating-point elements in a and b using the lower 32-bit integer in c, store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. imm8 is used to set the required flags reporting.\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fixupimm_round_ss&expand=2512) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmss, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_mask_fixupimm_round_ss( + a: __m128, + k: __mmask8, + b: __m128, + c: __m128i, + imm8: i32, + sae: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let c = c.as_i32x4(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vfixupimmss(a, b, c, $imm8, k, $imm4) + }; + } + let fixupimm = constify_imm8_roundscale!(imm8, sae, call); + let fixupimm: f32 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower single-precision (32-bit) floating-point elements in a and b using the lower 32-bit integer in c, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. imm8 is used to set the required flags reporting.\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fixupimm_round_ss&expand=2513) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmss, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_maskz_fixupimm_round_ss( + k: __mmask8, + a: __m128, + b: __m128, + c: __m128i, + imm8: i32, + sae: i32, +) -> __m128 { + let a = a.as_f32x4(); + let b = b.as_f32x4(); + let c = c.as_i32x4(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vfixupimmssz(a, b, c, $imm8, k, $imm4) + }; + } + let fixupimm = constify_imm8_roundscale!(imm8, sae, call); + let fixupimm: f32 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower double-precision (64-bit) floating-point elements in a and b using the lower 64-bit integer in c, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. imm8 is used to set the required flags reporting.\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_fixupimm_round_sd&expand=2508) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmsd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm_fixupimm_round_sd( + a: __m128d, + b: __m128d, + c: __m128i, + imm8: i32, + sae: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let c = c.as_i64x2(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vfixupimmsd(a, b, c, $imm8, 0b11111111, $imm4) + }; + } + let fixupimm = constify_imm8_roundscale!(imm8, sae, call); + let fixupimm: f64 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower double-precision (64-bit) floating-point elements in a and b using the lower 64-bit integer in c, store the result in the lower element of dst using writemask k (the element is copied from a when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. imm8 is used to set the required flags reporting.\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_fixupimm_round_sd&expand=2509) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmsd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_mask_fixupimm_round_sd( + a: __m128d, + k: __mmask8, + b: __m128d, + c: __m128i, + imm8: i32, + sae: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let c = c.as_i64x2(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vfixupimmsd(a, b, c, $imm8, k, $imm4) + }; + } + let fixupimm = constify_imm8_roundscale!(imm8, sae, call); + let fixupimm: f64 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Fix up the lower double-precision (64-bit) floating-point elements in a and b using the lower 64-bit integer in c, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. imm8 is used to set the required flags reporting.\ +/// +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_fixupimm_round_sd&expand=2510) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfixupimmsd, imm8 = 0, sae = 8))] +#[rustc_args_required_const(4, 5)] +pub unsafe fn _mm_maskz_fixupimm_round_sd( + k: __mmask8, + a: __m128d, + b: __m128d, + c: __m128i, + imm8: i32, + sae: i32, +) -> __m128d { + let a = a.as_f64x2(); + let b = b.as_f64x2(); + let c = c.as_i64x2(); + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vfixupimmsdz(a, b, c, $imm8, k, $imm4) + }; + } + let fixupimm = constify_imm8_roundscale!(imm8, sae, call); + let fixupimm: f64 = simd_extract(fixupimm, 0); + let r = simd_insert(a, 0, fixupimm); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_cvtss_sd&expand=1896) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2sd))] +pub unsafe fn _mm_mask_cvtss_sd(src: __m128d, k: __mmask8, a: __m128d, b: __m128) -> __m128d { + transmute(vcvtss2sd( + a.as_f64x2(), + b.as_f32x4(), + src.as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert the lower single-precision (32-bit) floating-point element in b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_cvtss_sd&expand=1897) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2sd))] +pub unsafe fn _mm_maskz_cvtss_sd(k: __mmask8, a: __m128d, b: __m128) -> __m128d { + transmute(vcvtss2sd( + a.as_f64x2(), + b.as_f32x4(), + _mm_setzero_pd().as_f64x2(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert the lower double-precision (64-bit) floating-point element in b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_cvtsd_ss&expand=1797) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2ss))] +pub unsafe fn _mm_mask_cvtsd_ss(src: __m128, k: __mmask8, a: __m128, b: __m128d) -> __m128 { + transmute(vcvtsd2ss( + a.as_f32x4(), + b.as_f64x2(), + src.as_f32x4(), + k, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + )) +} + +/// Convert the lower double-precision (64-bit) floating-point element in b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_cvtsd_ss&expand=1798) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2ss))] +pub unsafe fn _mm_maskz_cvtsd_ss(k: __mmask8, a: __m128, b: __m128d) -> __m128 { + transmute(vcvtsd2ss( + a.as_f32x4(), + b.as_f64x2(), + _mm_setzero_ps().as_f32x4(), + k, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + )) +} + +/// Convert the lower single-precision (32-bit) floating-point element in b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundss_sd&expand=1371) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2sd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_cvt_roundss_sd(a: __m128d, b: __m128, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vcvtss2sd( + a.as_f64x2(), + b.as_f32x4(), + _mm_setzero_pd().as_f64x2(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_cvt_roundss_sd&expand=1372) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2sd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_cvt_roundss_sd( + src: __m128d, + k: __mmask8, + a: __m128d, + b: __m128, + sae: i32, +) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vcvtss2sd(a.as_f64x2(), b.as_f32x4(), src.as_f64x2(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper element from a to the upper element of dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_cvt_roundss_sd&expand=1373) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2sd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_cvt_roundss_sd(k: __mmask8, a: __m128d, b: __m128, sae: i32) -> __m128d { + macro_rules! call { + ($imm4:expr) => { + vcvtss2sd( + a.as_f64x2(), + b.as_f32x4(), + _mm_setzero_pd().as_f64x2(), + k, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundsd_ss&expand=1361) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2ss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_cvt_roundsd_ss(a: __m128, b: __m128d, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2ss( + a.as_f32x4(), + b.as_f64x2(), + _mm_setzero_ps().as_f32x4(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst using writemask k (the element is copied from src when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mask_cvt_roundsd_ss&expand=1362) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2ss, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_cvt_roundsd_ss( + src: __m128, + k: __mmask8, + a: __m128, + b: __m128d, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2ss(a.as_f32x4(), b.as_f64x2(), src.as_f32x4(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst using zeromask k (the element is zeroed out when mask bit 0 is not set), and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_maskz_cvt_roundsd_ss&expand=1363) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2ss, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_cvt_roundsd_ss( + k: __mmask8, + a: __m128, + b: __m128d, + rounding: i32, +) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2ss( + a.as_f32x4(), + b.as_f64x2(), + _mm_setzero_ps().as_f32x4(), + k, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to a 32-bit integer, and store the result in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundss_si32&expand=1374) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2si, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvt_roundss_si32(a: __m128, rounding: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtss2si(a.as_f32x4(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to a 32-bit integer, and store the result in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundss_i32&expand=1369) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2si, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvt_roundss_i32(a: __m128, rounding: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtss2si(a.as_f32x4(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to an unsigned 32-bit integer, and store the result in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundss_u32&expand=1376) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2usi, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvt_roundss_u32(a: __m128, rounding: i32) -> u32 { + macro_rules! call { + ($imm4:expr) => { + vcvtss2usi(a.as_f32x4(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to a 32-bit integer, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtss_i32&expand=1893) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2si))] +pub unsafe fn _mm_cvtss_i32(a: __m128) -> i32 { + transmute(vcvtss2si(a.as_f32x4(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to an unsigned 32-bit integer, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtss_u32&expand=1901) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2usi))] +pub unsafe fn _mm_cvtss_u32(a: __m128) -> u32 { + transmute(vcvtss2usi(a.as_f32x4(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to a 32-bit integer, and store the result in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundsd_si32&expand=1359) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2si, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvt_roundsd_si32(a: __m128d, rounding: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2si(a.as_f64x2(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to a 32-bit integer, and store the result in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundsd_i32&expand=1357) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2si, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvt_roundsd_i32(a: __m128d, rounding: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2si(a.as_f64x2(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to an unsigned 32-bit integer, and store the result in dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvt_roundsd_u32&expand=1364) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2usi, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvt_roundsd_u32(a: __m128d, rounding: i32) -> u32 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2usi(a.as_f64x2(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to a 32-bit integer, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtsd_i32&expand=1791) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2si))] +pub unsafe fn _mm_cvtsd_i32(a: __m128d) -> i32 { + transmute(vcvtsd2si(a.as_f64x2(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to an unsigned 32-bit integer, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtsd_u32&expand=1799) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2usi))] +pub unsafe fn _mm_cvtsd_u32(a: __m128d) -> u32 { + transmute(vcvtsd2usi(a.as_f64x2(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the signed 32-bit integer b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundi32_ss&expand=1312) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsi2ss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_cvt_roundi32_ss(a: __m128, b: i32, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vcvtsi2ss(a.as_f32x4(), b, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the signed 32-bit integer b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundsi32_ss&expand=1366) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsi2ss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_cvt_roundsi32_ss(a: __m128, b: i32, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vcvtsi2ss(a.as_f32x4(), b, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the unsigned 32-bit integer b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst.\ +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of:\ +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions\ +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions\ +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions\ +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions\ +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvt_roundu32_ss&expand=1378) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtusi2ss, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_cvt_roundu32_ss(a: __m128, b: u32, rounding: i32) -> __m128 { + macro_rules! call { + ($imm4:expr) => { + vcvtusi2ss(a.as_f32x4(), b, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert the signed 32-bit integer b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvti32_ss&expand=1643) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsi2ss))] +pub unsafe fn _mm_cvti32_ss(a: __m128, b: i32) -> __m128 { + let b = b as f32; + let r = simd_insert(a, 0, b); + transmute(r) +} + +/// Convert the signed 32-bit integer b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvti32_sd&expand=1642) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsi2sd))] +pub unsafe fn _mm_cvti32_sd(a: __m128d, b: i32) -> __m128d { + let b = b as f64; + let r = simd_insert(a, 0, b); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to a 32-bit integer with truncation, and store the result in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtt_roundss_Si32&expand=1936) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2si, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvtt_roundss_si32(a: __m128, sae: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtss2si(a.as_f32x4(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to a 32-bit integer with truncation, and store the result in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtt_roundss_i32&expand=1934) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2si, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvtt_roundss_i32(a: __m128, sae: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtss2si(a.as_f32x4(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to an unsigned 32-bit integer with truncation, and store the result in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtt_roundss_u32&expand=1938) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2usi, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvtt_roundss_u32(a: __m128, sae: i32) -> u32 { + macro_rules! call { + ($imm4:expr) => { + vcvtss2usi(a.as_f32x4(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to a 32-bit integer with truncation, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvttss_i32&expand=2022) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2si))] +pub unsafe fn _mm_cvttss_i32(a: __m128) -> i32 { + transmute(vcvtss2si(a.as_f32x4(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the lower single-precision (32-bit) floating-point element in a to an unsigned 32-bit integer with truncation, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvttss_u32&expand=2026) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtss2usi))] +pub unsafe fn _mm_cvttss_u32(a: __m128) -> u32 { + transmute(vcvtss2usi(a.as_f32x4(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to a 32-bit integer with truncation, and store the result in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtt_roundsd_si32&expand=1930) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2si, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvtt_roundsd_si32(a: __m128d, sae: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2si(a.as_f64x2(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to a 32-bit integer with truncation, and store the result in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtt_roundsd_i32&expand=1928) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2si, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvtt_roundsd_i32(a: __m128d, sae: i32) -> i32 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2si(a.as_f64x2(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to an unsigned 32-bit integer with truncation, and store the result in dst.\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtt_roundsd_u32&expand=1932) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2usi, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm_cvtt_roundsd_u32(a: __m128d, sae: i32) -> u32 { + macro_rules! call { + ($imm4:expr) => { + vcvtsd2usi(a.as_f64x2(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to a 32-bit integer with truncation, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvttsd_i32&expand=2015) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2si))] +pub unsafe fn _mm_cvttsd_i32(a: __m128d) -> i32 { + transmute(vcvtsd2si(a.as_f64x2(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the lower double-precision (64-bit) floating-point element in a to an unsigned 32-bit integer with truncation, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvttsd_u32&expand=2020) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtsd2usi))] +pub unsafe fn _mm_cvttsd_u32(a: __m128d) -> u32 { + transmute(vcvtsd2usi(a.as_f64x2(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Convert the unsigned 32-bit integer b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtu32_ss&expand=2032) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtusi2ss))] +pub unsafe fn _mm_cvtu32_ss(a: __m128, b: u32) -> __m128 { + let b = b as f32; + let r = simd_insert(a, 0, b); + transmute(r) +} + +/// Convert the unsigned 32-bit integer b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtu32_sd&expand=2031) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtusi2sd))] +pub unsafe fn _mm_cvtu32_sd(a: __m128d, b: u32) -> __m128d { + let b = b as f64; + let r = simd_insert(a, 0, b); + transmute(r) +} + +/// Convert the unsigned 64-bit integer b to a single-precision (32-bit) floating-point element, store the result in the lower element of dst, and copy the upper 3 packed elements from a to the upper elements of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtu64_ss&expand=2035) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(mov))] // should be vcvtusi2ss +pub unsafe fn _mm_cvtu64_ss(a: __m128, b: u64) -> __m128 { + let b = b as f32; + let r = simd_insert(a, 0, b); + transmute(r) +} + +/// Convert the unsigned 64-bit integer b to a double-precision (64-bit) floating-point element, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_cvtu64_sd&expand=2034) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(mov))] // should be vcvtusi2sd +pub unsafe fn _mm_cvtu64_sd(a: __m128d, b: u64) -> __m128d { + let b = b as f64; + let r = simd_insert(a, 0, b); + transmute(r) +} + +/// Compare the lower single-precision (32-bit) floating-point element in a and b based on the comparison operand specified by imm8, and return the boolean result (0 or 1).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_comi_round_ss&expand=1175) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 5, sae = 4))] //should be vcomiss +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm_comi_round_ss(a: __m128, b: __m128, imm8: i32, sae: i32) -> i32 { + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vcomiss(a.as_f32x4(), b.as_f32x4(), $imm8, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Compare the lower double-precision (64-bit) floating-point element in a and b based on the comparison operand specified by imm8, and return the boolean result (0 or 1).\ +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_comi_round_sd&expand=1174) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcmp, imm8 = 5, sae = 4))] //should be vcomisd +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm_comi_round_sd(a: __m128d, b: __m128d, imm8: i32, sae: i32) -> i32 { + macro_rules! call { + ($imm8:expr, $imm4:expr) => { + vcomisd(a.as_f64x2(), b.as_f64x2(), $imm8, $imm4) + }; + } + let r = constify_imm5_sae!(imm8, sae, call); + transmute(r) +} + +/// Equal +pub const _MM_CMPINT_EQ: _MM_CMPINT_ENUM = 0x00; +/// Less-than +pub const _MM_CMPINT_LT: _MM_CMPINT_ENUM = 0x01; +/// Less-than-or-equal +pub const _MM_CMPINT_LE: _MM_CMPINT_ENUM = 0x02; +/// False +pub const _MM_CMPINT_FALSE: _MM_CMPINT_ENUM = 0x03; +/// Not-equal +pub const _MM_CMPINT_NE: _MM_CMPINT_ENUM = 0x04; +/// Not less-than +pub const _MM_CMPINT_NLT: _MM_CMPINT_ENUM = 0x05; +/// Not less-than-or-equal +pub const _MM_CMPINT_NLE: _MM_CMPINT_ENUM = 0x06; +/// True +pub const _MM_CMPINT_TRUE: _MM_CMPINT_ENUM = 0x07; + +/// interval [1, 2) +pub const _MM_MANT_NORM_1_2: _MM_MANTISSA_NORM_ENUM = 0x00; +/// interval [0.5, 2) +pub const _MM_MANT_NORM_P5_2: _MM_MANTISSA_NORM_ENUM = 0x01; +/// interval [0.5, 1) +pub const _MM_MANT_NORM_P5_1: _MM_MANTISSA_NORM_ENUM = 0x02; +/// interval [0.75, 1.5) +pub const _MM_MANT_NORM_P75_1P5: _MM_MANTISSA_NORM_ENUM = 0x03; + +/// sign = sign(SRC) +pub const _MM_MANT_SIGN_SRC: _MM_MANTISSA_SIGN_ENUM = 0x00; +/// sign = 0 +pub const _MM_MANT_SIGN_ZERO: _MM_MANTISSA_SIGN_ENUM = 0x01; +/// DEST = NaN if sign(SRC) = 1 +pub const _MM_MANT_SIGN_NAN: _MM_MANTISSA_SIGN_ENUM = 0x02; + +pub const _MM_PERM_AAAA: _MM_PERM_ENUM = 0x00; +pub const _MM_PERM_AAAB: _MM_PERM_ENUM = 0x01; +pub const _MM_PERM_AAAC: _MM_PERM_ENUM = 0x02; +pub const _MM_PERM_AAAD: _MM_PERM_ENUM = 0x03; +pub const _MM_PERM_AABA: _MM_PERM_ENUM = 0x04; +pub const _MM_PERM_AABB: _MM_PERM_ENUM = 0x05; +pub const _MM_PERM_AABC: _MM_PERM_ENUM = 0x06; +pub const _MM_PERM_AABD: _MM_PERM_ENUM = 0x07; +pub const _MM_PERM_AACA: _MM_PERM_ENUM = 0x08; +pub const _MM_PERM_AACB: _MM_PERM_ENUM = 0x09; +pub const _MM_PERM_AACC: _MM_PERM_ENUM = 0x0A; +pub const _MM_PERM_AACD: _MM_PERM_ENUM = 0x0B; +pub const _MM_PERM_AADA: _MM_PERM_ENUM = 0x0C; +pub const _MM_PERM_AADB: _MM_PERM_ENUM = 0x0D; +pub const _MM_PERM_AADC: _MM_PERM_ENUM = 0x0E; +pub const _MM_PERM_AADD: _MM_PERM_ENUM = 0x0F; +pub const _MM_PERM_ABAA: _MM_PERM_ENUM = 0x10; +pub const _MM_PERM_ABAB: _MM_PERM_ENUM = 0x11; +pub const _MM_PERM_ABAC: _MM_PERM_ENUM = 0x12; +pub const _MM_PERM_ABAD: _MM_PERM_ENUM = 0x13; +pub const _MM_PERM_ABBA: _MM_PERM_ENUM = 0x14; +pub const _MM_PERM_ABBB: _MM_PERM_ENUM = 0x15; +pub const _MM_PERM_ABBC: _MM_PERM_ENUM = 0x16; +pub const _MM_PERM_ABBD: _MM_PERM_ENUM = 0x17; +pub const _MM_PERM_ABCA: _MM_PERM_ENUM = 0x18; +pub const _MM_PERM_ABCB: _MM_PERM_ENUM = 0x19; +pub const _MM_PERM_ABCC: _MM_PERM_ENUM = 0x1A; +pub const _MM_PERM_ABCD: _MM_PERM_ENUM = 0x1B; +pub const _MM_PERM_ABDA: _MM_PERM_ENUM = 0x1C; +pub const _MM_PERM_ABDB: _MM_PERM_ENUM = 0x1D; +pub const _MM_PERM_ABDC: _MM_PERM_ENUM = 0x1E; +pub const _MM_PERM_ABDD: _MM_PERM_ENUM = 0x1F; +pub const _MM_PERM_ACAA: _MM_PERM_ENUM = 0x20; +pub const _MM_PERM_ACAB: _MM_PERM_ENUM = 0x21; +pub const _MM_PERM_ACAC: _MM_PERM_ENUM = 0x22; +pub const _MM_PERM_ACAD: _MM_PERM_ENUM = 0x23; +pub const _MM_PERM_ACBA: _MM_PERM_ENUM = 0x24; +pub const _MM_PERM_ACBB: _MM_PERM_ENUM = 0x25; +pub const _MM_PERM_ACBC: _MM_PERM_ENUM = 0x26; +pub const _MM_PERM_ACBD: _MM_PERM_ENUM = 0x27; +pub const _MM_PERM_ACCA: _MM_PERM_ENUM = 0x28; +pub const _MM_PERM_ACCB: _MM_PERM_ENUM = 0x29; +pub const _MM_PERM_ACCC: _MM_PERM_ENUM = 0x2A; +pub const _MM_PERM_ACCD: _MM_PERM_ENUM = 0x2B; +pub const _MM_PERM_ACDA: _MM_PERM_ENUM = 0x2C; +pub const _MM_PERM_ACDB: _MM_PERM_ENUM = 0x2D; +pub const _MM_PERM_ACDC: _MM_PERM_ENUM = 0x2E; +pub const _MM_PERM_ACDD: _MM_PERM_ENUM = 0x2F; +pub const _MM_PERM_ADAA: _MM_PERM_ENUM = 0x30; +pub const _MM_PERM_ADAB: _MM_PERM_ENUM = 0x31; +pub const _MM_PERM_ADAC: _MM_PERM_ENUM = 0x32; +pub const _MM_PERM_ADAD: _MM_PERM_ENUM = 0x33; +pub const _MM_PERM_ADBA: _MM_PERM_ENUM = 0x34; +pub const _MM_PERM_ADBB: _MM_PERM_ENUM = 0x35; +pub const _MM_PERM_ADBC: _MM_PERM_ENUM = 0x36; +pub const _MM_PERM_ADBD: _MM_PERM_ENUM = 0x37; +pub const _MM_PERM_ADCA: _MM_PERM_ENUM = 0x38; +pub const _MM_PERM_ADCB: _MM_PERM_ENUM = 0x39; +pub const _MM_PERM_ADCC: _MM_PERM_ENUM = 0x3A; +pub const _MM_PERM_ADCD: _MM_PERM_ENUM = 0x3B; +pub const _MM_PERM_ADDA: _MM_PERM_ENUM = 0x3C; +pub const _MM_PERM_ADDB: _MM_PERM_ENUM = 0x3D; +pub const _MM_PERM_ADDC: _MM_PERM_ENUM = 0x3E; +pub const _MM_PERM_ADDD: _MM_PERM_ENUM = 0x3F; +pub const _MM_PERM_BAAA: _MM_PERM_ENUM = 0x40; +pub const _MM_PERM_BAAB: _MM_PERM_ENUM = 0x41; +pub const _MM_PERM_BAAC: _MM_PERM_ENUM = 0x42; +pub const _MM_PERM_BAAD: _MM_PERM_ENUM = 0x43; +pub const _MM_PERM_BABA: _MM_PERM_ENUM = 0x44; +pub const _MM_PERM_BABB: _MM_PERM_ENUM = 0x45; +pub const _MM_PERM_BABC: _MM_PERM_ENUM = 0x46; +pub const _MM_PERM_BABD: _MM_PERM_ENUM = 0x47; +pub const _MM_PERM_BACA: _MM_PERM_ENUM = 0x48; +pub const _MM_PERM_BACB: _MM_PERM_ENUM = 0x49; +pub const _MM_PERM_BACC: _MM_PERM_ENUM = 0x4A; +pub const _MM_PERM_BACD: _MM_PERM_ENUM = 0x4B; +pub const _MM_PERM_BADA: _MM_PERM_ENUM = 0x4C; +pub const _MM_PERM_BADB: _MM_PERM_ENUM = 0x4D; +pub const _MM_PERM_BADC: _MM_PERM_ENUM = 0x4E; +pub const _MM_PERM_BADD: _MM_PERM_ENUM = 0x4F; +pub const _MM_PERM_BBAA: _MM_PERM_ENUM = 0x50; +pub const _MM_PERM_BBAB: _MM_PERM_ENUM = 0x51; +pub const _MM_PERM_BBAC: _MM_PERM_ENUM = 0x52; +pub const _MM_PERM_BBAD: _MM_PERM_ENUM = 0x53; +pub const _MM_PERM_BBBA: _MM_PERM_ENUM = 0x54; +pub const _MM_PERM_BBBB: _MM_PERM_ENUM = 0x55; +pub const _MM_PERM_BBBC: _MM_PERM_ENUM = 0x56; +pub const _MM_PERM_BBBD: _MM_PERM_ENUM = 0x57; +pub const _MM_PERM_BBCA: _MM_PERM_ENUM = 0x58; +pub const _MM_PERM_BBCB: _MM_PERM_ENUM = 0x59; +pub const _MM_PERM_BBCC: _MM_PERM_ENUM = 0x5A; +pub const _MM_PERM_BBCD: _MM_PERM_ENUM = 0x5B; +pub const _MM_PERM_BBDA: _MM_PERM_ENUM = 0x5C; +pub const _MM_PERM_BBDB: _MM_PERM_ENUM = 0x5D; +pub const _MM_PERM_BBDC: _MM_PERM_ENUM = 0x5E; +pub const _MM_PERM_BBDD: _MM_PERM_ENUM = 0x5F; +pub const _MM_PERM_BCAA: _MM_PERM_ENUM = 0x60; +pub const _MM_PERM_BCAB: _MM_PERM_ENUM = 0x61; +pub const _MM_PERM_BCAC: _MM_PERM_ENUM = 0x62; +pub const _MM_PERM_BCAD: _MM_PERM_ENUM = 0x63; +pub const _MM_PERM_BCBA: _MM_PERM_ENUM = 0x64; +pub const _MM_PERM_BCBB: _MM_PERM_ENUM = 0x65; +pub const _MM_PERM_BCBC: _MM_PERM_ENUM = 0x66; +pub const _MM_PERM_BCBD: _MM_PERM_ENUM = 0x67; +pub const _MM_PERM_BCCA: _MM_PERM_ENUM = 0x68; +pub const _MM_PERM_BCCB: _MM_PERM_ENUM = 0x69; +pub const _MM_PERM_BCCC: _MM_PERM_ENUM = 0x6A; +pub const _MM_PERM_BCCD: _MM_PERM_ENUM = 0x6B; +pub const _MM_PERM_BCDA: _MM_PERM_ENUM = 0x6C; +pub const _MM_PERM_BCDB: _MM_PERM_ENUM = 0x6D; +pub const _MM_PERM_BCDC: _MM_PERM_ENUM = 0x6E; +pub const _MM_PERM_BCDD: _MM_PERM_ENUM = 0x6F; +pub const _MM_PERM_BDAA: _MM_PERM_ENUM = 0x70; +pub const _MM_PERM_BDAB: _MM_PERM_ENUM = 0x71; +pub const _MM_PERM_BDAC: _MM_PERM_ENUM = 0x72; +pub const _MM_PERM_BDAD: _MM_PERM_ENUM = 0x73; +pub const _MM_PERM_BDBA: _MM_PERM_ENUM = 0x74; +pub const _MM_PERM_BDBB: _MM_PERM_ENUM = 0x75; +pub const _MM_PERM_BDBC: _MM_PERM_ENUM = 0x76; +pub const _MM_PERM_BDBD: _MM_PERM_ENUM = 0x77; +pub const _MM_PERM_BDCA: _MM_PERM_ENUM = 0x78; +pub const _MM_PERM_BDCB: _MM_PERM_ENUM = 0x79; +pub const _MM_PERM_BDCC: _MM_PERM_ENUM = 0x7A; +pub const _MM_PERM_BDCD: _MM_PERM_ENUM = 0x7B; +pub const _MM_PERM_BDDA: _MM_PERM_ENUM = 0x7C; +pub const _MM_PERM_BDDB: _MM_PERM_ENUM = 0x7D; +pub const _MM_PERM_BDDC: _MM_PERM_ENUM = 0x7E; +pub const _MM_PERM_BDDD: _MM_PERM_ENUM = 0x7F; +pub const _MM_PERM_CAAA: _MM_PERM_ENUM = 0x80; +pub const _MM_PERM_CAAB: _MM_PERM_ENUM = 0x81; +pub const _MM_PERM_CAAC: _MM_PERM_ENUM = 0x82; +pub const _MM_PERM_CAAD: _MM_PERM_ENUM = 0x83; +pub const _MM_PERM_CABA: _MM_PERM_ENUM = 0x84; +pub const _MM_PERM_CABB: _MM_PERM_ENUM = 0x85; +pub const _MM_PERM_CABC: _MM_PERM_ENUM = 0x86; +pub const _MM_PERM_CABD: _MM_PERM_ENUM = 0x87; +pub const _MM_PERM_CACA: _MM_PERM_ENUM = 0x88; +pub const _MM_PERM_CACB: _MM_PERM_ENUM = 0x89; +pub const _MM_PERM_CACC: _MM_PERM_ENUM = 0x8A; +pub const _MM_PERM_CACD: _MM_PERM_ENUM = 0x8B; +pub const _MM_PERM_CADA: _MM_PERM_ENUM = 0x8C; +pub const _MM_PERM_CADB: _MM_PERM_ENUM = 0x8D; +pub const _MM_PERM_CADC: _MM_PERM_ENUM = 0x8E; +pub const _MM_PERM_CADD: _MM_PERM_ENUM = 0x8F; +pub const _MM_PERM_CBAA: _MM_PERM_ENUM = 0x90; +pub const _MM_PERM_CBAB: _MM_PERM_ENUM = 0x91; +pub const _MM_PERM_CBAC: _MM_PERM_ENUM = 0x92; +pub const _MM_PERM_CBAD: _MM_PERM_ENUM = 0x93; +pub const _MM_PERM_CBBA: _MM_PERM_ENUM = 0x94; +pub const _MM_PERM_CBBB: _MM_PERM_ENUM = 0x95; +pub const _MM_PERM_CBBC: _MM_PERM_ENUM = 0x96; +pub const _MM_PERM_CBBD: _MM_PERM_ENUM = 0x97; +pub const _MM_PERM_CBCA: _MM_PERM_ENUM = 0x98; +pub const _MM_PERM_CBCB: _MM_PERM_ENUM = 0x99; +pub const _MM_PERM_CBCC: _MM_PERM_ENUM = 0x9A; +pub const _MM_PERM_CBCD: _MM_PERM_ENUM = 0x9B; +pub const _MM_PERM_CBDA: _MM_PERM_ENUM = 0x9C; +pub const _MM_PERM_CBDB: _MM_PERM_ENUM = 0x9D; +pub const _MM_PERM_CBDC: _MM_PERM_ENUM = 0x9E; +pub const _MM_PERM_CBDD: _MM_PERM_ENUM = 0x9F; +pub const _MM_PERM_CCAA: _MM_PERM_ENUM = 0xA0; +pub const _MM_PERM_CCAB: _MM_PERM_ENUM = 0xA1; +pub const _MM_PERM_CCAC: _MM_PERM_ENUM = 0xA2; +pub const _MM_PERM_CCAD: _MM_PERM_ENUM = 0xA3; +pub const _MM_PERM_CCBA: _MM_PERM_ENUM = 0xA4; pub const _MM_PERM_CCBB: _MM_PERM_ENUM = 0xA5; pub const _MM_PERM_CCBC: _MM_PERM_ENUM = 0xA6; pub const _MM_PERM_CCBD: _MM_PERM_ENUM = 0xA7; @@ -13696,7226 +24638,12440 @@ pub const _MM_PERM_DDDB: _MM_PERM_ENUM = 0xFD; pub const _MM_PERM_DDDC: _MM_PERM_ENUM = 0xFE; pub const _MM_PERM_DDDD: _MM_PERM_ENUM = 0xFF; -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.x86.avx512.pmul.dq.512"] - fn vpmuldq(a: i32x16, b: i32x16) -> i64x8; - #[link_name = "llvm.x86.avx512.pmulu.dq.512"] - fn vpmuludq(a: u32x16, b: u32x16) -> u64x8; +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.avx512.pmul.dq.512"] + fn vpmuldq(a: i32x16, b: i32x16) -> i64x8; + #[link_name = "llvm.x86.avx512.pmulu.dq.512"] + fn vpmuludq(a: u32x16, b: u32x16) -> u64x8; + + #[link_name = "llvm.x86.avx512.mask.pmaxs.d.512"] + fn vpmaxsd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pmaxs.q.512"] + fn vpmaxsq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pmins.d.512"] + fn vpminsd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pmins.q.512"] + fn vpminsq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.mask.pmaxu.d.512"] + fn vpmaxud(a: u32x16, b: u32x16) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.pmaxu.q.512"] + fn vpmaxuq(a: u64x8, b: u64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pminu.d.512"] + fn vpminud(a: u32x16, b: u32x16) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.pminu.q.512"] + fn vpminuq(a: u64x8, b: u64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.sqrt.ps.512"] + fn vsqrtps(a: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.sqrt.pd.512"] + fn vsqrtpd(a: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.vfmadd.ps.512"] + fn vfmadd132ps(a: f32x16, b: f32x16, c: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.vfmadd.pd.512"] + fn vfmadd132pd(a: f64x8, b: f64x8, c: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.vfmaddsub.ps.512"] + fn vfmaddsub213ps(a: f32x16, b: f32x16, c: f32x16, d: i32) -> f32x16; //from clang + #[link_name = "llvm.x86.avx512.vfmaddsub.pd.512"] + fn vfmaddsub213pd(a: f64x8, b: f64x8, c: f64x8, d: i32) -> f64x8; //from clang + + #[link_name = "llvm.x86.avx512.add.ps.512"] + fn vaddps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.add.pd.512"] + fn vaddpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.sub.ps.512"] + fn vsubps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.sub.pd.512"] + fn vsubpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.mul.ps.512"] + fn vmulps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mul.pd.512"] + fn vmulpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.div.ps.512"] + fn vdivps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.div.pd.512"] + fn vdivpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.max.ps.512"] + fn vmaxps(a: f32x16, b: f32x16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.max.pd.512"] + fn vmaxpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.min.ps.512"] + fn vminps(a: f32x16, b: f32x16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.min.pd.512"] + fn vminpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.getexp.ps.512"] + fn vgetexpps(a: f32x16, src: f32x16, m: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.getexp.pd.512"] + fn vgetexppd(a: f64x8, src: f64x8, m: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.rndscale.ps.512"] + fn vrndscaleps(a: f32x16, imm8: i32, src: f32x16, mask: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.rndscale.pd.512"] + fn vrndscalepd(a: f64x8, imm8: i32, src: f64x8, mask: u8, sae: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.mask.scalef.ps.512"] + fn vscalefps(a: f32x16, b: f32x16, src: f32x16, mask: u16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.scalef.pd.512"] + fn vscalefpd(a: f64x8, b: f64x8, src: f64x8, mask: u8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.fixupimm.ps.512"] + fn vfixupimmps(a: f32x16, b: f32x16, c: i32x16, imm8: i32, mask: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.fixupimm.pd.512"] + fn vfixupimmpd(a: f64x8, b: f64x8, c: i64x8, imm8: i32, mask: u8, sae: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.maskz.fixupimm.ps.512"] + fn vfixupimmpsz(a: f32x16, b: f32x16, c: i32x16, imm8: i32, mask: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.maskz.fixupimm.pd.512"] + fn vfixupimmpdz(a: f64x8, b: f64x8, c: i64x8, imm8: i32, mask: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.pternlog.d.512"] + fn vpternlogd(a: i32x16, b: i32x16, c: i32x16, sae: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.pternlog.q.512"] + fn vpternlogq(a: i64x8, b: i64x8, c: i64x8, sae: i32) -> i64x8; + + #[link_name = "llvm.x86.avx512.mask.getmant.ps.512"] + fn vgetmantps(a: f32x16, mantissas: i32, src: f32x16, m: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.getmant.pd.512"] + fn vgetmantpd(a: f64x8, mantissas: i32, src: f64x8, m: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.rcp14.ps.512"] + fn vrcp14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.rcp14.pd.512"] + fn vrcp14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; + #[link_name = "llvm.x86.avx512.rsqrt14.ps.512"] + fn vrsqrt14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.rsqrt14.pd.512"] + fn vrsqrt14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.cvtps2dq.512"] + fn vcvtps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.cvtps2udq.512"] + fn vcvtps2udq(a: f32x16, src: u32x16, mask: u16, rounding: i32) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.cvtps2pd.512"] + fn vcvtps2pd(a: f32x8, src: f64x8, mask: u8, sae: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.mask.cvtpd2ps.512"] + fn vcvtpd2ps(a: f64x8, src: f32x8, mask: u8, rounding: i32) -> f32x8; + #[link_name = "llvm.x86.avx512.mask.cvtpd2dq.512"] + fn vcvtpd2dq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> i32x8; + #[link_name = "llvm.x86.avx512.mask.cvtpd2udq.512"] + fn vcvtpd2udq(a: f64x8, src: u32x8, mask: u8, rounding: i32) -> u32x8; + #[link_name = "llvm.x86.avx512.sitofp.round.v16f32.v16i32"] + fn vcvtdq2ps(a: i32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.uitofp.round.v16f32.v16i32"] + fn vcvtudq2ps(a: u32x16, rounding: i32) -> f32x16; + + #[link_name = "llvm.x86.avx512.mask.vcvtps2ph.512"] + fn vcvtps2ph(a: f32x16, sae: i32, src: i16x16, mask: u16) -> i16x16; + #[link_name = "llvm.x86.avx512.mask.vcvtph2ps.512"] + fn vcvtph2ps(a: i16x16, src: f32x16, mask: u16, sae: i32) -> f32x16; + + #[link_name = "llvm.x86.avx512.mask.cvttps2dq.512"] + fn vcvttps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.cvttps2udq.512"] + fn vcvttps2udq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.cvttpd2dq.512"] + fn vcvttpd2dq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> i32x8; + #[link_name = "llvm.x86.avx512.mask.cvttpd2udq.512"] + fn vcvttpd2udq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> u32x8; + + #[link_name = "llvm.x86.avx512.mask.pmov.qb.512"] + fn vpmovqb(a: i64x8, src: i8x16, mask: u8) -> i8x16; + #[link_name = "llvm.x86.avx512.mask.pmovs.dw.512"] + fn vpmovsdw(a: i32x16, src: i16x16, mask: u16) -> i16x16; + #[link_name = "llvm.x86.avx512.mask.pmovs.db.512"] + fn vpmovsdb(a: i32x16, src: i8x16, mask: u16) -> i8x16; + #[link_name = "llvm.x86.avx512.mask.pmovs.qd.512"] + fn vpmovsqd(a: i64x8, src: i32x8, mask: u8) -> i32x8; + #[link_name = "llvm.x86.avx512.mask.pmovs.qw.512"] + fn vpmovsqw(a: i64x8, src: i16x8, mask: u8) -> i16x8; + #[link_name = "llvm.x86.avx512.mask.pmovs.qb.512"] + fn vpmovsqb(a: i64x8, src: i8x16, mask: u8) -> i8x16; + #[link_name = "llvm.x86.avx512.mask.pmovus.dw.512"] + fn vpmovusdw(a: u32x16, src: u16x16, mask: u16) -> u16x16; + #[link_name = "llvm.x86.avx512.mask.pmovus.db.512"] + fn vpmovusdb(a: u32x16, src: u8x16, mask: u16) -> u8x16; + #[link_name = "llvm.x86.avx512.mask.pmovus.qd.512"] + fn vpmovusqd(a: u64x8, src: u32x8, mask: u8) -> u32x8; + #[link_name = "llvm.x86.avx512.mask.pmovus.qw.512"] + fn vpmovusqw(a: u64x8, src: u16x8, mask: u8) -> u16x8; + #[link_name = "llvm.x86.avx512.mask.pmovus.qb.512"] + fn vpmovusqb(a: u64x8, src: u8x16, mask: u8) -> u8x16; + + #[link_name = "llvm.x86.avx512.gather.dpd.512"] + fn vgatherdpd(src: f64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.gather.dps.512"] + fn vgatherdps(src: f32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.gather.qpd.512"] + fn vgatherqpd(src: f64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.gather.qps.512"] + fn vgatherqps(src: f32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f32x8; + #[link_name = "llvm.x86.avx512.gather.dpq.512"] + fn vpgatherdq(src: i64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> i64x8; + #[link_name = "llvm.x86.avx512.gather.dpi.512"] + fn vpgatherdd(src: i32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.gather.qpq.512"] + fn vpgatherqq(src: i64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i64x8; + #[link_name = "llvm.x86.avx512.gather.qpi.512"] + fn vpgatherqd(src: i32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i32x8; + + #[link_name = "llvm.x86.avx512.scatter.dpd.512"] + fn vscatterdpd(slice: *mut i8, mask: i8, offsets: i32x8, src: f64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.dps.512"] + fn vscatterdps(slice: *mut i8, mask: i16, offsets: i32x16, src: f32x16, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qpd.512"] + fn vscatterqpd(slice: *mut i8, mask: i8, offsets: i64x8, src: f64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qps.512"] + fn vscatterqps(slice: *mut i8, mask: i8, offsets: i64x8, src: f32x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.dpq.512"] + fn vpscatterdq(slice: *mut i8, mask: i8, offsets: i32x8, src: i64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.dpi.512"] + fn vpscatterdd(slice: *mut i8, mask: i16, offsets: i32x16, src: i32x16, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qpq.512"] + fn vpscatterqq(slice: *mut i8, mask: i8, offsets: i64x8, src: i64x8, scale: i32); + #[link_name = "llvm.x86.avx512.scatter.qpi.512"] + fn vpscatterqd(slice: *mut i8, mask: i8, offsets: i64x8, src: i32x8, scale: i32); + + #[link_name = "llvm.x86.avx512.mask.cmp.ss"] + fn vcmpss(a: __m128, b: __m128, op: i32, m: i8, sae: i32) -> i8; + #[link_name = "llvm.x86.avx512.mask.cmp.sd"] + fn vcmpsd(a: __m128d, b: __m128d, op: i32, m: i8, sae: i32) -> i8; + #[link_name = "llvm.x86.avx512.mask.cmp.ps.512"] + fn vcmpps(a: f32x16, b: f32x16, op: i32, m: i16, sae: i32) -> i16; + #[link_name = "llvm.x86.avx512.mask.cmp.pd.512"] + fn vcmppd(a: f64x8, b: f64x8, op: i32, m: i8, sae: i32) -> i8; + #[link_name = "llvm.x86.avx512.mask.ucmp.q.512"] + fn vpcmpuq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; + #[link_name = "llvm.x86.avx512.mask.cmp.q.512"] + fn vpcmpq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; + #[link_name = "llvm.x86.avx512.mask.ucmp.d.512"] + fn vpcmpud(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; + #[link_name = "llvm.x86.avx512.mask.cmp.d.512"] + fn vpcmpd(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; + + #[link_name = "llvm.x86.avx512.mask.prol.d.512"] + fn vprold(a: i32x16, i8: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pror.d.512"] + fn vprord(a: i32x16, i8: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prol.q.512"] + fn vprolq(a: i64x8, i8: i32) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pror.q.512"] + fn vprorq(a: i64x8, i8: i32) -> i64x8; + + #[link_name = "llvm.x86.avx512.mask.prolv.d.512"] + fn vprolvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prorv.d.512"] + fn vprorvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prolv.q.512"] + fn vprolvq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.prorv.q.512"] + fn vprorvq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.psllv.d.512"] + fn vpsllvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psrlv.d.512"] + fn vpsrlvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psllv.q.512"] + fn vpsllvq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.psrlv.q.512"] + fn vpsrlvq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.pslli.d.512"] + fn vpsllid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.psrli.d.512"] + fn vpsrlid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.pslli.q.512"] + fn vpslliq(a: i64x8, imm8: u32) -> i64x8; + #[link_name = "llvm.x86.avx512.psrli.q.512"] + fn vpsrliq(a: i64x8, imm8: u32) -> i64x8; + + #[link_name = "llvm.x86.avx512.psll.d.512"] + fn vpslld(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psrl.d.512"] + fn vpsrld(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psll.q.512"] + fn vpsllq(a: i64x8, count: i64x2) -> i64x8; + #[link_name = "llvm.x86.avx512.psrl.q.512"] + fn vpsrlq(a: i64x8, count: i64x2) -> i64x8; + + #[link_name = "llvm.x86.avx512.psra.d.512"] + fn vpsrad(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psra.q.512"] + fn vpsraq(a: i64x8, count: i64x2) -> i64x8; + + #[link_name = "llvm.x86.avx512.psrai.d.512"] + fn vpsraid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.psrai.q.512"] + fn vpsraiq(a: i64x8, imm8: u32) -> i64x8; + + #[link_name = "llvm.x86.avx512.psrav.d.512"] + fn vpsravd(a: i32x16, count: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psrav.q.512"] + fn vpsravq(a: i64x8, count: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.vpermilvar.ps.512"] + fn vpermilps(a: f32x16, b: i32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.vpermilvar.pd.512"] + fn vpermilpd(a: f64x8, b: i64x8) -> f64x8; + + #[link_name = "llvm.x86.avx512.permvar.si.512"] + fn vpermd(a: i32x16, idx: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.permvar.di.512"] + fn vpermq(a: i64x8, idx: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.permvar.sf.512"] + fn vpermps(a: f32x16, idx: i32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.permvar.df.512"] + fn vpermpd(a: f64x8, idx: i64x8) -> f64x8; + + #[link_name = "llvm.x86.avx512.vpermi2var.d.512"] + fn vpermi2d(a: i32x16, idx: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.vpermi2var.q.512"] + fn vpermi2q(a: i64x8, idx: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.vpermi2var.ps.512"] + fn vpermi2ps(a: f32x16, idx: i32x16, b: f32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.vpermi2var.pd.512"] + fn vpermi2pd(a: f64x8, idx: i64x8, b: f64x8) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.compress.d.512"] + fn vpcompressd(a: i32x16, src: i32x16, mask: u16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.compress.q.512"] + fn vpcompressq(a: i64x8, src: i64x8, mask: u8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.compress.ps.512"] + fn vcompressps(a: f32x16, src: f32x16, mask: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.compress.pd.512"] + fn vcompresspd(a: f64x8, src: f64x8, mask: u8) -> f64x8; + #[link_name = "llvm.x86.avx512.mask.expand.d.512"] + fn vpexpandd(a: i32x16, src: i32x16, mask: u16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.expand.q.512"] + fn vpexpandq(a: i64x8, src: i64x8, mask: u8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.expand.ps.512"] + fn vexpandps(a: f32x16, src: f32x16, mask: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.expand.pd.512"] + fn vexpandpd(a: f64x8, src: f64x8, mask: u8) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.add.ss.round"] + fn vaddss(a: f32x4, b: f32x4, src: f32x4, mask: u8, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.add.sd.round"] + fn vaddsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, rounding: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.sub.ss.round"] + fn vsubss(a: f32x4, b: f32x4, src: f32x4, mask: u8, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.sub.sd.round"] + fn vsubsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, rounding: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.mul.ss.round"] + fn vmulss(a: f32x4, b: f32x4, src: f32x4, mask: u8, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.mul.sd.round"] + fn vmulsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, rounding: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.div.ss.round"] + fn vdivss(a: f32x4, b: f32x4, src: f32x4, mask: u8, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.div.sd.round"] + fn vdivsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, rounding: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.max.ss.round"] + fn vmaxss(a: f32x4, b: f32x4, src: f32x4, mask: u8, sae: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.max.sd.round"] + fn vmaxsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, sae: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.min.ss.round"] + fn vminss(a: f32x4, b: f32x4, src: f32x4, mask: u8, sae: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.min.sd.round"] + fn vminsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, sae: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.sqrt.ss"] + fn vsqrtss(a: f32x4, b: f32x4, src: f32x4, mask: u8, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.sqrt.sd"] + fn vsqrtsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, rounding: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.getexp.ss"] + fn vgetexpss(a: f32x4, b: f32x4, src: f32x4, mask: u8, sae: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.getexp.sd"] + fn vgetexpsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, sae: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.getmant.ss"] + fn vgetmantss(a: f32x4, b: f32x4, mantissas: i32, src: f32x4, m: u8, sae: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.getmant.sd"] + fn vgetmantsd(a: f64x2, b: f64x2, mantissas: i32, src: f64x2, m: u8, sae: i32) -> f64x2; + + #[link_name = "llvm.x86.avx512.rsqrt14.ss"] + fn vrsqrt14ss(a: f32x4, b: f32x4, src: f32x4, mask: u8) -> f32x4; + #[link_name = "llvm.x86.avx512.rsqrt14.sd"] + fn vrsqrt14sd(a: f64x2, b: f64x2, src: f64x2, mask: u8) -> f64x2; + #[link_name = "llvm.x86.avx512.rcp14.ss"] + fn vrcp14ss(a: f32x4, b: f32x4, src: f32x4, mask: u8) -> f32x4; + #[link_name = "llvm.x86.avx512.rcp14.sd"] + fn vrcp14sd(a: f64x2, b: f64x2, src: f64x2, mask: u8) -> f64x2; + + #[link_name = "llvm.x86.avx512.mask.rndscale.ss"] + fn vrndscaless(a: f32x4, b: f32x4, src: f32x4, mask: u8, imm8: i32, sae: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.rndscale.sd"] + fn vrndscalesd(a: f64x2, b: f64x2, src: f64x2, mask: u8, imm8: i32, sae: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.scalef.ss"] + fn vscalefss(a: f32x4, b: f32x4, src: f32x4, mask: u8, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.scalef.sd"] + fn vscalefsd(a: f64x2, b: f64x2, src: f64x2, mask: u8, rounding: i32) -> f64x2; + + #[link_name = "llvm.x86.avx512.vfmadd.f32"] + fn vfmadd132ss(a: f32, b: f32, c: f32, rounding: i32) -> f32; + #[link_name = "llvm.x86.avx512.vfmadd.f64"] + fn vfmadd132sd(a: f64, b: f64, c: f64, rounding: i32) -> f64; + + #[link_name = "llvm.x86.avx512.mask.fixupimm.ss"] + fn vfixupimmss(a: f32x4, b: f32x4, c: i32x4, imm8: i32, mask: u8, sae: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.mask.fixupimm.sd"] + fn vfixupimmsd(a: f64x2, b: f64x2, c: i64x2, imm8: i32, mask: u8, sae: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.maskz.fixupimm.ss"] + fn vfixupimmssz(a: f32x4, b: f32x4, c: i32x4, imm8: i32, mask: u8, sae: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.maskz.fixupimm.sd"] + fn vfixupimmsdz(a: f64x2, b: f64x2, c: i64x2, imm8: i32, mask: u8, sae: i32) -> f64x2; + + #[link_name = "llvm.x86.avx512.mask.cvtss2sd.round"] + fn vcvtss2sd(a: f64x2, a: f32x4, src: f64x2, mask: u8, sae: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.mask.cvtsd2ss.round"] + fn vcvtsd2ss(a: f32x4, b: f64x2, src: f32x4, mask: u8, rounding: i32) -> f32x4; + + #[link_name = "llvm.x86.avx512.vcvtss2si32"] + fn vcvtss2si(a: f32x4, rounding: i32) -> i32; + #[link_name = "llvm.x86.avx512.vcvtss2si64"] + fn vcvtss2si64(a: f32x4, rounding: i32) -> i64; + #[link_name = "llvm.x86.avx512.vcvtss2usi32"] + fn vcvtss2usi(a: f32x4, rounding: i32) -> u32; + #[link_name = "llvm.x86.avx512.vcvtss2usi64"] + fn vcvtss2usi64(a: f32x4, rounding: i32) -> u64; + #[link_name = "llvm.x86.avx512.vcvtsd2si32"] + fn vcvtsd2si(a: f64x2, rounding: i32) -> i32; + #[link_name = "llvm.x86.avx512.vcvtsd2si64"] + fn vcvtsd2si64(a: f64x2, rounding: i32) -> i64; + #[link_name = "llvm.x86.avx512.vcvtsd2usi32"] + fn vcvtsd2usi(a: f64x2, rounding: i32) -> u32; + #[link_name = "llvm.x86.avx512.vcvtsd2usi64"] + fn vcvtsd2usi64(a: f64x2, rounding: i32) -> u64; + + #[link_name = "llvm.x86.avx512.cvtsi2ss32"] + fn vcvtsi2ss(a: f32x4, b: i32, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.cvtsi2ss64"] + fn vcvtsi2ss64(a: f32x4, b: i64, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.cvtsi2sd64"] + fn vcvtsi2sd(a: f64x2, b: i64, rounding: i32) -> f64x2; + #[link_name = "llvm.x86.avx512.cvtusi2ss"] + fn vcvtusi2ss(a: f32x4, b: u32, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.cvtusi642ss"] + fn vcvtusi2ss64(a: f32x4, b: u64, rounding: i32) -> f32x4; + #[link_name = "llvm.x86.avx512.cvtusi642sd"] + fn vcvtusi2sd(a: f64x2, b: u64, rounding: i32) -> f64x2; + + #[link_name = "llvm.x86.avx512.vcomi.ss"] + fn vcomiss(a: f32x4, b: f32x4, imm8: i32, sae: i32) -> i32; + #[link_name = "llvm.x86.avx512.vcomi.sd"] + fn vcomisd(a: f64x2, b: f64x2, imm8: i32, sae: i32) -> i32; +} + +#[cfg(test)] +mod tests { + + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + use crate::hint::black_box; + use crate::mem::{self}; + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_abs_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm512_abs_epi32(a); + let e = _mm512_setr_epi32( + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_abs_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm512_mask_abs_epi32(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_abs_epi32(a, 0b00000000_11111111, a); + let e = _mm512_setr_epi32( + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_abs_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let r = _mm512_maskz_abs_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_abs_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32( + 0, + 1, + 1, + i32::MAX, + i32::MAX.wrapping_add(1), + 100, + 100, + 32, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_abs_ps() { + #[rustfmt::skip] + let a = _mm512_setr_ps( + 0., 1., -1., f32::MAX, + f32::MIN, 100., -100., -32., + 0., 1., -1., f32::MAX, + f32::MIN, 100., -100., -32., + ); + let r = _mm512_abs_ps(a); + let e = _mm512_setr_ps( + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_abs_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let r = _mm512_mask_abs_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_abs_ps(a, 0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mov_epi32() { + let src = _mm512_set1_epi32(1); + let a = _mm512_set1_epi32(2); + let r = _mm512_mask_mov_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_mov_epi32(src, 0b11111111_11111111, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mov_epi32() { + let a = _mm512_set1_epi32(2); + let r = _mm512_maskz_mov_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mov_epi32(0b11111111_11111111, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mov_ps() { + let src = _mm512_set1_ps(1.); + let a = _mm512_set1_ps(2.); + let r = _mm512_mask_mov_ps(src, 0, a); + assert_eq_m512(r, src); + let r = _mm512_mask_mov_ps(src, 0b11111111_11111111, a); + assert_eq_m512(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mov_ps() { + let a = _mm512_set1_ps(2.); + let r = _mm512_maskz_mov_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_mov_ps(0b11111111_11111111, a); + assert_eq_m512(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_add_epi32(a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_add_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_add_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_add_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_add_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_add_ps(a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_add_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_add_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_add_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_add_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_sub_epi32(a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_sub_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_sub_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_sub_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sub_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_sub_ps(a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_sub_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_sub_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_sub_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sub_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_mullo_epi32(a, b); + let e = _mm512_setr_epi32( + 0, 2, -2, -2, 0, 200, -200, -64, 0, 2, -2, -2, 0, 200, -200, -64, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_mask_mullo_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mullo_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 0, + 2, + -2, + -2, + 0, + 200, + -200, + -64, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_maskz_mullo_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mullo_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 2, -2, -2, 0, 200, -200, -64, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_mul_ps(a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_mask_mul_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_mul_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_maskz_mul_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_mul_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_div_ps(a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 0.5, + -0.5, + 500., + f32::NEG_INFINITY, + 50., + -50., + -16., + ); + assert_eq_m512(r, e); // 0/0 = NAN + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_mask_div_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_div_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 1., + -1., + 1000., + -131., + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_maskz_div_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_div_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epi32(a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_max_ps(a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_max_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_max_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_max_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_max_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epu32(a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epu32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epu32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epi32(a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_min_ps(a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_min_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_min_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_min_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_min_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epu32(a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epu32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epu32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_sqrt_ps(a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_mask_sqrt_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_sqrt_ps(a, 0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 64., 81., 100., 121., 144., 169., 196., 225., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_maskz_sqrt_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sqrt_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmaddsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 7., 10., 9., 12., 11., 14., 13., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmaddsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmaddsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmaddsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmaddsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmsubadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 9., 8., 11., 10., 13., 12., 15., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmsubadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsubadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmsubadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsubadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fnmadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fnmadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fnmadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fnmadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fnmsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., -15., -16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fnmsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fnmsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fnmsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_rcp14_ps(a); + let e = _mm512_set1_ps(0.33333206); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_rcp14_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_rcp14_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 0.33333206, 0.33333206, 0.33333206, 0.33333206, + 0.33333206, 0.33333206, 0.33333206, 0.33333206, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_rcp14_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_rcp14_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.33333206, 0.33333206, 0.33333206, 0.33333206, + 0.33333206, 0.33333206, 0.33333206, 0.33333206, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_rsqrt14_ps(a); + let e = _mm512_set1_ps(0.5773392); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_rsqrt14_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_rsqrt14_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, + 0.5773392, 0.5773392, 0.5773392, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_rsqrt14_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_rsqrt14_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, + 0.5773392, 0.5773392, 0.5773392, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_getexp_ps(a); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_getexp_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_getexp_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_getexp_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getexp_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_roundscale_ps() { + let a = _mm512_set1_ps(1.1); + let r = _mm512_roundscale_ps(a, 0); + let e = _mm512_set1_ps(1.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_roundscale_ps() { + let a = _mm512_set1_ps(1.1); + let r = _mm512_mask_roundscale_ps(a, 0, a, 0); + let e = _mm512_set1_ps(1.1); + assert_eq_m512(r, e); + let r = _mm512_mask_roundscale_ps(a, 0b11111111_11111111, a, 0); + let e = _mm512_set1_ps(1.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_roundscale_ps() { + let a = _mm512_set1_ps(1.1); + let r = _mm512_maskz_roundscale_ps(0, a, 0); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_roundscale_ps(0b11111111_11111111, a, 0); + let e = _mm512_set1_ps(1.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_scalef_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_scalef_ps(a, b); + let e = _mm512_set1_ps(8.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_scalef_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_mask_scalef_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_scalef_ps(a, 0b11111111_00000000, a, b); + let e = _mm512_set_ps( + 8., 8., 8., 8., 8., 8., 8., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_scalef_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_maskz_scalef_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_scalef_ps(0b11111111_00000000, a, b); + let e = _mm512_set_ps( + 8., 8., 8., 8., 8., 8., 8., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fixupimm_ps() { + let a = _mm512_set1_ps(f32::NAN); + let b = _mm512_set1_ps(f32::MAX); + let c = _mm512_set1_epi32(i32::MAX); + let r = _mm512_fixupimm_ps(a, b, c, 5); + let e = _mm512_set1_ps(0.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fixupimm_ps() { + let a = _mm512_set_ps( + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + 1., + 1., + 1., + 1., + 1., + 1., + 1., + 1., + ); + let b = _mm512_set1_ps(f32::MAX); + let c = _mm512_set1_epi32(i32::MAX); + let r = _mm512_mask_fixupimm_ps(a, 0b11111111_00000000, b, c, 5); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fixupimm_ps() { + let a = _mm512_set_ps( + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + 1., + 1., + 1., + 1., + 1., + 1., + 1., + 1., + ); + let b = _mm512_set1_ps(f32::MAX); + let c = _mm512_set1_epi32(i32::MAX); + let r = _mm512_maskz_fixupimm_ps(0b11111111_00000000, a, b, c, 5); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_ternarylogic_epi32() { + let a = _mm512_set1_epi32(1 << 2); + let b = _mm512_set1_epi32(1 << 1); + let c = _mm512_set1_epi32(1 << 0); + let r = _mm512_ternarylogic_epi32(a, b, c, 8); + let e = _mm512_set1_epi32(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_ternarylogic_epi32() { + let src = _mm512_set1_epi32(1 << 2); + let a = _mm512_set1_epi32(1 << 1); + let b = _mm512_set1_epi32(1 << 0); + let r = _mm512_mask_ternarylogic_epi32(src, 0, a, b, 8); + assert_eq_m512i(r, src); + let r = _mm512_mask_ternarylogic_epi32(src, 0b11111111_11111111, a, b, 8); + let e = _mm512_set1_epi32(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_ternarylogic_epi32() { + let a = _mm512_set1_epi32(1 << 2); + let b = _mm512_set1_epi32(1 << 1); + let c = _mm512_set1_epi32(1 << 0); + let r = _mm512_maskz_ternarylogic_epi32(0, a, b, c, 9); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_ternarylogic_epi32(0b11111111_11111111, a, b, c, 8); + let e = _mm512_set1_epi32(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_getmant_ps(a, _MM_MANT_NORM_P75_1P5, _MM_MANT_SIGN_NAN); + let e = _mm512_set1_ps(1.25); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_mask_getmant_ps(a, 0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512(r, a); + let r = _mm512_mask_getmant_ps( + a, + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + ); + let e = _mm512_setr_ps( + 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_maskz_getmant_ps(0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = + _mm512_maskz_getmant_ps(0b11111111_00000000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., + 0.5, + 1., + 2.5, + 3., + 4.5, + 5., + 6.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_mask_add_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_add_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_maskz_add_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_add_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., + 0.5, + 1., + 2.5, + 3., + 4.5, + 5., + 6.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_sub_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_sub_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_sub_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sub_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., + 0.15, + 0.2, + 0.35, + 0.4, + 0.55, + 0.6, + 0.75, + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., + 0.14999999, + 0.2, + 0.35, + 0.4, + 0.54999995, + 0.59999996, + 0.75, + 0.8, + 0.95, + 1.0, + 1.15, + 1.1999999, + 1.3499999, + 1.4, + 0.000000000000000000000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_mask_mul_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_mul_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_maskz_mul_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_mul_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.33333334); + assert_eq_m512(r, e); + let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.3333333); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_mask_div_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_div_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 0.33333334, 0.33333334, 0.33333334, 0.33333334, + 0.33333334, 0.33333334, 0.33333334, 0.33333334, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_maskz_div_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_div_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.33333334, 0.33333334, 0.33333334, 0.33333334, + 0.33333334, 0.33333334, 0.33333334, 0.33333334, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.7320508); + assert_eq_m512(r, e); + let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.7320509); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_sqrt_round_ps(a, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_sqrt_round_ps( + a, + 0b11111111_00000000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, + 1.7320508, 1.7320508, 1.7320508, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_sqrt_round_ps(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sqrt_round_ps( + 0b11111111_00000000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, + 1.7320508, 1.7320508, 1.7320508, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask_fmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fmadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_maskz_fmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask3_fmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask_fmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_maskz_fmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask3_fmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 1., + 1., + 1., + 1., + 1., + 1., + 1., + 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + -0.9999999, 1., -0.9999999, 1., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask_fmaddsub_round_ps( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_fmaddsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_maskz_fmaddsub_round_ps( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmaddsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask3_fmaddsub_round_ps( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmaddsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + ); + assert_eq_m512(r, e); + let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask_fmsubadd_round_ps( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsubadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_maskz_fmsubadd_round_ps( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsubadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask3_fmsubadd_round_ps( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsubadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask_fnmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, + 0.00000007, 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_maskz_fnmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask3_fnmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask_fnmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, + 0.00000007, 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_maskz_fnmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask3_fnmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, -1., -1., -1., -1., -1., -1., -1., -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_max_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_max_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_max_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_max_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_max_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_min_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_min_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_min_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_min_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_min_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_getexp_round_ps(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + let r = _mm512_getexp_round_ps(a, _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_getexp_round_ps(a, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_getexp_round_ps(a, 0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_getexp_round_ps(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getexp_round_ps(0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_roundscale_round_ps() { + let a = _mm512_set1_ps(1.1); + let r = _mm512_roundscale_round_ps(a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(1.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_roundscale_round_ps() { + let a = _mm512_set1_ps(1.1); + let r = _mm512_mask_roundscale_round_ps(a, 0, a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(1.1); + assert_eq_m512(r, e); + let r = + _mm512_mask_roundscale_round_ps(a, 0b11111111_11111111, a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(1.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_roundscale_round_ps() { + let a = _mm512_set1_ps(1.1); + let r = _mm512_maskz_roundscale_round_ps(0, a, 0, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = + _mm512_maskz_roundscale_round_ps(0b11111111_11111111, a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(1.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_scalef_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_scalef_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(8.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_scalef_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = + _mm512_mask_scalef_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_scalef_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_set_ps( + 8., 8., 8., 8., 8., 8., 8., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_scalef_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = + _mm512_maskz_scalef_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_scalef_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_set_ps( + 8., 8., 8., 8., 8., 8., 8., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fixupimm_round_ps() { + let a = _mm512_set1_ps(f32::NAN); + let b = _mm512_set1_ps(f32::MAX); + let c = _mm512_set1_epi32(i32::MAX); + let r = _mm512_fixupimm_round_ps(a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(0.0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fixupimm_round_ps() { + let a = _mm512_set_ps( + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + 1., + 1., + 1., + 1., + 1., + 1., + 1., + 1., + ); + let b = _mm512_set1_ps(f32::MAX); + let c = _mm512_set1_epi32(i32::MAX); + let r = _mm512_mask_fixupimm_round_ps( + a, + 0b11111111_00000000, + b, + c, + 5, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fixupimm_round_ps() { + let a = _mm512_set_ps( + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + f32::NAN, + 1., + 1., + 1., + 1., + 1., + 1., + 1., + 1., + ); + let b = _mm512_set1_ps(f32::MAX); + let c = _mm512_set1_epi32(i32::MAX); + let r = _mm512_maskz_fixupimm_round_ps( + 0b11111111_00000000, + a, + b, + c, + 5, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_getmant_round_ps( + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_set1_ps(1.25); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_mask_getmant_round_ps( + a, + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_getmant_round_ps( + a, + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_ps( + 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_maskz_getmant_round_ps( + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getmant_round_ps( + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtps_epi32(a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtps_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtps_epi32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtps_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtps_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtps_epu32(a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtps_epu32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtps_epu32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtps_epu32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtps_epu32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi8_epi32() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi8_epi32(a); + let e = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi8_epi32() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi32(-1); + let r = _mm512_mask_cvtepi8_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepi8_epi32(src, 0b00000000_11111111, a); + let e = _mm512_set_epi32(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi8_epi32() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi8_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepi8_epi32(0b00000000_11111111, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepu8_epi32() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu8_epi32(a); + let e = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepu8_epi32() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi32(-1); + let r = _mm512_mask_cvtepu8_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepu8_epi32(src, 0b00000000_11111111, a); + let e = _mm512_set_epi32(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepu8_epi32() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepu8_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepu8_epi32(0b00000000_11111111, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi16_epi32() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi16_epi32(a); + let e = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi16_epi32() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi32(-1); + let r = _mm512_mask_cvtepi16_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepi16_epi32(src, 0b00000000_11111111, a); + let e = _mm512_set_epi32(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi16_epi32() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi16_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepi16_epi32(0b00000000_11111111, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepu16_epi32() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu16_epi32(a); + let e = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepu16_epi32() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi32(-1); + let r = _mm512_mask_cvtepu16_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepu16_epi32(src, 0b00000000_11111111, a); + let e = _mm512_set_epi32(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepu16_epi32() { + let a = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepu16_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepu16_epi32(0b00000000_11111111, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi32_ps() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi32_ps(a); + let e = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi32_ps() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_ps(-1.); + let r = _mm512_mask_cvtepi32_ps(src, 0, a); + assert_eq_m512(r, src); + let r = _mm512_mask_cvtepi32_ps(src, 0b00000000_11111111, a); + let e = _mm512_set_ps( + -1., -1., -1., -1., -1., -1., -1., -1., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi32_ps() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi32_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_cvtepi32_ps(0b00000000_11111111, a); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepu32_ps() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu32_ps(a); + let e = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepu32_ps() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_ps(-1.); + let r = _mm512_mask_cvtepu32_ps(src, 0, a); + assert_eq_m512(r, src); + let r = _mm512_mask_cvtepu32_ps(src, 0b00000000_11111111, a); + let e = _mm512_set_ps( + -1., -1., -1., -1., -1., -1., -1., -1., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepu32_ps() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepu32_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_cvtepu32_ps(0b00000000_11111111, a); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi32_epi16() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi32_epi16(a); + let e = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi32_epi16() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm256_set1_epi16(-1); + let r = _mm512_mask_cvtepi32_epi16(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtepi32_epi16(src, 0b00000000_11111111, a); + let e = _mm256_set_epi16(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi32_epi16() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi32_epi16(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtepi32_epi16(0b00000000_11111111, a); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi32_epi8() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi32_epi8(a); + let e = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi32_epi8() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm_set1_epi8(-1); + let r = _mm512_mask_cvtepi32_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtepi32_epi8(src, 0b00000000_11111111, a); + let e = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi32_epi8() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi32_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtepi32_epi8(0b00000000_11111111, a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtsepi32_epi16() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MAX, + ); + let r = _mm512_cvtsepi32_epi16(a); + let e = _mm256_set_epi16( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i16::MIN, + i16::MAX, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtsepi32_epi16() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MAX, + ); + let src = _mm256_set1_epi16(-1); + let r = _mm512_mask_cvtsepi32_epi16(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtsepi32_epi16(src, 0b00000000_11111111, a); + let e = _mm256_set_epi16( + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 8, + 9, + 10, + 11, + 12, + 13, + i16::MIN, + i16::MAX, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtsepi32_epi16() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MAX, + ); + let r = _mm512_maskz_cvtsepi32_epi16(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtsepi32_epi16(0b00000000_11111111, a); + let e = _mm256_set_epi16( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 9, + 10, + 11, + 12, + 13, + i16::MIN, + i16::MAX, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtsepi32_epi8() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MAX, + ); + let r = _mm512_cvtsepi32_epi8(a); + let e = _mm_set_epi8( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i8::MIN, + i8::MAX, + ); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtsepi32_epi8() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MAX, + ); + let src = _mm_set1_epi8(-1); + let r = _mm512_mask_cvtsepi32_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtsepi32_epi8(src, 0b00000000_11111111, a); + let e = _mm_set_epi8( + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 8, + 9, + 10, + 11, + 12, + 13, + i8::MIN, + i8::MAX, + ); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtsepi32_epi8() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MAX, + ); + let r = _mm512_maskz_cvtsepi32_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtsepi32_epi8(0b00000000_11111111, a); + let e = _mm_set_epi8( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 9, + 10, + 11, + 12, + 13, + i8::MIN, + i8::MAX, + ); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtusepi32_epi16() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MIN, + ); + let r = _mm512_cvtusepi32_epi16(a); + let e = _mm256_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtusepi32_epi16() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MIN, + ); + let src = _mm256_set1_epi16(-1); + let r = _mm512_mask_cvtusepi32_epi16(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtusepi32_epi16(src, 0b00000000_11111111, a); + let e = _mm256_set_epi16(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtusepi32_epi16() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MIN, + ); + let r = _mm512_maskz_cvtusepi32_epi16(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtusepi32_epi16(0b00000000_11111111, a); + let e = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtusepi32_epi8() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MIN, + ); + let r = _mm512_cvtusepi32_epi8(a); + let e = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtusepi32_epi8() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MIN, + ); + let src = _mm_set1_epi8(-1); + let r = _mm512_mask_cvtusepi32_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtusepi32_epi8(src, 0b00000000_11111111, a); + let e = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtusepi32_epi8() { + let a = _mm512_set_epi32( + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + i32::MIN, + i32::MIN, + ); + let r = _mm512_maskz_cvtusepi32_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtusepi32_epi8(0b00000000_11111111, a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = + _mm512_mask_cvt_roundps_epi32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvt_roundps_epi32( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvt_roundps_epi32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvt_roundps_epi32( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = + _mm512_mask_cvt_roundps_epu32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvt_roundps_epu32( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvt_roundps_epu32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvt_roundps_epu32( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundepi32_ps() { + let a = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + let r = _mm512_cvt_roundepi32_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., -2., 2., -4., 4., -6., 6., -8., 8., 10., 10., 12., 12., 14., 14., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundepi32_ps() { + let a = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + let src = _mm512_set1_ps(0.); + let r = + _mm512_mask_cvt_roundepi32_ps(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, src); + let r = _mm512_mask_cvt_roundepi32_ps( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., -2., 2., -4., 4., -6., 6., -8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundepi32_ps() { + let a = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + let r = _mm512_maskz_cvt_roundepi32_ps(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_cvt_roundepi32_ps( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., -2., 2., -4., 4., -6., 6., -8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundepu32_ps() { + let a = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + let r = _mm512_cvt_roundepu32_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., + 4294967300., + 2., + 4294967300., + 4., + 4294967300., + 6., + 4294967300., + 8., + 10., + 10., + 12., + 12., + 14., + 14., + 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundepu32_ps() { + let a = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + let src = _mm512_set1_ps(0.); + let r = + _mm512_mask_cvt_roundepu32_ps(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, src); + let r = _mm512_mask_cvt_roundepu32_ps( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 4294967300., + 2., + 4294967300., + 4., + 4294967300., + 6., + 4294967300., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundepu32_ps() { + let a = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + let r = _mm512_maskz_cvt_roundepu32_ps(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_cvt_roundepu32_ps( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 4294967300., + 2., + 4294967300., + 4., + 4294967300., + 6., + 4294967300., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_ph() { + let a = _mm512_set1_ps(1.); + let r = _mm512_cvt_roundps_ph(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_ph() { + let a = _mm512_set1_ps(1.); + let src = _mm256_set1_epi16(0); + let r = _mm512_mask_cvt_roundps_ph(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvt_roundps_ph(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi64x(4323521613979991040, 4323521613979991040, 0, 0); + assert_eq_m256i(r, e); + } - #[link_name = "llvm.x86.avx512.mask.pmaxs.d.512"] - fn vpmaxsd(a: i32x16, b: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.pmaxs.q.512"] - fn vpmaxsq(a: i64x8, b: i64x8) -> i64x8; - #[link_name = "llvm.x86.avx512.mask.pmins.d.512"] - fn vpminsd(a: i32x16, b: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.pmins.q.512"] - fn vpminsq(a: i64x8, b: i64x8) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_ph() { + let a = _mm512_set1_ps(1.); + let r = _mm512_maskz_cvt_roundps_ph(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvt_roundps_ph(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi64x(4323521613979991040, 4323521613979991040, 0, 0); + assert_eq_m256i(r, e); + } - #[link_name = "llvm.x86.avx512.mask.pmaxu.d.512"] - fn vpmaxud(a: u32x16, b: u32x16) -> u32x16; - #[link_name = "llvm.x86.avx512.mask.pmaxu.q.512"] - fn vpmaxuq(a: u64x8, b: u64x8) -> i64x8; - #[link_name = "llvm.x86.avx512.mask.pminu.d.512"] - fn vpminud(a: u32x16, b: u32x16) -> u32x16; - #[link_name = "llvm.x86.avx512.mask.pminu.q.512"] - fn vpminuq(a: u64x8, b: u64x8) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_ph() { + let a = _mm512_set1_ps(1.); + let r = _mm512_cvtps_ph(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + assert_eq_m256i(r, e); + } - #[link_name = "llvm.x86.avx512.sqrt.ps.512"] - fn vsqrtps(a: f32x16, rounding: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.sqrt.pd.512"] - fn vsqrtpd(a: f64x8, rounding: i32) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_ph() { + let a = _mm512_set1_ps(1.); + let src = _mm256_set1_epi16(0); + let r = _mm512_mask_cvtps_ph(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtps_ph(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi64x(4323521613979991040, 4323521613979991040, 0, 0); + assert_eq_m256i(r, e); + } - #[link_name = "llvm.x86.avx512.vfmadd.ps.512"] - fn vfmadd132ps(a: f32x16, b: f32x16, c: f32x16, rounding: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.vfmadd.pd.512"] - fn vfmadd132pd(a: f64x8, b: f64x8, c: f64x8, rounding: i32) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_ph() { + let a = _mm512_set1_ps(1.); + let r = _mm512_maskz_cvtps_ph(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtps_ph(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi64x(4323521613979991040, 4323521613979991040, 0, 0); + assert_eq_m256i(r, e); + } - #[link_name = "llvm.x86.avx512.vfmaddsub.ps.512"] - fn vfmaddsub213ps(a: f32x16, b: f32x16, c: f32x16, d: i32) -> f32x16; //from clang - #[link_name = "llvm.x86.avx512.vfmaddsub.pd.512"] - fn vfmaddsub213pd(a: f64x8, b: f64x8, c: f64x8, d: i32) -> f64x8; //from clang + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundph_ps() { + let a = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + let r = _mm512_cvt_roundph_ps(a, _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } - #[link_name = "llvm.x86.avx512.add.ps.512"] - fn vaddps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.add.pd.512"] - fn vaddpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.sub.ps.512"] - fn vsubps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.sub.pd.512"] - fn vsubpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.mul.ps.512"] - fn vmulps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.mul.pd.512"] - fn vmulpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.div.ps.512"] - fn vdivps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.div.pd.512"] - fn vdivpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundph_ps() { + let a = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + let src = _mm512_set1_ps(0.); + let r = _mm512_mask_cvt_roundph_ps(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m512(r, src); + let r = _mm512_mask_cvt_roundph_ps(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } - #[link_name = "llvm.x86.avx512.max.ps.512"] - fn vmaxps(a: f32x16, b: f32x16, sae: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.max.pd.512"] - fn vmaxpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.min.ps.512"] - fn vminps(a: f32x16, b: f32x16, sae: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.min.pd.512"] - fn vminpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundph_ps() { + let a = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + let r = _mm512_maskz_cvt_roundph_ps(0, a, _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_cvt_roundph_ps(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } - #[link_name = "llvm.x86.avx512.mask.getexp.ps.512"] - fn vgetexpps(a: f32x16, src: f32x16, m: u16, sae: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.mask.getexp.pd.512"] - fn vgetexppd(a: f64x8, src: f64x8, m: u8, sae: i32) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtph_ps() { + let a = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + let r = _mm512_cvtph_ps(a); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } - #[link_name = "llvm.x86.avx512.mask.getmant.ps.512"] - fn vgetmantps(a: f32x16, mantissas: i32, src: f32x16, m: u16, sae: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.mask.getmant.pd.512"] - fn vgetmantpd(a: f64x8, mantissas: i32, src: f64x8, m: u8, sae: i32) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtph_ps() { + let a = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + let src = _mm512_set1_ps(0.); + let r = _mm512_mask_cvtph_ps(src, 0, a); + assert_eq_m512(r, src); + let r = _mm512_mask_cvtph_ps(src, 0b00000000_11111111, a); + let e = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } - #[link_name = "llvm.x86.avx512.rcp14.ps.512"] - fn vrcp14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; - #[link_name = "llvm.x86.avx512.rcp14.pd.512"] - fn vrcp14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; - #[link_name = "llvm.x86.avx512.rsqrt14.ps.512"] - fn vrsqrt14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; - #[link_name = "llvm.x86.avx512.rsqrt14.pd.512"] - fn vrsqrt14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtph_ps() { + let a = _mm256_setr_epi64x( + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + 4323521613979991040, + ); + let r = _mm512_maskz_cvtph_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_cvtph_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } - #[link_name = "llvm.x86.avx512.mask.cvtps2dq.512"] - fn vcvtps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.cvtps2udq.512"] - fn vcvtps2udq(a: f32x16, src: u32x16, mask: u16, rounding: i32) -> u32x16; - #[link_name = "llvm.x86.avx512.mask.cvtps2pd.512"] - fn vcvtps2pd(a: f32x8, src: f64x8, mask: u8, sae: i32) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtt_roundps_epi32(a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } - #[link_name = "llvm.x86.avx512.mask.cvttps2dq.512"] - fn vcvttps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.cvttps2udq.512"] - fn vcvttps2udq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> u32x16; - #[link_name = "llvm.x86.avx512.mask.cvttpd2dq.512"] - fn vcvttpd2dq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> i32x8; - #[link_name = "llvm.x86.avx512.mask.cvttpd2udq.512"] - fn vcvttpd2udq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> u32x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtt_roundps_epi32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtt_roundps_epi32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtt_roundps_epi32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtt_roundps_epi32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtt_roundps_epu32(a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtt_roundps_epu32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtt_roundps_epu32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtt_roundps_epu32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtt_roundps_epu32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvttps_epi32(a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvttps_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvttps_epi32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvttps_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvttps_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvttps_epu32(a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } - #[link_name = "llvm.x86.avx512.gather.dpd.512"] - fn vgatherdpd(src: f64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.gather.dps.512"] - fn vgatherdps(src: f32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> f32x16; - #[link_name = "llvm.x86.avx512.gather.qpd.512"] - fn vgatherqpd(src: f64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f64x8; - #[link_name = "llvm.x86.avx512.gather.qps.512"] - fn vgatherqps(src: f32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> f32x8; - #[link_name = "llvm.x86.avx512.gather.dpq.512"] - fn vpgatherdq(src: i64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> i64x8; - #[link_name = "llvm.x86.avx512.gather.dpi.512"] - fn vpgatherdd(src: i32x16, slice: *const i8, offsets: i32x16, mask: i16, scale: i32) -> i32x16; - #[link_name = "llvm.x86.avx512.gather.qpq.512"] - fn vpgatherqq(src: i64x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i64x8; - #[link_name = "llvm.x86.avx512.gather.qpi.512"] - fn vpgatherqd(src: i32x8, slice: *const i8, offsets: i64x8, mask: i8, scale: i32) -> i32x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvttps_epu32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvttps_epu32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } - #[link_name = "llvm.x86.avx512.scatter.dpd.512"] - fn vscatterdpd(slice: *mut i8, mask: i8, offsets: i32x8, src: f64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.dps.512"] - fn vscatterdps(slice: *mut i8, mask: i16, offsets: i32x16, src: f32x16, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qpd.512"] - fn vscatterqpd(slice: *mut i8, mask: i8, offsets: i64x8, src: f64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qps.512"] - fn vscatterqps(slice: *mut i8, mask: i8, offsets: i64x8, src: f32x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.dpq.512"] - fn vpscatterdq(slice: *mut i8, mask: i8, offsets: i32x8, src: i64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.dpi.512"] - fn vpscatterdd(slice: *mut i8, mask: i16, offsets: i32x16, src: i32x16, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qpq.512"] - fn vpscatterqq(slice: *mut i8, mask: i8, offsets: i64x8, src: i64x8, scale: i32); - #[link_name = "llvm.x86.avx512.scatter.qpi.512"] - fn vpscatterqd(slice: *mut i8, mask: i8, offsets: i64x8, src: i32x8, scale: i32); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvttps_epu32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvttps_epu32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } - #[link_name = "llvm.x86.avx512.mask.cmp.ss"] - fn vcmpss(a: __m128, b: __m128, op: i32, m: i8, sae: i32) -> i8; - #[link_name = "llvm.x86.avx512.mask.cmp.sd"] - fn vcmpsd(a: __m128d, b: __m128d, op: i32, m: i8, sae: i32) -> i8; - #[link_name = "llvm.x86.avx512.mask.cmp.ps.512"] - fn vcmpps(a: f32x16, b: f32x16, op: i32, m: i16, sae: i32) -> i16; - #[link_name = "llvm.x86.avx512.mask.cmp.pd.512"] - fn vcmppd(a: f64x8, b: f64x8, op: i32, m: i8, sae: i32) -> i8; - #[link_name = "llvm.x86.avx512.mask.ucmp.q.512"] - fn vpcmpuq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; - #[link_name = "llvm.x86.avx512.mask.cmp.q.512"] - fn vpcmpq(a: i64x8, b: i64x8, op: i32, m: i8) -> i8; - #[link_name = "llvm.x86.avx512.mask.ucmp.d.512"] - fn vpcmpud(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; - #[link_name = "llvm.x86.avx512.mask.cmp.d.512"] - fn vpcmpd(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32gather_ps() { + let mut arr = [0f32; 256]; + for i in 0..256 { + arr[i] = i as f32; + } + // A multiplier of 4 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176); + let r = _mm512_i32gather_ps(index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512(r, _mm512_setr_ps(0., 16., 32., 48., 64., 80., 96., 112., + 120., 128., 136., 144., 152., 160., 168., 176.)); + } - #[link_name = "llvm.x86.avx512.mask.prol.d.512"] - fn vprold(a: i32x16, i8: i32) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.pror.d.512"] - fn vprord(a: i32x16, i8: i32) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.prol.q.512"] - fn vprolq(a: i64x8, i8: i32) -> i64x8; - #[link_name = "llvm.x86.avx512.mask.pror.q.512"] - fn vprorq(a: i64x8, i8: i32) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32gather_ps() { + let mut arr = [0f32; 256]; + for i in 0..256 { + arr[i] = i as f32; + } + let src = _mm512_set1_ps(2.); + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176); + // A multiplier of 4 is word-addressing + let r = _mm512_mask_i32gather_ps(src, mask, index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512(r, _mm512_setr_ps(2., 16., 2., 48., 2., 80., 2., 112., + 2., 128., 2., 144., 2., 160., 2., 176.)); + } - #[link_name = "llvm.x86.avx512.mask.prolv.d.512"] - fn vprolvd(a: i32x16, b: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.prorv.d.512"] - fn vprorvd(a: i32x16, b: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.mask.prolv.q.512"] - fn vprolvq(a: i64x8, b: i64x8) -> i64x8; - #[link_name = "llvm.x86.avx512.mask.prorv.q.512"] - fn vprorvq(a: i64x8, b: i64x8) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32gather_epi32() { + let mut arr = [0i32; 256]; + for i in 0..256 { + arr[i] = i as i32; + } + // A multiplier of 4 is word-addressing + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176); + let r = _mm512_i32gather_epi32(index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512i(r, _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 120, 128, 136, 144, 152, 160, 168, 176)); + } - #[link_name = "llvm.x86.avx512.psllv.d.512"] - fn vpsllvd(a: i32x16, b: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.psrlv.d.512"] - fn vpsrlvd(a: i32x16, b: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.psllv.q.512"] - fn vpsllvq(a: i64x8, b: i64x8) -> i64x8; - #[link_name = "llvm.x86.avx512.psrlv.q.512"] - fn vpsrlvq(a: i64x8, b: i64x8) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32gather_epi32() { + let mut arr = [0i32; 256]; + for i in 0..256 { + arr[i] = i as i32; + } + let src = _mm512_set1_epi32(2); + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + // A multiplier of 4 is word-addressing + let r = _mm512_mask_i32gather_epi32(src, mask, index, arr.as_ptr() as *const u8, 4); + #[rustfmt::skip] + assert_eq_m512i(r, _mm512_setr_epi32(2, 16, 2, 48, 2, 80, 2, 112, + 2, 144, 2, 176, 2, 208, 2, 240)); + } - #[link_name = "llvm.x86.avx512.pslli.d.512"] - fn vpsllid(a: i32x16, imm8: u32) -> i32x16; - #[link_name = "llvm.x86.avx512.psrli.d.512"] - fn vpsrlid(a: i32x16, imm8: u32) -> i32x16; - #[link_name = "llvm.x86.avx512.pslli.q.512"] - fn vpslliq(a: i64x8, imm8: u32) -> i64x8; - #[link_name = "llvm.x86.avx512.psrli.q.512"] - fn vpsrliq(a: i64x8, imm8: u32) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32scatter_ps() { + let mut arr = [0f32; 256]; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + // A multiplier of 4 is word-addressing + _mm512_i32scatter_ps(arr.as_mut_ptr() as *mut u8, index, src, 4); + let mut expected = [0f32; 256]; + for i in 0..16 { + expected[i * 16] = (i + 1) as f32; + } + assert_eq!(&arr[..], &expected[..],); + } - #[link_name = "llvm.x86.avx512.psll.d.512"] - fn vpslld(a: i32x16, count: i32x4) -> i32x16; - #[link_name = "llvm.x86.avx512.psrl.d.512"] - fn vpsrld(a: i32x16, count: i32x4) -> i32x16; - #[link_name = "llvm.x86.avx512.psll.q.512"] - fn vpsllq(a: i64x8, count: i64x2) -> i64x8; - #[link_name = "llvm.x86.avx512.psrl.q.512"] - fn vpsrlq(a: i64x8, count: i64x2) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32scatter_ps() { + let mut arr = [0f32; 256]; + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + // A multiplier of 4 is word-addressing + _mm512_mask_i32scatter_ps(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); + let mut expected = [0f32; 256]; + for i in 0..8 { + expected[i * 32 + 16] = 2. * (i + 1) as f32; + } + assert_eq!(&arr[..], &expected[..],); + } - #[link_name = "llvm.x86.avx512.psra.d.512"] - fn vpsrad(a: i32x16, count: i32x4) -> i32x16; - #[link_name = "llvm.x86.avx512.psra.q.512"] - fn vpsraq(a: i64x8, count: i64x2) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_i32scatter_epi32() { + let mut arr = [0i32; 256]; + #[rustfmt::skip] - #[link_name = "llvm.x86.avx512.psrai.d.512"] - fn vpsraid(a: i32x16, imm8: u32) -> i32x16; - #[link_name = "llvm.x86.avx512.psrai.q.512"] - fn vpsraiq(a: i64x8, imm8: u32) -> i64x8; + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + // A multiplier of 4 is word-addressing + _mm512_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, index, src, 4); + let mut expected = [0i32; 256]; + for i in 0..16 { + expected[i * 16] = (i + 1) as i32; + } + assert_eq!(&arr[..], &expected[..],); + } - #[link_name = "llvm.x86.avx512.psrav.d.512"] - fn vpsravd(a: i32x16, count: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.psrav.q.512"] - fn vpsravq(a: i64x8, count: i64x8) -> i64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_i32scatter_epi32() { + let mut arr = [0i32; 256]; + let mask = 0b10101010_10101010; + #[rustfmt::skip] + let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, + 128, 144, 160, 176, 192, 208, 224, 240); + let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + // A multiplier of 4 is word-addressing + _mm512_mask_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); + let mut expected = [0i32; 256]; + for i in 0..8 { + expected[i * 32 + 16] = 2 * (i + 1) as i32; + } + assert_eq!(&arr[..], &expected[..],); + } - #[link_name = "llvm.x86.avx512.vpermilvar.ps.512"] - fn vpermilps(a: f32x16, b: i32x16) -> f32x16; - #[link_name = "llvm.x86.avx512.vpermilvar.pd.512"] - fn vpermilpd(a: f64x8, b: i64x8) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmplt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmplt_ps_mask(a, b); + assert_eq!(m, 0b00000101_00000101); + } - #[link_name = "llvm.x86.avx512.permvar.si.512"] - fn vpermd(a: i32x16, idx: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.permvar.di.512"] - fn vpermq(a: i64x8, idx: i64x8) -> i64x8; - #[link_name = "llvm.x86.avx512.permvar.sf.512"] - fn vpermps(a: f32x16, idx: i32x16) -> f32x16; - #[link_name = "llvm.x86.avx512.permvar.df.512"] - fn vpermpd(a: f64x8, idx: i64x8) -> f64x8; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmplt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmplt_ps_mask(mask, a, b); + assert_eq!(r, 0b00000100_00000100); + } - #[link_name = "llvm.x86.avx512.vpermi2var.d.512"] - fn vpermi2d(a: i32x16, idx: i32x16, b: i32x16) -> i32x16; - #[link_name = "llvm.x86.avx512.vpermi2var.q.512"] - fn vpermi2q(a: i64x8, idx: i64x8, b: i64x8) -> i64x8; - #[link_name = "llvm.x86.avx512.vpermi2var.ps.512"] - fn vpermi2ps(a: f32x16, idx: i32x16, b: f32x16) -> f32x16; - #[link_name = "llvm.x86.avx512.vpermi2var.pd.512"] - fn vpermi2pd(a: f64x8, idx: i64x8, b: f64x8) -> f64x8; -} + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpnlt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + assert_eq!(_mm512_cmpnlt_ps_mask(a, b), !_mm512_cmplt_ps_mask(a, b)); + } -#[cfg(test)] -mod tests { - use std; - use stdarch_test::simd_test; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpnlt_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmpnlt_ps_mask(mask, a, b), 0b01111010_01111010); + } - use crate::core_arch::x86::*; - use crate::hint::black_box; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpnle_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmpnle_ps_mask(b, a); + assert_eq!(m, 0b00001101_00001101); + } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_abs_epi32() { + unsafe fn test_mm512_mask_cmpnle_ps_mask() { #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let r = _mm512_abs_epi32(a); - let e = _mm512_setr_epi32( - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - ); - assert_eq_m512i(r, e); + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmpnle_ps_mask(mask, b, a); + assert_eq!(r, 0b00000100_00000100); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_abs_epi32() { + unsafe fn test_mm512_cmple_ps_mask() { #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let r = _mm512_mask_abs_epi32(a, 0, a); - assert_eq_m512i(r, a); - let r = _mm512_mask_abs_epi32(a, 0b00000000_11111111, a); - let e = _mm512_setr_epi32( - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - assert_eq_m512i(r, e); + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + assert_eq!(_mm512_cmple_ps_mask(a, b), 0b00100101_00100101); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_abs_epi32() { + unsafe fn test_mm512_mask_cmple_ps_mask() { #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let r = _mm512_maskz_abs_epi32(0, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_abs_epi32(0b00000000_11111111, a); - let e = _mm512_setr_epi32( - 0, - 1, - 1, - i32::MAX, - i32::MAX.wrapping_add(1), - 100, - 100, - 32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - assert_eq_m512i(r, e); + let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., + 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmple_ps_mask(mask, a, b), 0b00100000_00100000); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_abs_ps() { + unsafe fn test_mm512_cmpeq_ps_mask() { #[rustfmt::skip] - let a = _mm512_setr_ps( - 0., 1., -1., f32::MAX, - f32::MIN, 100., -100., -32., - 0., 1., -1., f32::MAX, - f32::MIN, 100., -100., -32., - ); - let r = _mm512_abs_ps(a); - let e = _mm512_setr_ps( - 0., - 1., - 1., - f32::MAX, - f32::MAX, - 100., - 100., - 32., - 0., - 1., - 1., - f32::MAX, - f32::MAX, - 100., - 100., - 32., - ); - assert_eq_m512(r, e); + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let m = _mm512_cmpeq_ps_mask(b, a); + assert_eq!(m, 0b11001101_11001101); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_abs_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let r = _mm512_mask_abs_ps(a, 0, a); - assert_eq_m512(r, a); - let r = _mm512_mask_abs_ps(a, 0b00000000_11111111, a); - let e = _mm512_setr_ps( - 0., - 1., - 1., - f32::MAX, - f32::MAX, - 100., - 100., - 32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_cmpeq_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpeq_ps_mask(mask, b, a); + assert_eq!(r, 0b01001000_01001000); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_add_epi32() { - let a = _mm512_setr_epi32( - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_add_epi32(a, b); - let e = _mm512_setr_epi32( - 1, - 2, - 0, - i32::MIN, - i32::MIN + 1, - 101, - -99, - -31, - 1, - 2, - 0, - i32::MIN, - i32::MIN + 1, - 101, - -99, - -31, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm512_cmpneq_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let m = _mm512_cmpneq_ps_mask(b, a); + assert_eq!(m, 0b00110010_00110010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_add_epi32() { + unsafe fn test_mm512_mask_cmpneq_ps_mask() { #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_mask_add_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_add_epi32(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_epi32( - 1, - 2, - 0, - i32::MIN, - i32::MIN + 1, - 101, - -99, - -31, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - assert_eq_m512i(r, e); + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); + #[rustfmt::skip] + let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., + 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpneq_ps_mask(mask, b, a); + assert_eq!(r, 0b00110010_00110010) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_add_epi32() { + unsafe fn test_mm512_cmp_ps_mask() { #[rustfmt::skip] - let a = _mm512_setr_epi32( - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - 0, 1, -1, i32::MAX, - i32::MIN, 100, -100, -32, - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_maskz_add_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_add_epi32(0b00000000_11111111, a, b); - let e = _mm512_setr_epi32( - 1, - 2, - 0, - i32::MIN, - i32::MIN + 1, - 101, - -99, - -31, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - assert_eq_m512i(r, e); + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmp_ps_mask(a, b, _CMP_LT_OQ); + assert_eq!(m, 0b00000101_00000101); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_add_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_add_ps(a, b); - let e = _mm512_setr_ps( - 1., - 2., - 0., - f32::MAX, - f32::MIN + 1., - 101., - -99., - -31., - 1., - 2., - 0., - f32::MAX, - f32::MIN + 1., - 101., - -99., - -31., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_cmp_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmp_ps_mask(mask, a, b, _CMP_LT_OQ); + assert_eq!(r, 0b00000100_00000100); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_add_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_mask_add_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_add_ps(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 1., - 2., - 0., - f32::MAX, - f32::MIN + 1., - 101., - -99., - -31., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_cmp_round_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let m = _mm512_cmp_round_ps_mask(a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmp_round_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., + 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); + let b = _mm512_set1_ps(-1.); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmp_round_ps_mask(mask, a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); + assert_eq!(r, 0b00000100_00000100); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let m = _mm512_cmpord_ps_mask(a, b); + assert_eq!(m, 0b00000101_00000101); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let mask = 0b11000011_11000011; + let m = _mm512_mask_cmpord_ps_mask(mask, a, b); + assert_eq!(m, 0b00000001_00000001); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_add_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_maskz_add_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_add_ps(0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 1., - 2., - 0., - f32::MAX, - f32::MIN + 1., - 101., - -99., - -31., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_cmpunord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let m = _mm512_cmpunord_ps_mask(a, b); + + assert_eq!(m, 0b11111010_11111010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sub_epi32() { - let a = _mm512_setr_epi32( - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_sub_epi32(a, b); - let e = _mm512_setr_epi32( - -1, - 0, - -2, - i32::MAX - 1, - i32::MAX, - 99, - -101, - -33, - -1, - 0, - -2, - i32::MAX - 1, - i32::MAX, - 99, - -101, - -33, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmpunord_ps_mask() { + #[rustfmt::skip] + let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., + f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); + #[rustfmt::skip] + let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., + f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); + let mask = 0b00001111_00001111; + let m = _mm512_mask_cmpunord_ps_mask(mask, a, b); + assert_eq!(m, 0b000001010_00001010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sub_epi32() { - let a = _mm512_setr_epi32( - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_mask_sub_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_sub_epi32(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_epi32( - -1, - 0, - -2, - i32::MAX - 1, - i32::MAX, - 99, - -101, - -33, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_cmp_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_cmp_ss_mask(a, b, _CMP_GE_OS); + assert_eq!(m, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sub_epi32() { - let a = _mm512_setr_epi32( - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_maskz_sub_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_sub_epi32(0b00000000_11111111, a, b); - let e = _mm512_setr_epi32( - -1, - 0, - -2, - i32::MAX - 1, - i32::MAX, - 99, - -101, - -33, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_cmp_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_mask_cmp_ss_mask(0b10, a, b, _CMP_GE_OS); + assert_eq!(m, 0); + let m = _mm_mask_cmp_ss_mask(0b1, a, b, _CMP_GE_OS); + assert_eq!(m, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sub_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_sub_ps(a, b); - let e = _mm512_setr_ps( - -1., - 0., - -2., - f32::MAX - 1., - f32::MIN, - 99., - -101., - -33., - -1., - 0., - -2., - f32::MAX - 1., - f32::MIN, - 99., - -101., - -33., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_cmp_round_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_cmp_round_ss_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cmp_round_ss_mask() { + let a = _mm_setr_ps(2., 1., 1., 1.); + let b = _mm_setr_ps(1., 2., 2., 2.); + let m = _mm_mask_cmp_round_ss_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 0); + let m = _mm_mask_cmp_round_ss_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sub_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_mask_sub_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_sub_ps(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - -1., - 0., - -2., - f32::MAX - 1., - f32::MIN, - 99., - -101., - -33., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_cmp_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_cmp_sd_mask(a, b, _CMP_GE_OS); + assert_eq!(m, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sub_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_maskz_sub_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_sub_ps(0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - -1., - 0., - -2., - f32::MAX - 1., - f32::MIN, - 99., - -101., - -33., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_cmp_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_mask_cmp_sd_mask(0b10, a, b, _CMP_GE_OS); + assert_eq!(m, 0); + let m = _mm_mask_cmp_sd_mask(0b1, a, b, _CMP_GE_OS); + assert_eq!(m, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mullo_epi32() { - let a = _mm512_setr_epi32( - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - let b = _mm512_set1_epi32(2); - let r = _mm512_mullo_epi32(a, b); - let e = _mm512_setr_epi32( - 0, 2, -2, -2, 0, 200, -200, -64, 0, 2, -2, -2, 0, 200, -200, -64, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_cmp_round_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_cmp_round_sd_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_mullo_epi32() { - let a = _mm512_setr_epi32( - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - let b = _mm512_set1_epi32(2); - let r = _mm512_mask_mullo_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_mullo_epi32(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_epi32( - 0, - 2, - -2, - -2, - 0, - 200, - -200, - -64, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_cmp_round_sd_mask() { + let a = _mm_setr_pd(2., 1.); + let b = _mm_setr_pd(1., 2.); + let m = _mm_mask_cmp_round_sd_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 0); + let m = _mm_mask_cmp_round_sd_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); + assert_eq!(m, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_mullo_epi32() { - let a = _mm512_setr_epi32( - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - 0, - 1, - -1, - i32::MAX, - i32::MIN, - 100, - -100, - -32, - ); - let b = _mm512_set1_epi32(2); - let r = _mm512_maskz_mullo_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_mullo_epi32(0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(0, 2, -2, -2, 0, 200, -200, -64, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_cmplt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmplt_epu32_mask(a, b); + assert_eq!(m, 0b11001111_11001111); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mul_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(2.); - let r = _mm512_mul_ps(a, b); - let e = _mm512_setr_ps( - 0., - 2., - -2., - f32::INFINITY, - f32::NEG_INFINITY, - 200., - -200., - -64., - 0., - 2., - -2., - f32::INFINITY, - f32::NEG_INFINITY, - 200., - -200., - -64., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_cmplt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmplt_epu32_mask(mask, a, b); + assert_eq!(r, 0b01001010_01001010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_mul_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(2.); - let r = _mm512_mask_mul_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_mul_ps(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 0., - 2., - -2., - f32::INFINITY, - f32::NEG_INFINITY, - 200., - -200., - -64., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_cmpgt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmpgt_epu32_mask(b, a); + assert_eq!(m, 0b11001111_11001111); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_mul_ps() { - let a = _mm512_setr_ps( - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - 0., - 1., - -1., - f32::MAX, - f32::MIN, - 100., - -100., - -32., - ); - let b = _mm512_set1_ps(2.); - let r = _mm512_maskz_mul_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_mul_ps(0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 0., - 2., - -2., - f32::INFINITY, - f32::NEG_INFINITY, - 200., - -200., - -64., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_cmpgt_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpgt_epu32_mask(mask, b, a); + assert_eq!(r, 0b01001010_01001010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_div_ps() { - let a = _mm512_setr_ps( - 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., - ); - let b = _mm512_setr_ps( - 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., - ); - let r = _mm512_div_ps(a, b); - let e = _mm512_setr_ps( - 0., - 0.5, - -0.5, - -1., - 50., - f32::INFINITY, - -50., - -16., - 0., - 0.5, - -0.5, - 500., - f32::NEG_INFINITY, - 50., - -50., - -16., - ); - assert_eq_m512(r, e); // 0/0 = NAN + unsafe fn test_mm512_cmple_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmple_epu32_mask(a, b), + !_mm512_cmpgt_epu32_mask(a, b) + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_div_ps() { - let a = _mm512_setr_ps( - 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., - ); - let b = _mm512_setr_ps( - 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., - ); - let r = _mm512_mask_div_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_div_ps(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 0., - 0.5, - -0.5, - -1., - 50., - f32::INFINITY, - -50., - -16., - 0., - 1., - -1., - 1000., - -131., - 100., - -100., - -32., + unsafe fn test_mm512_mask_cmple_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!( + _mm512_mask_cmple_epu32_mask(mask, a, b), + 0b01111010_01111010 ); - assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_div_ps() { - let a = _mm512_setr_ps( - 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., - ); - let b = _mm512_setr_ps( - 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., - ); - let r = _mm512_maskz_div_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_div_ps(0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 0., - 0.5, - -0.5, - -1., - 50., - f32::INFINITY, - -50., - -16., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_cmpge_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmpge_epu32_mask(a, b), + !_mm512_cmplt_epu32_mask(a, b) + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_max_epi32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_max_epi32(a, b); - let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmpge_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmpge_epu32_mask(mask, a, b), 0b01100000_0110000); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpeq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpeq_epu32_mask(b, a); + assert_eq!(m, 0b11001111_11001111); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cmpeq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpeq_epu32_mask(mask, b, a); + assert_eq!(r, 0b01001010_01001010); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cmpneq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpneq_epu32_mask(b, a); + assert_eq!(m, !_mm512_cmpeq_epu32_mask(b, a)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_max_epi32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_mask_max_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_max_epi32(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmpneq_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpneq_epu32_mask(mask, b, a); + assert_eq!(r, 0b00110010_00110010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_max_epi32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_maskz_max_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_max_epi32(0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_cmp_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmp_epu32_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b11001111_11001111); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_max_ps() { - let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ); - let r = _mm512_max_ps(a, b); - let e = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_cmp_epu32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b01001010_01001010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_max_ps() { - let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ); - let r = _mm512_mask_max_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_max_ps(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_cmplt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmplt_epi32_mask(a, b); + assert_eq!(m, 0b00000101_00000101); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_max_ps() { - let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ); - let r = _mm512_maskz_max_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_max_ps(0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_cmplt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmplt_epi32_mask(mask, a, b); + assert_eq!(r, 0b00000100_00000100); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_max_epu32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_max_epu32(a, b); - let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + unsafe fn test_mm512_cmpgt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmpgt_epi32_mask(b, a); + assert_eq!(m, 0b00000101_00000101); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_max_epu32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_mask_max_epu32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_max_epu32(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmpgt_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmpgt_epi32_mask(mask, b, a); + assert_eq!(r, 0b00000100_00000100); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_max_epu32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_maskz_max_epu32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_max_epu32(0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_cmple_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmple_epi32_mask(a, b), + !_mm512_cmpgt_epi32_mask(a, b) + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_min_epi32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_min_epi32(a, b); - let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmple_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!(_mm512_mask_cmple_epi32_mask(mask, a, b), 0b01100000_0110000); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_min_epi32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_mask_min_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_min_epi32(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + unsafe fn test_mm512_cmpge_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + assert_eq!( + _mm512_cmpge_epi32_mask(a, b), + !_mm512_cmplt_epi32_mask(a, b) + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_min_epi32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_maskz_min_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_min_epi32(0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmpge_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01111010_01111010; + assert_eq!( + _mm512_mask_cmpge_epi32_mask(mask, a, b), + 0b01111010_01111010 + ); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_min_ps() { - let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ); - let r = _mm512_min_ps(a, b); - let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_cmpeq_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpeq_epi32_mask(b, a); + assert_eq!(m, 0b11001111_11001111); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_min_ps() { - let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ); - let r = _mm512_mask_min_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_min_ps(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_cmpeq_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpeq_epi32_mask(mask, b, a); + assert_eq!(r, 0b01001010_01001010); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_min_ps() { - let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ); - let r = _mm512_maskz_min_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_min_ps(0b00000000_11111111, a, b); - let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_cmpneq_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let m = _mm512_cmpneq_epi32_mask(b, a); + assert_eq!(m, !_mm512_cmpeq_epi32_mask(b, a)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_min_epu32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_min_epu32(a, b); - let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmpneq_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100, + 0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100); + #[rustfmt::skip] + let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, + 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); + let mask = 0b01111010_01111010; + let r = _mm512_mask_cmpneq_epi32_mask(mask, b, a); + assert_eq!(r, 0b00110010_00110010) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_min_epu32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_mask_min_epu32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_min_epu32(a, 0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + unsafe fn test_mm512_cmp_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let m = _mm512_cmp_epi32_mask(a, b, _MM_CMPINT_LT); + assert_eq!(m, 0b00000101_00000101); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_min_epu32() { - let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - let r = _mm512_maskz_min_epu32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_min_epu32(0b00000000_11111111, a, b); - let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_cmp_epi32_mask() { + #[rustfmt::skip] + let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, + 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); + let b = _mm512_set1_epi32(-1); + let mask = 0b01100110_01100110; + let r = _mm512_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); + assert_eq!(r, 0b00000100_00000100); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sqrt_ps() { - let a = _mm512_setr_ps( - 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., - ); - let r = _mm512_sqrt_ps(a); - let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_set_epi8() { + let r = _mm512_set1_epi8(2); + assert_eq_m512i( + r, + _mm512_set_epi8( + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + ), + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sqrt_ps() { - let a = _mm512_setr_ps( - 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., - ); - let r = _mm512_mask_sqrt_ps(a, 0, a); - assert_eq_m512(r, a); - let r = _mm512_mask_sqrt_ps(a, 0b00000000_11111111, a); - let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 64., 81., 100., 121., 144., 169., 196., 225., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_set_epi16() { + let r = _mm512_set1_epi16(2); + assert_eq_m512i( + r, + _mm512_set_epi16( + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, + ), + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sqrt_ps() { - let a = _mm512_setr_ps( - 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., - ); - let r = _mm512_maskz_sqrt_ps(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_sqrt_ps(0b00000000_11111111, a); - let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_set_epi32() { + let r = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i( + r, + _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_fmadd_ps(a, b, c); - let e = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_setr_epi32() { + let r = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i( + r, + _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_mask_fmadd_ps(a, 0, b, c); - assert_eq_m512(r, a); - let r = _mm512_mask_fmadd_ps(a, 0b00000000_11111111, b, c); - let e = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 1., 1., 1., 1., 1., 1., 1., 1., + unsafe fn test_mm512_set1_epi8() { + let r = _mm512_set_epi8( + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, _mm512_set1_epi8(2)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_maskz_fmadd_ps(0, a, b, c); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmadd_ps(0b00000000_11111111, a, b, c); - let e = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 0., 0., 0., 0., 0., 0., 0., 0., + unsafe fn test_mm512_set1_epi16() { + let r = _mm512_set_epi16( + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, _mm512_set1_epi16(2)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., - ); - let r = _mm512_mask3_fmadd_ps(a, b, c, 0); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmadd_ps(a, b, c, 0b00000000_11111111); - let e = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 2., 2., 2., 2., 2., 2., 2., 2., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_set1_epi32() { + let r = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, _mm512_set1_epi32(2)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_fmsub_ps(a, b, c); - let e = _mm512_setr_ps( - -1., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_setzero_si512() { + assert_eq_m512i(_mm512_set1_epi32(0), _mm512_setzero_si512()); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_mask_fmsub_ps(a, 0, b, c); - assert_eq_m512(r, a); - let r = _mm512_mask_fmsub_ps(a, 0b00000000_11111111, b, c); - let e = _mm512_setr_ps( - -1., 0., 1., 2., 3., 4., 5., 6., 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_setzero_epi32() { + assert_eq_m512i(_mm512_set1_epi32(0), _mm512_setzero_epi32()); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( + unsafe fn test_mm512_set_ps() { + let r = _mm512_setr_ps( 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_maskz_fmsub_ps(0, a, b, c); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmsub_ps(0b00000000_11111111, a, b, c); - let e = _mm512_setr_ps( - -1., 0., 1., 2., 3., 4., 5., 6., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + assert_eq_m512( + r, + _mm512_set_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ), + ) } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( + unsafe fn test_mm512_setr_ps() { + let r = _mm512_set_ps( 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., - ); - let r = _mm512_mask3_fmsub_ps(a, b, c, 0); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmsub_ps(a, b, c, 0b00000000_11111111); - let e = _mm512_setr_ps( - -1., 0., 1., 2., 3., 4., 5., 6., 2., 2., 2., 2., 2., 2., 2., 2., - ); - assert_eq_m512(r, e); + assert_eq_m512( + r, + _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ), + ) + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set1_ps() { + #[rustfmt::skip] + let expected = _mm512_set_ps(2., 2., 2., 2., 2., 2., 2., 2., + 2., 2., 2., 2., 2., 2., 2., 2.); + assert_eq_m512(expected, _mm512_set1_ps(2.)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmaddsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_fmaddsub_ps(a, b, c); - let e = _mm512_setr_ps( - -1., 2., 1., 4., 3., 6., 5., 8., 7., 10., 9., 12., 11., 14., 13., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_set4_epi32() { + let r = _mm512_set_epi32(4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1); + assert_eq_m512i(r, _mm512_set4_epi32(4, 3, 2, 1)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmaddsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_mask_fmaddsub_ps(a, 0, b, c); - assert_eq_m512(r, a); - let r = _mm512_mask_fmaddsub_ps(a, 0b00000000_11111111, b, c); - let e = _mm512_setr_ps( - -1., 2., 1., 4., 3., 6., 5., 8., 1., 1., 1., 1., 1., 1., 1., 1., + unsafe fn test_mm512_set4_ps() { + let r = _mm512_set_ps( + 4., 3., 2., 1., 4., 3., 2., 1., 4., 3., 2., 1., 4., 3., 2., 1., ); - assert_eq_m512(r, e); + assert_eq_m512(r, _mm512_set4_ps(4., 3., 2., 1.)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmaddsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_maskz_fmaddsub_ps(0, a, b, c); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmaddsub_ps(0b00000000_11111111, a, b, c); - let e = _mm512_setr_ps( - -1., 2., 1., 4., 3., 6., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_setr4_epi32() { + let r = _mm512_set_epi32(4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1); + assert_eq_m512i(r, _mm512_setr4_epi32(1, 2, 3, 4)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmaddsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., - ); - let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0b00000000_11111111); - let e = _mm512_setr_ps( - -1., 2., 1., 4., 3., 6., 5., 8., 2., 2., 2., 2., 2., 2., 2., 2., + unsafe fn test_mm512_setr4_ps() { + let r = _mm512_set_ps( + 4., 3., 2., 1., 4., 3., 2., 1., 4., 3., 2., 1., 4., 3., 2., 1., ); - assert_eq_m512(r, e); + assert_eq_m512(r, _mm512_setr4_ps(1., 2., 3., 4.)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmsubadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_fmsubadd_ps(a, b, c); - let e = _mm512_setr_ps( - 1., 0., 3., 2., 5., 4., 7., 6., 9., 8., 11., 10., 13., 12., 15., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_setzero_ps() { + assert_eq_m512(_mm512_setzero_ps(), _mm512_set1_ps(0.)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmsubadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_mask_fmsubadd_ps(a, 0, b, c); - assert_eq_m512(r, a); - let r = _mm512_mask_fmsubadd_ps(a, 0b00000000_11111111, b, c); - let e = _mm512_setr_ps( - 1., 0., 3., 2., 5., 4., 7., 6., 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_setzero() { + assert_eq_m512(_mm512_setzero(), _mm512_set1_ps(0.)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmsubadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_maskz_fmsubadd_ps(0, a, b, c); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmsubadd_ps(0b00000000_11111111, a, b, c); - let e = _mm512_setr_ps( - 1., 0., 3., 2., 5., 4., 7., 6., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_loadu_pd() { + let a = &[4., 3., 2., 5., 8., 9., 64., 50.]; + let p = a.as_ptr(); + let r = _mm512_loadu_pd(black_box(p)); + let e = _mm512_setr_pd(4., 3., 2., 5., 8., 9., 64., 50.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmsubadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., - ); - let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0b00000000_11111111); - let e = _mm512_setr_ps( - 1., 0., 3., 2., 5., 4., 7., 6., 2., 2., 2., 2., 2., 2., 2., 2., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_storeu_pd() { + let a = _mm512_set1_pd(9.); + let mut r = _mm512_undefined_pd(); + _mm512_storeu_pd(&mut r as *mut _ as *mut f64, a); + assert_eq_m512d(r, a); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fnmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_fnmadd_ps(a, b, c); + unsafe fn test_mm512_loadu_ps() { + let a = &[ + 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., + ]; + let p = a.as_ptr(); + let r = _mm512_loadu_ps(black_box(p)); let e = _mm512_setr_ps( - 1., 0., -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., + 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fnmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_mask_fnmadd_ps(a, 0, b, c); + unsafe fn test_mm512_storeu_ps() { + let a = _mm512_set1_ps(9.); + let mut r = _mm512_undefined_ps(); + _mm512_storeu_ps(&mut r as *mut _ as *mut f32, a); assert_eq_m512(r, a); - let r = _mm512_mask_fnmadd_ps(a, 0b00000000_11111111, b, c); - let e = _mm512_setr_ps( - 1., 0., -1., -2., -3., -4., -5., -6., 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fnmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_maskz_fnmadd_ps(0, a, b, c); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fnmadd_ps(0b00000000_11111111, a, b, c); - let e = _mm512_setr_ps( - 1., 0., -1., -2., -3., -4., -5., -6., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_setr_pd() { + let r = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fnmadd_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., - ); - let r = _mm512_mask3_fnmadd_ps(a, b, c, 0); - assert_eq_m512(r, c); - let r = _mm512_mask3_fnmadd_ps(a, b, c, 0b00000000_11111111); - let e = _mm512_setr_ps( - 1., 0., -1., -2., -3., -4., -5., -6., 2., 2., 2., 2., 2., 2., 2., 2., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_set_pd() { + let r = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, _mm512_set_pd(7., 6., 5., 4., 3., 2., 1., 0.)); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fnmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_fnmsub_ps(a, b, c); - let e = _mm512_setr_ps( - -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., -15., -16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_rol_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_rol_epi32(a, 1); + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rol_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_mask_rol_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rol_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fnmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_mask_fnmsub_ps(a, 0, b, c); - assert_eq_m512(r, a); - let r = _mm512_mask_fnmsub_ps(a, 0b00000000_11111111, b, c); - let e = _mm512_setr_ps( - -1., -2., -3., -4., -5., -6., -7., -8., 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_rol_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let r = _mm512_maskz_rol_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rol_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fnmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let r = _mm512_maskz_fnmsub_ps(0, a, b, c); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fnmsub_ps(0b00000000_11111111, a, b, c); - let e = _mm512_setr_ps( - -1., -2., -3., -4., -5., -6., -7., -8., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_ror_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_ror_epi32(a, 1); + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fnmsub_ps() { - let a = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - ); - let b = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let c = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., - ); - let r = _mm512_mask3_fnmsub_ps(a, b, c, 0); - assert_eq_m512(r, c); - let r = _mm512_mask3_fnmsub_ps(a, b, c, 0b00000000_11111111); - let e = _mm512_setr_ps( - -1., -2., -3., -4., -5., -6., -7., -8., 2., 2., 2., 2., 2., 2., 2., 2., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_ror_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_mask_ror_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_ror_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_rcp14_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_rcp14_ps(a); - let e = _mm512_set1_ps(0.33333206); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_ror_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + let r = _mm512_maskz_ror_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_ror_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_rcp14_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_mask_rcp14_ps(a, 0, a); - assert_eq_m512(r, a); - let r = _mm512_mask_rcp14_ps(a, 0b11111111_00000000, a); - let e = _mm512_setr_ps( - 3., 3., 3., 3., 3., 3., 3., 3., 0.33333206, 0.33333206, 0.33333206, 0.33333206, - 0.33333206, 0.33333206, 0.33333206, 0.33333206, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_slli_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_slli_epi32(a, 1); + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_rcp14_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_maskz_rcp14_ps(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_rcp14_ps(0b11111111_00000000, a); - let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 0.33333206, 0.33333206, 0.33333206, 0.33333206, - 0.33333206, 0.33333206, 0.33333206, 0.33333206, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_slli_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_mask_slli_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_slli_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_rsqrt14_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_rsqrt14_ps(a); - let e = _mm512_set1_ps(0.5773392); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_slli_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let r = _mm512_maskz_slli_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_slli_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_rsqrt14_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_mask_rsqrt14_ps(a, 0, a); - assert_eq_m512(r, a); - let r = _mm512_mask_rsqrt14_ps(a, 0b11111111_00000000, a); - let e = _mm512_setr_ps( - 3., 3., 3., 3., 3., 3., 3., 3., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, - 0.5773392, 0.5773392, 0.5773392, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_srli_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_srli_epi32(a, 1); + let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_rsqrt14_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_maskz_rsqrt14_ps(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_rsqrt14_ps(0b11111111_00000000, a); - let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, - 0.5773392, 0.5773392, 0.5773392, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_srli_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_mask_srli_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srli_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_getexp_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_getexp_ps(a); - let e = _mm512_set1_ps(1.); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_srli_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); + let r = _mm512_maskz_srli_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srli_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0 << 31); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_getexp_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_mask_getexp_ps(a, 0, a); - assert_eq_m512(r, a); - let r = _mm512_mask_getexp_ps(a, 0b11111111_00000000, a); - let e = _mm512_setr_ps( - 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_rolv_epi32(a, b); + + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_getexp_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_maskz_getexp_ps(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_getexp_ps(0b11111111_00000000, a); - let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_rolv_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rolv_epi32(a, 0b11111111_11111111, a, b); + + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_getmant_ps() { - let a = _mm512_set1_ps(10.); - let r = _mm512_getmant_ps(a, _MM_MANT_NORM_P75_1P5, _MM_MANT_SIGN_NAN); - let e = _mm512_set1_ps(1.25); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_rolv_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rolv_epi32(0b00000000_11111111, a, b); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_getmant_ps() { - let a = _mm512_set1_ps(10.); - let r = _mm512_mask_getmant_ps(a, 0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); - assert_eq_m512(r, a); - let r = _mm512_mask_getmant_ps( - a, - 0b11111111_00000000, - a, - _MM_MANT_NORM_1_2, - _MM_MANT_SIGN_SRC, - ); - let e = _mm512_setr_ps( - 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_rorv_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_rorv_epi32(a, b); + + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_getmant_ps() { - let a = _mm512_set1_ps(10.); - let r = _mm512_maskz_getmant_ps(0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = - _mm512_maskz_getmant_ps(0b11111111_00000000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); - let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, - ); - assert_eq_m512(r, e); - } + unsafe fn test_mm512_mask_rorv_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_add_round_ps() { - let a = _mm512_setr_ps( - 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, - ); - let b = _mm512_set1_ps(-1.); - let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - -1., - 0.5, - 1., - 2.5, - 3., - 4.5, - 5., - 6.5, - 7., - 8.5, - 9., - 10.5, - 11., - 12.5, - 13., - -0.99999994, - ); - assert_eq_m512(r, e); - let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, - ); - assert_eq_m512(r, e); + let r = _mm512_mask_rorv_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rorv_epi32(a, 0b11111111_11111111, a, b); + + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_add_round_ps() { - let a = _mm512_setr_ps( - 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, - ); - let b = _mm512_set1_ps(-1.); - let r = _mm512_mask_add_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_add_round_ps( - a, - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 0., - 1.5, - 2., - 3.5, - 4., - 5.5, - 6., - 7.5, - 7., - 8.5, - 9., - 10.5, - 11., - 12.5, - 13., - -0.99999994, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_rorv_epi32() { + let a = _mm512_set_epi32(3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + let b = _mm512_set_epi32(2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_rorv_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rorv_epi32(0b00000000_11111111, a, b); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_add_round_ps() { - let a = _mm512_setr_ps( - 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, - ); - let b = _mm512_set1_ps(-1.); - let r = _mm512_maskz_add_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_add_round_ps( - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 7., - 8.5, - 9., - 10.5, - 11., - 12.5, - 13., - -0.99999994, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_sllv_epi32(a, count); + + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sub_round_ps() { - let a = _mm512_setr_ps( - 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - -1., - 0.5, - 1., - 2.5, - 3., - 4.5, - 5., - 6.5, - 7., - 8.5, - 9., - 10.5, - 11., - 12.5, - 13., - -0.99999994, - ); - assert_eq_m512(r, e); - let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_sllv_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sllv_epi32(a, 0b11111111_11111111, a, count); + + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sub_round_ps() { - let a = _mm512_setr_ps( - 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_mask_sub_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_sub_round_ps( - a, - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 0., - 1.5, - 2., - 3.5, - 4., - 5.5, - 6., - 7.5, - 7., - 8.5, - 9., - 10.5, - 11., - 12.5, - 13., - -0.99999994, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_sllv_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sllv_epi32(0b00000000_11111111, a, count); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sub_round_ps() { - let a = _mm512_setr_ps( - 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, - ); - let b = _mm512_set1_ps(1.); - let r = _mm512_maskz_sub_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_sub_round_ps( - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 7., - 8.5, - 9., - 10.5, - 11., - 12.5, - 13., - -0.99999994, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_srlv_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_srlv_epi32(a, count); + + let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mul_round_ps() { - let a = _mm512_setr_ps( - 0., - 1.5, - 2., - 3.5, - 4., - 5.5, - 6., - 7.5, - 8., - 9.5, - 10., - 11.5, - 12., - 13.5, - 14., - 0.00000000000000000000007, - ); - let b = _mm512_set1_ps(0.1); - let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - 0., - 0.15, - 0.2, - 0.35, - 0.4, - 0.55, - 0.6, - 0.75, - 0.8, - 0.95, - 1.0, - 1.15, - 1.2, - 1.35, - 1.4, - 0.000000000000000000000007000001, - ); - assert_eq_m512(r, e); - let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - 0., - 0.14999999, - 0.2, - 0.35, - 0.4, - 0.54999995, - 0.59999996, - 0.75, - 0.8, - 0.95, - 1.0, - 1.15, - 1.1999999, - 1.3499999, - 1.4, - 0.000000000000000000000007, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_srlv_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_srlv_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srlv_epi32(a, 0b11111111_11111111, a, count); + + let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_mul_round_ps() { - let a = _mm512_setr_ps( - 0., - 1.5, - 2., - 3.5, - 4., - 5.5, - 6., - 7.5, - 8., - 9.5, - 10., - 11.5, - 12., - 13.5, - 14., - 0.00000000000000000000007, - ); - let b = _mm512_set1_ps(0.1); - let r = _mm512_mask_mul_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_mul_round_ps( - a, - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_srlv_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); + let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_srlv_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srlv_epi32(0b00000000_11111111, a, count); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ); - let e = _mm512_setr_ps( - 0., - 1.5, - 2., - 3.5, - 4., - 5.5, - 6., - 7.5, - 0.8, - 0.95, - 1.0, - 1.15, - 1.2, - 1.35, - 1.4, - 0.000000000000000000000007000001, + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_sll_epi32(a, count); + let e = _mm512_set_epi32( + 0, + 1 << 2, + 1 << 3, + 1 << 4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_mul_round_ps() { - let a = _mm512_setr_ps( - 0., - 1.5, - 2., - 3.5, - 4., - 5.5, - 6., - 7.5, - 8., - 9.5, - 10., - 11.5, - 12., - 13.5, - 14., - 0.00000000000000000000007, - ); - let b = _mm512_set1_ps(0.1); - let r = _mm512_maskz_mul_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_mul_round_ps( - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ); - let e = _mm512_setr_ps( - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0.8, - 0.95, - 1.0, - 1.15, - 1.2, - 1.35, - 1.4, - 0.000000000000000000000007000001, + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_sll_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sll_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32( + 0, + 1 << 2, + 1 << 3, + 1 << 4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_div_round_ps() { - let a = _mm512_set1_ps(1.); - let b = _mm512_set1_ps(3.); - let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(0.33333334); - assert_eq_m512(r, e); - let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(0.3333333); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 31, + ); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_sll_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sll_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_div_round_ps() { - let a = _mm512_set1_ps(1.); - let b = _mm512_set1_ps(3.); - let r = _mm512_mask_div_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_div_round_ps( - a, - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 1., 1., 1., 1., 1., 1., 1., 1., 0.33333334, 0.33333334, 0.33333334, 0.33333334, - 0.33333334, 0.33333334, 0.33333334, 0.33333334, + unsafe fn test_mm512_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ); - assert_eq_m512(r, e); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_srl_epi32(a, count); + let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_div_round_ps() { - let a = _mm512_set1_ps(1.); - let b = _mm512_set1_ps(3.); - let r = _mm512_maskz_div_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_div_round_ps( - 0b11111111_00000000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ); - let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 0.33333334, 0.33333334, 0.33333334, 0.33333334, - 0.33333334, 0.33333334, 0.33333334, 0.33333334, + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_srl_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srl_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 31, ); - assert_eq_m512(r, e); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_srl_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srl_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 29); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sqrt_round_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(1.7320508); - assert_eq_m512(r, e); - let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(1.7320509); - assert_eq_m512(r, e); + unsafe fn test_mm512_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let count = _mm_set_epi32(1, 0, 0, 2); + let r = _mm512_sra_epi32(a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sqrt_round_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_mask_sqrt_round_ps(a, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_sqrt_round_ps( - a, - 0b11111111_00000000, - a, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 3., 3., 3., 3., 3., 3., 3., 3., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, - 1.7320508, 1.7320508, 1.7320508, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_sra_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sra_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sqrt_round_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_maskz_sqrt_round_ps(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_sqrt_round_ps( - 0b11111111_00000000, - a, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, - 1.7320508, 1.7320508, 1.7320508, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_sra_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sra_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(-0.99999994); - assert_eq_m512(r, e); - let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(-0.9999999); - assert_eq_m512(r, e); + unsafe fn test_mm512_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_srav_epi32(a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = - _mm512_mask_fmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_fmadd_round_ps( - a, - 0b00000000_11111111, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let r = _mm512_mask_srav_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srav_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = - _mm512_maskz_fmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmadd_round_ps( - 0b00000000_11111111, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_maskz_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2); + let r = _mm512_maskz_srav_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srav_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = - _mm512_mask3_fmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmadd_round_ps( - a, - b, - c, - 0b00000000_11111111, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -1., - -1., - -1., - -1., - -1., - -1., - -1., - -1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, -15); + let r = _mm512_srai_epi32(a, 2); + let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(-0.99999994); - assert_eq_m512(r, e); - let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(-0.9999999); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); + let r = _mm512_mask_srai_epi32(a, 0, a, 2); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srai_epi32(a, 0b11111111_11111111, a, 2); + let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = - _mm512_mask_fmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_fmsub_round_ps( - a, - 0b00000000_11111111, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); + let r = _mm512_maskz_srai_epi32(0, a, 2); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srai_epi32(0b00000000_11111111, a, 2); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let e = _mm512_setr_ps( - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, + let r = _mm512_permute_ps(a, 1); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = - _mm512_maskz_fmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmsub_round_ps( - 0b00000000_11111111, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let e = _mm512_setr_ps( - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., + let r = _mm512_mask_permute_ps(a, 0b00000000_00000000, a, 1); + assert_eq_m512(r, a); + let r = _mm512_mask_permute_ps(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = - _mm512_mask3_fmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmsub_round_ps( - a, - b, - c, - 0b00000000_11111111, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let e = _mm512_setr_ps( - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - -0.99999994, - 1., - 1., - 1., - 1., - 1., - 1., - 1., - 1., + let r = _mm512_maskz_permute_ps(0, a, 1); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permute_ps(0b00000000_11111111, a, 1); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmaddsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, + unsafe fn test_mm512_permutevar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_permutevar_epi32(idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutevar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_permutevar_epi32(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutevar_epi32(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - assert_eq_m512(r, e); - let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., - -0.9999999, 1., -0.9999999, 1., -0.9999999, + let b = _mm512_set1_epi32(1); + let r = _mm512_permutevar_ps(a, b); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmaddsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_mask_fmaddsub_round_ps( - a, - 0, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_permutevar_ps(a, 0, a, b); assert_eq_m512(r, a); - let r = _mm512_mask_fmaddsub_round_ps( - a, - 0b00000000_11111111, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, + let r = _mm512_mask_permutevar_ps(a, 0b11111111_11111111, a, b); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmaddsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_maskz_fmaddsub_round_ps( - 0, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_permutevar_ps(0, a, b); assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmaddsub_round_ps( - 0b00000000_11111111, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + let r = _mm512_maskz_permutevar_ps(0b00000000_11111111, a, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., ); - let e = _mm512_setr_ps( - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_permutexvar_epi32(idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_permutexvar_epi32(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutexvar_epi32(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_permutexvar_epi32(0, idx, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutexvar_epi32(0b00000000_11111111, idx, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); + let r = _mm512_permutexvar_ps(idx, a); + let e = _mm512_set1_ps(14.); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmaddsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_mask3_fmaddsub_round_ps( - a, - b, - c, - 0, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmaddsub_round_ps( - a, - b, - c, - 0b00000000_11111111, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + let r = _mm512_mask_permutexvar_ps(a, 0, idx, a); + assert_eq_m512(r, a); + let r = _mm512_mask_permutexvar_ps(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_ps(14.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let e = _mm512_setr_ps( - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - -1., - -1., - -1., - -1., - -1., - -1., - -1., - -1., + let r = _mm512_maskz_permutexvar_ps(0, idx, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutexvar_ps(0b00000000_11111111, idx, a); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 14., 14., 14., 14., 14., 14., 14., 14., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fmsubadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, + unsafe fn test_mm512_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, ); - assert_eq_m512(r, e); - let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_setr_ps( - -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., - -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + let b = _mm512_set1_epi32(100); + let r = _mm512_permutex2var_epi32(a, idx, b); + let e = _mm512_set_epi32( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fmsubadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_mask_fmsubadd_round_ps( - a, - 0, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - assert_eq_m512(r, a); - let r = _mm512_mask_fmsubadd_round_ps( - a, - 0b00000000_11111111, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, ); - let e = _mm512_setr_ps( - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, - 0.00000007, + let b = _mm512_set1_epi32(100); + let r = _mm512_mask_permutex2var_epi32(a, 0, idx, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex2var_epi32(a, 0b11111111_11111111, idx, b); + let e = _mm512_set_epi32( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fmsubadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_maskz_fmsubadd_round_ps( - 0, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, ); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fmsubadd_round_ps( - 0b00000000_11111111, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + let b = _mm512_set1_epi32(100); + let r = _mm512_maskz_permutex2var_epi32(0, a, idx, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex2var_epi32(0b00000000_11111111, a, idx, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 10, 100, 9, 100, 8, 100, 7, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1000, + 1 << 4, + 2000, + 1 << 4, + 3000, + 1 << 4, + 4000, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, ); - let e = _mm512_setr_ps( - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., + let b = _mm512_set1_epi32(100); + let r = _mm512_mask2_permutex2var_epi32(a, idx, 0, b); + assert_eq_m512i(r, idx); + let r = _mm512_mask2_permutex2var_epi32(a, idx, 0b00000000_11111111, b); + let e = _mm512_set_epi32( + 1000, + 1 << 4, + 2000, + 1 << 4, + 3000, + 1 << 4, + 4000, + 1 << 4, + 10, + 100, + 9, + 100, + 8, + 100, + 7, + 100, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fmsubadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_mask3_fmsubadd_round_ps( - a, - b, - c, - 0, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - assert_eq_m512(r, c); - let r = _mm512_mask3_fmsubadd_round_ps( - a, - b, - c, - 0b00000000_11111111, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, ); - let e = _mm512_setr_ps( - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -0.99999994, - 1.0000001, - -1., - -1., - -1., - -1., - -1., - -1., - -1., - -1., + let b = _mm512_set1_ps(100.); + let r = _mm512_permutex2var_ps(a, idx, b); + let e = _mm512_set_ps( + 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fnmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(0.99999994); - assert_eq_m512(r, e); - let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(0.9999999); + unsafe fn test_mm512_mask_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_mask_permutex2var_ps(a, 0, idx, b); + assert_eq_m512(r, a); + let r = _mm512_mask_permutex2var_ps(a, 0b11111111_11111111, idx, b); + let e = _mm512_set_ps( + 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., + ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fnmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = - _mm512_mask_fnmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_fnmadd_round_ps( - a, - 0b00000000_11111111, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let e = _mm512_setr_ps( - 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, - 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, - 0.00000007, 0.00000007, + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_maskz_permutex2var_ps(0, a, idx, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutex2var_ps(0b00000000_11111111, a, idx, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fnmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = - _mm512_maskz_fnmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fnmadd_round_ps( - 0b00000000_11111111, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask2_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - let e = _mm512_setr_ps( - 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, - 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_mask2_permutex2var_ps(a, idx, 0, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_mask2_permutex2var_ps(a, idx, 0b00000000_11111111, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fnmadd_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(1.); - let r = - _mm512_mask3_fnmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, c); - let r = _mm512_mask3_fnmadd_round_ps( - a, - b, - c, - 0b00000000_11111111, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_ps( - 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, - 0.99999994, 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm512_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_shuffle_epi32(a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_fnmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(0.99999994); - assert_eq_m512(r, e); - let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(0.9999999); - assert_eq_m512(r, e); + unsafe fn test_mm512_mask_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_mask_shuffle_epi32(a, 0, a, _MM_PERM_AADD); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_epi32(a, 0b11111111_11111111, a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_fnmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = - _mm512_mask_fnmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, a); - let r = _mm512_mask_fnmsub_round_ps( - a, - 0b00000000_11111111, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_maskz_shuffle_epi32(0, a, _MM_PERM_AADD); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_epi32(0b00000000_11111111, a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., ); + let r = _mm512_shuffle_ps(a, b, 0x0F); let e = _mm512_setr_ps( - 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, - 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, - 0.00000007, 0.00000007, + 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_fnmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = - _mm512_maskz_fnmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_fnmsub_round_ps( - 0b00000000_11111111, - a, - b, - c, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_mask_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., ); + let r = _mm512_mask_shuffle_ps(a, 0, a, b, 0x0F); + assert_eq_m512(r, a); + let r = _mm512_mask_shuffle_ps(a, 0b11111111_11111111, a, b, 0x0F); let e = _mm512_setr_ps( - 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, - 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask3_fnmsub_round_ps() { - let a = _mm512_set1_ps(0.00000007); - let b = _mm512_set1_ps(1.); - let c = _mm512_set1_ps(-1.); - let r = - _mm512_mask3_fnmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512(r, c); - let r = _mm512_mask3_fnmsub_round_ps( - a, - b, - c, - 0b00000000_11111111, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + unsafe fn test_mm512_maskz_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., ); + let r = _mm512_maskz_shuffle_ps(0, a, b, 0x0F); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_shuffle_ps(0b00000000_11111111, a, b, 0x0F); let e = _mm512_setr_ps( - 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, - 0.99999994, -1., -1., -1., -1., -1., -1., -1., -1., + 8., 8., 2., 2., 16., 16., 10., 10., 0., 0., 0., 0., 0., 0., 0., 0., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_max_round_ps() { + unsafe fn test_mm512_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_shuffle_i32x4(a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_mask_shuffle_i32x4(a, 0, a, b, 0b00000000); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_i32x4(a, 0b11111111_11111111, a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_maskz_shuffle_i32x4(0, a, b, 0b00000000); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_i32x4(0b00000000_11111111, a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_f32x4() { let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., ); let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., ); - let r = _mm512_max_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_shuffle_f32x4(a, b, 0b00000000); let e = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_max_round_ps() { + unsafe fn test_mm512_mask_shuffle_f32x4() { let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., ); let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., ); - let r = _mm512_mask_max_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_mask_shuffle_f32x4(a, 0, a, b, 0b00000000); assert_eq_m512(r, a); - let r = _mm512_mask_max_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_mask_shuffle_f32x4(a, 0b11111111_11111111, a, b, 0b00000000); let e = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_max_round_ps() { + unsafe fn test_mm512_maskz_shuffle_f32x4() { let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., ); let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., ); - let r = _mm512_maskz_max_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_maskz_shuffle_f32x4(0, a, b, 0b00000000); assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_max_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_maskz_shuffle_f32x4(0b00000000_11111111, a, b, 0b00000000); let e = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., + 1., 4., 5., 8., 1., 4., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_min_round_ps() { + unsafe fn test_mm512_extractf32x4_ps() { let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + let r = _mm512_extractf32x4_ps(a, 0x1); + let e = _mm_setr_ps(5., 6., 7., 8.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_extractf32x4_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); - let r = _mm512_min_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let src = _mm_set1_ps(100.); + let r = _mm512_mask_extractf32x4_ps(src, 0, a, 0x1); + assert_eq_m128(r, src); + let r = _mm512_mask_extractf32x4_ps(src, 0b11111111, a, 0x1); + let e = _mm_setr_ps(5., 6., 7., 8.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_extractf32x4_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_maskz_extractf32x4_ps(0, a, 0x1); + assert_eq_m128(r, _mm_setzero_ps()); + let r = _mm512_maskz_extractf32x4_ps(0b00000001, a, 0x1); + let e = _mm_setr_ps(5., 0., 0., 0.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_extracti32x4_epi32() { + let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_extracti32x4_epi32(a, 0x1); + let e = _mm_setr_epi32(5, 6, 7, 8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_extracti32x4_epi32() { + let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let src = _mm_set1_epi32(100); + let r = _mm512_mask_extracti32x4_epi32(src, 0, a, 0x1); + assert_eq_m128i(r, src); + let r = _mm512_mask_extracti32x4_epi32(src, 0b11111111, a, 0x1); + let e = _mm_setr_epi32(5, 6, 7, 8); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_extracti32x4_epi32() { + let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_maskz_extracti32x4_epi32(0, a, 0x1); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_extracti32x4_epi32(0b00000001, a, 0x1); + let e = _mm_setr_epi32(5, 0, 0, 0); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_moveldup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_moveldup_ps(a); let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., + 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_min_round_ps() { + unsafe fn test_mm512_mask_moveldup_ps() { let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); - let r = _mm512_mask_min_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_mask_moveldup_ps(a, 0, a); assert_eq_m512(r, a); - let r = _mm512_mask_min_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_mask_moveldup_ps(a, 0b11111111_11111111, a); let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_min_round_ps() { + unsafe fn test_mm512_maskz_moveldup_ps() { let a = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); - let r = _mm512_maskz_min_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_maskz_moveldup_ps(0, a); assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_min_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_maskz_moveldup_ps(0b00000000_11111111, a); let e = _mm512_setr_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + 1., 1., 3., 3., 5., 5., 7., 7., 0., 0., 0., 0., 0., 0., 0., 0., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_getexp_round_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_getexp_round_ps(a, _MM_FROUND_CUR_DIRECTION); - let e = _mm512_set1_ps(1.); - assert_eq_m512(r, e); - let r = _mm512_getexp_round_ps(a, _MM_FROUND_NO_EXC); - let e = _mm512_set1_ps(1.); + unsafe fn test_mm512_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_movehdup_ps(a); + let e = _mm512_setr_ps( + 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., + ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_getexp_round_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_mask_getexp_round_ps(a, 0, a, _MM_FROUND_CUR_DIRECTION); + unsafe fn test_mm512_mask_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_mask_movehdup_ps(a, 0, a); assert_eq_m512(r, a); - let r = _mm512_mask_getexp_round_ps(a, 0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_mask_movehdup_ps(a, 0b11111111_11111111, a); let e = _mm512_setr_ps( - 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., + 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_getexp_round_ps() { - let a = _mm512_set1_ps(3.); - let r = _mm512_maskz_getexp_round_ps(0, a, _MM_FROUND_CUR_DIRECTION); + unsafe fn test_mm512_maskz_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_maskz_movehdup_ps(0, a); assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_getexp_round_ps(0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let r = _mm512_maskz_movehdup_ps(0b00000000_11111111, a); let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + 2., 2., 4., 4., 6., 6., 8., 8., 0., 0., 0., 0., 0., 0., 0., 0., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_getmant_round_ps() { - let a = _mm512_set1_ps(10.); - let r = _mm512_getmant_round_ps( - a, - _MM_MANT_NORM_1_2, - _MM_MANT_SIGN_SRC, - _MM_FROUND_CUR_DIRECTION, - ); - let e = _mm512_set1_ps(1.25); - assert_eq_m512(r, e); + unsafe fn test_mm512_inserti32x4() { + let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm_setr_epi32(17, 18, 19, 20); + let r = _mm512_inserti32x4(a, b, 0); + let e = _mm512_setr_epi32(17, 18, 19, 20, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_getmant_round_ps() { - let a = _mm512_set1_ps(10.); - let r = _mm512_mask_getmant_round_ps( - a, - 0, - a, - _MM_MANT_NORM_1_2, - _MM_MANT_SIGN_SRC, - _MM_FROUND_CUR_DIRECTION, - ); - assert_eq_m512(r, a); - let r = _mm512_mask_getmant_round_ps( - a, - 0b11111111_00000000, - a, - _MM_MANT_NORM_1_2, - _MM_MANT_SIGN_SRC, - _MM_FROUND_CUR_DIRECTION, + unsafe fn test_mm512_mask_inserti32x4() { + let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm_setr_epi32(17, 18, 19, 20); + let r = _mm512_mask_inserti32x4(a, 0, a, b, 0); + assert_eq_m512i(r, a); + let r = _mm512_mask_inserti32x4(a, 0b11111111_11111111, a, b, 0); + let e = _mm512_setr_epi32(17, 18, 19, 20, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_inserti32x4() { + let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm_setr_epi32(17, 18, 19, 20); + let r = _mm512_maskz_inserti32x4(0, a, b, 0); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_inserti32x4(0b00000000_11111111, a, b, 0); + let e = _mm512_setr_epi32(17, 18, 19, 20, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_insertf32x4() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); + let b = _mm_setr_ps(17., 18., 19., 20.); + let r = _mm512_insertf32x4(a, b, 0); let e = _mm512_setr_ps( - 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + 17., 18., 19., 20., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_getmant_round_ps() { - let a = _mm512_set1_ps(10.); - let r = _mm512_maskz_getmant_round_ps( - 0, - a, - _MM_MANT_NORM_1_2, - _MM_MANT_SIGN_SRC, - _MM_FROUND_CUR_DIRECTION, - ); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_getmant_round_ps( - 0b11111111_00000000, - a, - _MM_MANT_NORM_1_2, - _MM_MANT_SIGN_SRC, - _MM_FROUND_CUR_DIRECTION, + unsafe fn test_mm512_mask_insertf32x4() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); + let b = _mm_setr_ps(17., 18., 19., 20.); + let r = _mm512_mask_insertf32x4(a, 0, a, b, 0); + assert_eq_m512(r, a); + let r = _mm512_mask_insertf32x4(a, 0b11111111_11111111, a, b, 0); let e = _mm512_setr_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + 17., 18., 19., 20., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvtps_epi32() { + unsafe fn test_mm512_maskz_insertf32x4() { let a = _mm512_setr_ps( - 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., ); - let r = _mm512_cvtps_epi32(a); - let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); - assert_eq_m512i(r, e); + let b = _mm_setr_ps(17., 18., 19., 20.); + let r = _mm512_maskz_insertf32x4(0, a, b, 0); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_insertf32x4(0b00000000_11111111, a, b, 0); + let e = _mm512_setr_ps( + 17., 18., 19., 20., 5., 6., 7., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvtps_epi32() { - let a = _mm512_setr_ps( - 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_castps128_ps512() { + let a = _mm_setr_ps(17., 18., 19., 20.); + let r = _mm512_castps128_ps512(a); + let e = _mm512_setr_ps( + 17., 18., 19., 20., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., ); - let src = _mm512_set1_epi32(0); - let r = _mm512_mask_cvtps_epi32(src, 0, a); - assert_eq_m512i(r, src); - let r = _mm512_mask_cvtps_epi32(src, 0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvtps_epi32() { - let a = _mm512_setr_ps( - 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_castps256_ps512() { + let a = _mm256_setr_ps(17., 18., 19., 20., 21., 22., 23., 24.); + let r = _mm512_castps256_ps512(a); + let e = _mm512_setr_ps( + 17., 18., 19., 20., 21., 22., 23., 24., -1., -1., -1., -1., -1., -1., -1., -1., ); - let r = _mm512_maskz_cvtps_epi32(0, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvtps_epi32(0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvtps_epu32() { - let a = _mm512_setr_ps( - 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_zextps128_ps512() { + let a = _mm_setr_ps(17., 18., 19., 20.); + let r = _mm512_zextps128_ps512(a); + let e = _mm512_setr_ps( + 17., 18., 19., 20., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., ); - let r = _mm512_cvtps_epu32(a); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); - assert_eq_m512i(r, e); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvtps_epu32() { - let a = _mm512_setr_ps( - 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_zextps256_ps512() { + let a = _mm256_setr_ps(17., 18., 19., 20., 21., 22., 23., 24.); + let r = _mm512_zextps256_ps512(a); + let e = _mm512_setr_ps( + 17., 18., 19., 20., 21., 22., 23., 24., 0., 0., 0., 0., 0., 0., 0., 0., ); - let src = _mm512_set1_epi32(0); - let r = _mm512_mask_cvtps_epu32(src, 0, a); - assert_eq_m512i(r, src); - let r = _mm512_mask_cvtps_epu32(src, 0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvtps_epu32() { + unsafe fn test_mm512_castps512_ps128() { let a = _mm512_setr_ps( - 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + 17., 18., 19., 20., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., ); - let r = _mm512_maskz_cvtps_epu32(0, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvtps_epu32(0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + let r = _mm512_castps512_ps128(a); + let e = _mm_setr_ps(17., 18., 19., 20.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvt_roundps_epi32() { + unsafe fn test_mm512_castps512_ps256() { let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + 17., 18., 19., 20., 21., 22., 23., 24., -1., -1., -1., -1., -1., -1., -1., -1., ); - let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); - assert_eq_m512i(r, e); - let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + let r = _mm512_castps512_ps256(a); + let e = _mm256_setr_ps(17., 18., 19., 20., 21., 22., 23., 24.); + assert_eq_m256(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvt_roundps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let src = _mm512_set1_epi32(0); - let r = - _mm512_mask_cvt_roundps_epi32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512i(r, src); - let r = _mm512_mask_cvt_roundps_epi32( - src, - 0b00000000_11111111, - a, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_castps_pd() { + let a = _mm512_set1_ps(1.); + let r = _mm512_castps_pd(a); + let e = _mm512_set1_pd(0.007812501848093234); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvt_roundps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let r = _mm512_maskz_cvt_roundps_epi32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvt_roundps_epi32( - 0b00000000_11111111, - a, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + unsafe fn test_mm512_castps_si512() { + let a = _mm512_set1_ps(1.); + let r = _mm512_castps_si512(a); + let e = _mm512_set1_epi32(1065353216); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvt_roundps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); - assert_eq_m512i(r, e); - let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + unsafe fn test_mm512_broadcastd_epi32() { + let a = _mm_set_epi32(17, 18, 19, 20); + let r = _mm512_broadcastd_epi32(a); + let e = _mm512_set1_epi32(20); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvt_roundps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let src = _mm512_set1_epi32(0); - let r = - _mm512_mask_cvt_roundps_epu32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + unsafe fn test_mm512_mask_broadcastd_epi32() { + let src = _mm512_set1_epi32(20); + let a = _mm_set_epi32(17, 18, 19, 20); + let r = _mm512_mask_broadcastd_epi32(src, 0, a); assert_eq_m512i(r, src); - let r = _mm512_mask_cvt_roundps_epu32( - src, - 0b00000000_11111111, - a, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_mask_broadcastd_epi32(src, 0b11111111_11111111, a); + let e = _mm512_set1_epi32(20); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvt_roundps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let r = _mm512_maskz_cvt_roundps_epu32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + unsafe fn test_mm512_maskz_broadcastd_epi32() { + let a = _mm_set_epi32(17, 18, 19, 20); + let r = _mm512_maskz_broadcastd_epi32(0, a); assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvt_roundps_epu32( - 0b00000000_11111111, - a, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_maskz_broadcastd_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvtt_roundps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let r = _mm512_cvtt_roundps_epi32(a, _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + unsafe fn test_mm512_broadcastss_ps() { + let a = _mm_set_ps(17., 18., 19., 20.); + let r = _mm512_broadcastss_ps(a); + let e = _mm512_set1_ps(20.); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvtt_roundps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let src = _mm512_set1_epi32(0); - let r = _mm512_mask_cvtt_roundps_epi32(src, 0, a, _MM_FROUND_NO_EXC); - assert_eq_m512i(r, src); - let r = _mm512_mask_cvtt_roundps_epi32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_mask_broadcastss_ps() { + let src = _mm512_set1_ps(20.); + let a = _mm_set_ps(17., 18., 19., 20.); + let r = _mm512_mask_broadcastss_ps(src, 0, a); + assert_eq_m512(r, src); + let r = _mm512_mask_broadcastss_ps(src, 0b11111111_11111111, a); + let e = _mm512_set1_ps(20.); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvtt_roundps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_maskz_broadcastss_ps() { + let a = _mm_set_ps(17., 18., 19., 20.); + let r = _mm512_maskz_broadcastss_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_broadcastss_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 20., 20., 20., 20., 20., 20., 20., 20., 0., 0., 0., 0., 0., 0., 0., 0., ); - let r = _mm512_maskz_cvtt_roundps_epi32(0, a, _MM_FROUND_NO_EXC); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvtt_roundps_epi32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvtt_roundps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_broadcast_i32x4() { + let a = _mm_set_epi32(17, 18, 19, 20); + let r = _mm512_broadcast_i32x4(a); + let e = _mm512_set_epi32( + 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, ); - let r = _mm512_cvtt_roundps_epu32(a, _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvtt_roundps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let src = _mm512_set1_epi32(0); - let r = _mm512_mask_cvtt_roundps_epu32(src, 0, a, _MM_FROUND_NO_EXC); + unsafe fn test_mm512_mask_broadcast_i32x4() { + let src = _mm512_set1_epi32(20); + let a = _mm_set_epi32(17, 18, 19, 20); + let r = _mm512_mask_broadcast_i32x4(src, 0, a); assert_eq_m512i(r, src); - let r = _mm512_mask_cvtt_roundps_epu32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_mask_broadcast_i32x4(src, 0b11111111_11111111, a); + let e = _mm512_set_epi32( + 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, + ); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvtt_roundps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, - ); - let r = _mm512_maskz_cvtt_roundps_epu32(0, a, _MM_FROUND_NO_EXC); + unsafe fn test_mm512_maskz_broadcast_i32x4() { + let a = _mm_set_epi32(17, 18, 19, 20); + let r = _mm512_maskz_broadcast_i32x4(0, a); assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvtt_roundps_epu32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_maskz_broadcast_i32x4(0b00000000_11111111, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 20, 17, 18, 19, 20); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvttps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_broadcast_f32x4() { + let a = _mm_set_ps(17., 18., 19., 20.); + let r = _mm512_broadcast_f32x4(a); + let e = _mm512_set_ps( + 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., ); - let r = _mm512_cvttps_epi32(a); - let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i(r, e); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_broadcast_f32x4() { + let src = _mm512_set1_ps(20.); + let a = _mm_set_ps(17., 18., 19., 20.); + let r = _mm512_mask_broadcast_f32x4(src, 0, a); + assert_eq_m512(r, src); + let r = _mm512_mask_broadcast_f32x4(src, 0b11111111_11111111, a); + let e = _mm512_set_ps( + 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvttps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_maskz_broadcast_f32x4() { + let a = _mm_set_ps(17., 18., 19., 20.); + let r = _mm512_maskz_broadcast_f32x4(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_broadcast_f32x4(0b00000000_11111111, a); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 17., 18., 19., 20., 17., 18., 19., 20., ); - let src = _mm512_set1_epi32(0); - let r = _mm512_mask_cvttps_epi32(src, 0, a); - assert_eq_m512i(r, src); - let r = _mm512_mask_cvttps_epi32(src, 0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_blend_epi32() { + let a = _mm512_set1_epi32(1); + let b = _mm512_set1_epi32(2); + let r = _mm512_mask_blend_epi32(0b11111111_00000000, a, b); + let e = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvttps_epi32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_mask_blend_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(2.); + let r = _mm512_mask_blend_ps(0b11111111_00000000, a, b); + let e = _mm512_set_ps( + 2., 2., 2., 2., 2., 2., 2., 2., 1., 1., 1., 1., 1., 1., 1., 1., ); - let r = _mm512_maskz_cvttps_epi32(0, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvttps_epi32(0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvttps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_unpackhi_epi32() { + let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm512_set_epi32( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ); - let r = _mm512_cvttps_epu32(a); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_unpackhi_epi32(a, b); + let e = _mm512_set_epi32(17, 1, 18, 2, 21, 5, 22, 6, 25, 9, 26, 10, 29, 13, 30, 14); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvttps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_mask_unpackhi_epi32() { + let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm512_set_epi32( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ); - let src = _mm512_set1_epi32(0); - let r = _mm512_mask_cvttps_epu32(src, 0, a); - assert_eq_m512i(r, src); - let r = _mm512_mask_cvttps_epu32(src, 0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_mask_unpackhi_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_unpackhi_epi32(a, 0b11111111_11111111, a, b); + let e = _mm512_set_epi32(17, 1, 18, 2, 21, 5, 22, 6, 25, 9, 26, 10, 29, 13, 30, 14); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvttps_epu32() { - let a = _mm512_setr_ps( - 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + unsafe fn test_mm512_maskz_unpackhi_epi32() { + let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm512_set_epi32( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ); - let r = _mm512_maskz_cvttps_epu32(0, a); + let r = _mm512_maskz_unpackhi_epi32(0, a, b); assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_cvttps_epu32(0b00000000_11111111, a); - let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_maskz_unpackhi_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 25, 9, 26, 10, 29, 13, 30, 14); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32gather_ps() { - let mut arr = [0f32; 256]; - for i in 0..256 { - arr[i] = i as f32; - } - // A multiplier of 4 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176); - let r = _mm512_i32gather_ps(index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512(r, _mm512_setr_ps(0., 16., 32., 48., 64., 80., 96., 112., - 120., 128., 136., 144., 152., 160., 168., 176.)); + unsafe fn test_mm512_unpackhi_ps() { + let a = _mm512_set_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let b = _mm512_set_ps( + 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + ); + let r = _mm512_unpackhi_ps(a, b); + let e = _mm512_set_ps( + 17., 1., 18., 2., 21., 5., 22., 6., 25., 9., 26., 10., 29., 13., 30., 14., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32gather_ps() { - let mut arr = [0f32; 256]; - for i in 0..256 { - arr[i] = i as f32; - } - let src = _mm512_set1_ps(2.); - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176); - // A multiplier of 4 is word-addressing - let r = _mm512_mask_i32gather_ps(src, mask, index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512(r, _mm512_setr_ps(2., 16., 2., 48., 2., 80., 2., 112., - 2., 128., 2., 144., 2., 160., 2., 176.)); + unsafe fn test_mm512_mask_unpackhi_ps() { + let a = _mm512_set_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let b = _mm512_set_ps( + 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + ); + let r = _mm512_mask_unpackhi_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_unpackhi_ps(a, 0b11111111_11111111, a, b); + let e = _mm512_set_ps( + 17., 1., 18., 2., 21., 5., 22., 6., 25., 9., 26., 10., 29., 13., 30., 14., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32gather_epi32() { - let mut arr = [0i32; 256]; - for i in 0..256 { - arr[i] = i as i32; - } - // A multiplier of 4 is word-addressing - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176); - let r = _mm512_i32gather_epi32(index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512i(r, _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 120, 128, 136, 144, 152, 160, 168, 176)); + unsafe fn test_mm512_maskz_unpackhi_ps() { + let a = _mm512_set_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let b = _mm512_set_ps( + 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + ); + let r = _mm512_maskz_unpackhi_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_unpackhi_ps(0b00000000_11111111, a, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 25., 9., 26., 10., 29., 13., 30., 14., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32gather_epi32() { - let mut arr = [0i32; 256]; - for i in 0..256 { - arr[i] = i as i32; - } - let src = _mm512_set1_epi32(2); - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - // A multiplier of 4 is word-addressing - let r = _mm512_mask_i32gather_epi32(src, mask, index, arr.as_ptr() as *const u8, 4); - #[rustfmt::skip] - assert_eq_m512i(r, _mm512_setr_epi32(2, 16, 2, 48, 2, 80, 2, 112, - 2, 144, 2, 176, 2, 208, 2, 240)); + unsafe fn test_mm512_unpacklo_epi32() { + let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm512_set_epi32( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + ); + let r = _mm512_unpacklo_epi32(a, b); + let e = _mm512_set_epi32(19, 3, 20, 4, 23, 7, 24, 8, 27, 11, 28, 12, 31, 15, 32, 16); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32scatter_ps() { - let mut arr = [0f32; 256]; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + unsafe fn test_mm512_mask_unpacklo_epi32() { + let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm512_set_epi32( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ); - // A multiplier of 4 is word-addressing - _mm512_i32scatter_ps(arr.as_mut_ptr() as *mut u8, index, src, 4); - let mut expected = [0f32; 256]; - for i in 0..16 { - expected[i * 16] = (i + 1) as f32; - } - assert_eq!(&arr[..], &expected[..],); + let r = _mm512_mask_unpacklo_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_unpacklo_epi32(a, 0b11111111_11111111, a, b); + let e = _mm512_set_epi32(19, 3, 20, 4, 23, 7, 24, 8, 27, 11, 28, 12, 31, 15, 32, 16); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32scatter_ps() { - let mut arr = [0f32; 256]; - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + unsafe fn test_mm512_maskz_unpacklo_epi32() { + let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = _mm512_set_epi32( + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ); - // A multiplier of 4 is word-addressing - _mm512_mask_i32scatter_ps(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); - let mut expected = [0f32; 256]; - for i in 0..8 { - expected[i * 32 + 16] = 2. * (i + 1) as f32; - } - assert_eq!(&arr[..], &expected[..],); + let r = _mm512_maskz_unpacklo_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_unpacklo_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 27, 11, 28, 12, 31, 15, 32, 16); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_i32scatter_epi32() { - let mut arr = [0i32; 256]; - #[rustfmt::skip] - - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - // A multiplier of 4 is word-addressing - _mm512_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, index, src, 4); - let mut expected = [0i32; 256]; - for i in 0..16 { - expected[i * 16] = (i + 1) as i32; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_unpacklo_ps() { + let a = _mm512_set_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let b = _mm512_set_ps( + 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + ); + let r = _mm512_unpacklo_ps(a, b); + let e = _mm512_set_ps( + 19., 3., 20., 4., 23., 7., 24., 8., 27., 11., 28., 12., 31., 15., 32., 16., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_i32scatter_epi32() { - let mut arr = [0i32; 256]; - let mask = 0b10101010_10101010; - #[rustfmt::skip] - let index = _mm512_setr_epi32(0, 16, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240); - let src = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - // A multiplier of 4 is word-addressing - _mm512_mask_i32scatter_epi32(arr.as_mut_ptr() as *mut u8, mask, index, src, 4); - let mut expected = [0i32; 256]; - for i in 0..8 { - expected[i * 32 + 16] = 2 * (i + 1) as i32; - } - assert_eq!(&arr[..], &expected[..],); + unsafe fn test_mm512_mask_unpacklo_ps() { + let a = _mm512_set_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let b = _mm512_set_ps( + 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + ); + let r = _mm512_mask_unpacklo_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_unpacklo_ps(a, 0b11111111_11111111, a, b); + let e = _mm512_set_ps( + 19., 3., 20., 4., 23., 7., 24., 8., 27., 11., 28., 12., 31., 15., 32., 16., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmplt_ps_mask(a, b); - assert_eq!(m, 0b00000101_00000101); + unsafe fn test_mm512_maskz_unpacklo_ps() { + let a = _mm512_set_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let b = _mm512_set_ps( + 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + ); + let r = _mm512_maskz_unpacklo_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_unpacklo_ps(0b00000000_11111111, a, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 27., 11., 28., 12., 31., 15., 32., 16., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmplt_ps_mask(mask, a, b); - assert_eq!(r, 0b00000100_00000100); + unsafe fn test_mm512_alignr_epi32() { + let a = _mm512_set_epi32(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let b = _mm512_set_epi32( + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, + ); + let r = _mm512_alignr_epi32(a, b, 0); + assert_eq_m512i(r, b); + let r = _mm512_alignr_epi32(a, b, 16); + assert_eq_m512i(r, b); + let r = _mm512_alignr_epi32(a, b, 1); + let e = _mm512_set_epi32( + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpnlt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - assert_eq!(_mm512_cmpnlt_ps_mask(a, b), !_mm512_cmplt_ps_mask(a, b)); + unsafe fn test_mm512_mask_alignr_epi32() { + let a = _mm512_set_epi32(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let b = _mm512_set_epi32( + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, + ); + let r = _mm512_mask_alignr_epi32(a, 0, a, b, 1); + assert_eq_m512i(r, a); + let r = _mm512_mask_alignr_epi32(a, 0b11111111_11111111, a, b, 1); + let e = _mm512_set_epi32( + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpnlt_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmpnlt_ps_mask(mask, a, b), 0b01111010_01111010); + unsafe fn test_mm512_maskz_alignr_epi32() { + let a = _mm512_set_epi32(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + let b = _mm512_set_epi32( + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, + ); + let r = _mm512_maskz_alignr_epi32(0, a, b, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_alignr_epi32(0b00000000_11111111, a, b, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 25, 24, 23, 22, 21, 20, 19, 18); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpnle_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmpnle_ps_mask(b, a); - assert_eq!(m, 0b00001101_00001101); + unsafe fn test_mm512_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_and_epi32(a, b); + let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpnle_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmpnle_ps_mask(mask, b, a); - assert_eq!(r, 0b00000100_00000100); - } + unsafe fn test_mm512_mask_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_and_epi32(a, 0, a, b); + assert_eq_m512i(r, a); - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - assert_eq!(_mm512_cmple_ps_mask(a, b), 0b00100101_00100101); + let r = _mm512_mask_and_epi32(a, 0b01111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100., - 0., 1., -1., f32::MAX, f32::NAN, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmple_ps_mask(mask, a, b), 0b00100000_00100000); + unsafe fn test_mm512_maskz_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_and_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_and_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let m = _mm512_cmpeq_ps_mask(b, a); - assert_eq!(m, 0b11001101_11001101); + unsafe fn test_mm512_and_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_and_epi32(a, b); + let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpeq_ps_mask(mask, b, a); - assert_eq!(r, 0b01001000_01001000); + unsafe fn test_mm512_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_or_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let m = _mm512_cmpneq_ps_mask(b, a); - assert_eq!(m, 0b00110010_00110010); + unsafe fn test_mm512_mask_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_or_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_or_epi32(a, 0b11111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, f32::NAN, -100.); - #[rustfmt::skip] - let b = _mm512_set_ps(0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100., - 0., 1., 13., 42., f32::MAX, f32::MIN, f32::NAN, -100.); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpneq_ps_mask(mask, b, a); - assert_eq!(r, 0b00110010_00110010) + unsafe fn test_mm512_maskz_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_or_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_or_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmp_ps_mask(a, b, _CMP_LT_OQ); - assert_eq!(m, 0b00000101_00000101); + unsafe fn test_mm512_or_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_or_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmp_ps_mask(mask, a, b, _CMP_LT_OQ); - assert_eq!(r, 0b00000100_00000100); + unsafe fn test_mm512_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_xor_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_round_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let m = _mm512_cmp_round_ps_mask(a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 0b00000101_00000101); - } + unsafe fn test_mm512_mask_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_xor_epi32(a, 0, a, b); + assert_eq_m512i(r, a); - #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_round_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100., - 0., 1., -1., 13., f32::MAX, f32::MIN, 100., -100.); - let b = _mm512_set1_ps(-1.); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmp_round_ps_mask(mask, a, b, _CMP_LT_OQ, _MM_FROUND_CUR_DIRECTION); - assert_eq!(r, 0b00000100_00000100); + let r = _mm512_mask_xor_epi32(a, 0b01111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let m = _mm512_cmpord_ps_mask(a, b); - assert_eq!(m, 0b00000101_00000101); + unsafe fn test_mm512_maskz_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_xor_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_xor_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let mask = 0b11000011_11000011; - let m = _mm512_mask_cmpord_ps_mask(mask, a, b); - assert_eq!(m, 0b00000001_00000001); + unsafe fn test_mm512_xor_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_xor_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpunord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let m = _mm512_cmpunord_ps_mask(a, b); - - assert_eq!(m, 0b11111010_11111010); + unsafe fn test_mm512_andnot_epi32() { + let a = _mm512_set1_epi32(0); + let b = _mm512_set1_epi32(1 << 3 | 1 << 4); + let r = _mm512_andnot_epi32(a, b); + let e = _mm512_set1_epi32(1 << 3 | 1 << 4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpunord_ps_mask() { - #[rustfmt::skip] - let a = _mm512_set_ps(f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, -1., f32::NAN, 0., - f32::NAN, f32::MAX, f32::NAN, f32::MIN, f32::NAN, 1., f32::NAN, 2.); - #[rustfmt::skip] - let b = _mm512_set_ps(f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 0., - f32::NAN, f32::NAN, f32::NAN, f32::NAN, f32::MIN, f32::MAX, -1., 2.); - let mask = 0b00001111_00001111; - let m = _mm512_mask_cmpunord_ps_mask(mask, a, b); - assert_eq!(m, 0b000001010_00001010); + unsafe fn test_mm512_mask_andnot_epi32() { + let a = _mm512_set1_epi32(1 << 1 | 1 << 2); + let b = _mm512_set1_epi32(1 << 3 | 1 << 4); + let r = _mm512_mask_andnot_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_andnot_epi32(a, 0b11111111_11111111, a, b); + let e = _mm512_set1_epi32(1 << 3 | 1 << 4); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_cmp_ss_mask(a, b, _CMP_GE_OS); - assert_eq!(m, 1); + unsafe fn test_mm512_maskz_andnot_epi32() { + let a = _mm512_set1_epi32(1 << 1 | 1 << 2); + let b = _mm512_set1_epi32(1 << 3 | 1 << 4); + let r = _mm512_maskz_andnot_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_andnot_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + 1 << 3 | 1 << 4, + 1 << 3 | 1 << 4, + 1 << 3 | 1 << 4, + 1 << 3 | 1 << 4, + 1 << 3 | 1 << 4, + 1 << 3 | 1 << 4, + 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_mask_cmp_ss_mask(0b10, a, b, _CMP_GE_OS); - assert_eq!(m, 0); - let m = _mm_mask_cmp_ss_mask(0b1, a, b, _CMP_GE_OS); - assert_eq!(m, 1); + unsafe fn test_mm512_kand() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b11001100_00110011; + let r = _mm512_kand(a, b); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_round_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_cmp_round_ss_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); + unsafe fn test_kand_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b11001100_00110011; + let r = _kand_mask16(a, b); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_round_ss_mask() { - let a = _mm_setr_ps(2., 1., 1., 1.); - let b = _mm_setr_ps(1., 2., 2., 2.); - let m = _mm_mask_cmp_round_ss_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 0); - let m = _mm_mask_cmp_round_ss_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); + unsafe fn test_mm512_kor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kor(a, b); + let e: u16 = 0b11101110_00111011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_cmp_sd_mask(a, b, _CMP_GE_OS); - assert_eq!(m, 1); + unsafe fn test_kor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kor_mask16(a, b); + let e: u16 = 0b11101110_00111011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_mask_cmp_sd_mask(0b10, a, b, _CMP_GE_OS); - assert_eq!(m, 0); - let m = _mm_mask_cmp_sd_mask(0b1, a, b, _CMP_GE_OS); - assert_eq!(m, 1); + unsafe fn test_mm512_kxor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kxor(a, b); + let e: u16 = 0b11100010_00111000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_cmp_round_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_cmp_round_sd_mask(a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); + unsafe fn test_kxor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kxor_mask16(a, b); + let e: u16 = 0b11100010_00111000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm_mask_cmp_round_sd_mask() { - let a = _mm_setr_pd(2., 1.); - let b = _mm_setr_pd(1., 2.); - let m = _mm_mask_cmp_round_sd_mask(0b10, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 0); - let m = _mm_mask_cmp_round_sd_mask(0b1, a, b, _CMP_GE_OS, _MM_FROUND_CUR_DIRECTION); - assert_eq!(m, 1); + unsafe fn test_mm512_knot() { + let a: u16 = 0b11001100_00110011; + let r = _mm512_knot(a); + let e: u16 = 0b00110011_11001100; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmplt_epu32_mask(a, b); - assert_eq!(m, 0b11001111_11001111); + unsafe fn test_knot_mask16() { + let a: u16 = 0b11001100_00110011; + let r = _knot_mask16(a); + let e: u16 = 0b00110011_11001100; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmplt_epu32_mask(mask, a, b); - assert_eq!(r, 0b01001010_01001010); + unsafe fn test_mm512_kandn() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kandn(a, b); + let e: u16 = 0b00100010_00001000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpgt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmpgt_epu32_mask(b, a); - assert_eq!(m, 0b11001111_11001111); + unsafe fn test_kandn_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kandn_mask16(a, b); + let e: u16 = 0b00100010_00001000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpgt_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpgt_epu32_mask(mask, b, a); - assert_eq!(r, 0b01001010_01001010); + unsafe fn test_mm512_kxnor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kxnor(a, b); + let e: u16 = 0b00011101_11000111; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmple_epu32_mask(a, b), - !_mm512_cmpgt_epu32_mask(a, b) - ) + unsafe fn test_kxnor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kxnor_mask16(a, b); + let e: u16 = 0b00011101_11000111; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!( - _mm512_mask_cmple_epu32_mask(mask, a, b), - 0b01111010_01111010 - ); + unsafe fn test_mm512_kmov() { + let a: u16 = 0b11001100_00110011; + let r = _mm512_kmov(a); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpge_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmpge_epu32_mask(a, b), - !_mm512_cmplt_epu32_mask(a, b) - ) + unsafe fn test_mm512_int2mask() { + let a: i32 = 0b11001100_00110011; + let r = _mm512_int2mask(a); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpge_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmpge_epu32_mask(mask, a, b), 0b01100000_0110000); + unsafe fn test_mm512_mask2int() { + let k1: __mmask16 = 0b11001100_00110011; + let r = _mm512_mask2int(k1); + let e: i32 = 0b11001100_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpeq_epu32_mask(b, a); - assert_eq!(m, 0b11001111_11001111); + unsafe fn test_mm512_kunpackb() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kunpackb(a, b); + let e: u16 = 0b00101110_00110011; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpeq_epu32_mask(mask, b, a); - assert_eq!(r, 0b01001010_01001010); + unsafe fn test_mm512_kortestc() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kortestc(a, b); + assert_eq!(r, 0); + let b: u16 = 0b11111111_11111111; + let r = _mm512_kortestc(a, b); + assert_eq!(r, 1); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpneq_epu32_mask(b, a); - assert_eq!(m, !_mm512_cmpeq_epu32_mask(b, a)); + unsafe fn test_mm512_test_epi32_mask() { + let a = _mm512_set1_epi32(1 << 0); + let b = _mm512_set1_epi32(1 << 0 | 1 << 1); + let r = _mm512_test_epi32_mask(a, b); + let e: __mmask16 = 0b11111111_11111111; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, -100, 100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpneq_epu32_mask(mask, b, a); - assert_eq!(r, 0b00110010_00110010); + unsafe fn test_mm512_mask_test_epi32_mask() { + let a = _mm512_set1_epi32(1 << 0); + let b = _mm512_set1_epi32(1 << 0 | 1 << 1); + let r = _mm512_mask_test_epi32_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_test_epi32_mask(0b11111111_11111111, a, b); + let e: __mmask16 = 0b11111111_11111111; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmp_epu32_mask(a, b, _MM_CMPINT_LT); - assert_eq!(m, 0b11001111_11001111); + unsafe fn test_mm512_testn_epi32_mask() { + let a = _mm512_set1_epi32(1 << 0); + let b = _mm512_set1_epi32(1 << 0 | 1 << 1); + let r = _mm512_testn_epi32_mask(a, b); + let e: __mmask16 = 0b00000000_00000000; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_epu32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); - assert_eq!(r, 0b01001010_01001010); + unsafe fn test_mm512_mask_testn_epi32_mask() { + let a = _mm512_set1_epi32(1 << 0); + let b = _mm512_set1_epi32(1 << 1); + let r = _mm512_mask_test_epi32_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_testn_epi32_mask(0b11111111_11111111, a, b); + let e: __mmask16 = 0b11111111_11111111; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmplt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmplt_epi32_mask(a, b); - assert_eq!(m, 0b00000101_00000101); + unsafe fn test_mm512_stream_ps() { + #[repr(align(32))] + struct Memory { + pub data: [f32; 16], + } + let a = _mm512_set1_ps(7.0); + let mut mem = Memory { data: [-1.0; 16] }; + + _mm512_stream_ps(&mut mem.data[0] as *mut f32, a); + for i in 0..16 { + assert_eq!(mem.data[i], get_m512(a, i)); + } } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmplt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmplt_epi32_mask(mask, a, b); - assert_eq!(r, 0b00000100_00000100); + unsafe fn test_mm512_reduce_add_epi32() { + let a = _mm512_set1_epi32(1); + let e: i32 = _mm512_reduce_add_epi32(a); + assert_eq!(16, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpgt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmpgt_epi32_mask(b, a); - assert_eq!(m, 0b00000101_00000101); + unsafe fn test_mm512_mask_reduce_add_epi32() { + let a = _mm512_set1_epi32(1); + let e: i32 = _mm512_mask_reduce_add_epi32(0b11111111_00000000, a); + assert_eq!(8, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpgt_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmpgt_epi32_mask(mask, b, a); - assert_eq!(r, 0b00000100_00000100); + unsafe fn test_mm512_reduce_add_ps() { + let a = _mm512_set1_ps(1.); + let e: f32 = _mm512_reduce_add_ps(a); + assert_eq!(16., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmple_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmple_epi32_mask(a, b), - !_mm512_cmpgt_epi32_mask(a, b) - ) + unsafe fn test_mm512_mask_reduce_add_ps() { + let a = _mm512_set1_ps(1.); + let e: f32 = _mm512_mask_reduce_add_ps(0b11111111_00000000, a); + assert_eq!(8., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmple_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!(_mm512_mask_cmple_epi32_mask(mask, a, b), 0b01100000_0110000); + unsafe fn test_mm512_reduce_mul_epi32() { + let a = _mm512_set1_epi32(2); + let e: i32 = _mm512_reduce_mul_epi32(a); + assert_eq!(65536, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpge_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - assert_eq!( - _mm512_cmpge_epi32_mask(a, b), - !_mm512_cmplt_epi32_mask(a, b) - ) + unsafe fn test_mm512_mask_reduce_mul_epi32() { + let a = _mm512_set1_epi32(2); + let e: i32 = _mm512_mask_reduce_mul_epi32(0b11111111_00000000, a); + assert_eq!(256, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpge_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, u32::MAX as i32, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01111010_01111010; - assert_eq!( - _mm512_mask_cmpge_epi32_mask(mask, a, b), - 0b01111010_01111010 - ); + unsafe fn test_mm512_reduce_mul_ps() { + let a = _mm512_set1_ps(2.); + let e: f32 = _mm512_reduce_mul_ps(a); + assert_eq!(65536., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpeq_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpeq_epi32_mask(b, a); - assert_eq!(m, 0b11001111_11001111); + unsafe fn test_mm512_mask_reduce_mul_ps() { + let a = _mm512_set1_ps(2.); + let e: f32 = _mm512_mask_reduce_mul_ps(0b11111111_00000000, a); + assert_eq!(256., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpeq_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpeq_epi32_mask(mask, b, a); - assert_eq!(r, 0b01001010_01001010); + unsafe fn test_mm512_reduce_max_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: i32 = _mm512_reduce_max_epi32(a); + assert_eq!(15, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmpneq_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let m = _mm512_cmpneq_epi32_mask(b, a); - assert_eq!(m, !_mm512_cmpeq_epi32_mask(b, a)); + unsafe fn test_mm512_mask_reduce_max_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: i32 = _mm512_mask_reduce_max_epi32(0b11111111_00000000, a); + assert_eq!(7, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmpneq_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100, - 0, 1, -1, 13, i32::MAX, i32::MIN, -100, 100); - #[rustfmt::skip] - let b = _mm512_set_epi32(0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100, - 0, 1, 13, 42, i32::MAX, i32::MIN, 100, -100); - let mask = 0b01111010_01111010; - let r = _mm512_mask_cmpneq_epi32_mask(mask, b, a); - assert_eq!(r, 0b00110010_00110010) + unsafe fn test_mm512_reduce_max_epu32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u32 = _mm512_reduce_max_epu32(a); + assert_eq!(15, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cmp_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let m = _mm512_cmp_epi32_mask(a, b, _MM_CMPINT_LT); - assert_eq!(m, 0b00000101_00000101); + unsafe fn test_mm512_mask_reduce_max_epu32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u32 = _mm512_mask_reduce_max_epu32(0b11111111_00000000, a); + assert_eq!(7, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cmp_epi32_mask() { - #[rustfmt::skip] - let a = _mm512_set_epi32(0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100, - 0, 1, -1, 13, i32::MAX, i32::MIN, 100, -100); - let b = _mm512_set1_epi32(-1); - let mask = 0b01100110_01100110; - let r = _mm512_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); - assert_eq!(r, 0b00000100_00000100); + unsafe fn test_mm512_reduce_max_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let e: f32 = _mm512_reduce_max_ps(a); + assert_eq!(15., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set_epi32() { - let r = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i( - r, - _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), - ) + unsafe fn test_mm512_mask_reduce_max_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let e: f32 = _mm512_mask_reduce_max_ps(0b11111111_00000000, a); + assert_eq!(7., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setr_epi32() { - let r = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m512i( - r, - _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), - ) + unsafe fn test_mm512_reduce_min_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: i32 = _mm512_reduce_min_epi32(a); + assert_eq!(0, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set1_epi32() { - let r = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, _mm512_set1_epi32(2)); + unsafe fn test_mm512_mask_reduce_min_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: i32 = _mm512_mask_reduce_min_epi32(0b11111111_00000000, a); + assert_eq!(0, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setzero_si512() { - assert_eq_m512i(_mm512_set1_epi32(0), _mm512_setzero_si512()); + unsafe fn test_mm512_reduce_min_epu32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u32 = _mm512_reduce_min_epu32(a); + assert_eq!(0, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set_ps() { - let r = _mm512_setr_ps( + unsafe fn test_mm512_mask_reduce_min_epu32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let e: u32 = _mm512_mask_reduce_min_epu32(0b11111111_00000000, a); + assert_eq!(0, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_min_ps() { + let a = _mm512_set_ps( 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - assert_eq_m512( - r, - _mm512_set_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ), - ) + let e: f32 = _mm512_reduce_min_ps(a); + assert_eq!(0., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setr_ps() { - let r = _mm512_set_ps( + unsafe fn test_mm512_mask_reduce_min_ps() { + let a = _mm512_set_ps( 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., ); - assert_eq_m512( - r, - _mm512_setr_ps( - 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., - ), - ) + let e: f32 = _mm512_mask_reduce_min_ps(0b11111111_00000000, a); + assert_eq!(0., e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set1_ps() { - #[rustfmt::skip] - let expected = _mm512_set_ps(2., 2., 2., 2., 2., 2., 2., 2., - 2., 2., 2., 2., 2., 2., 2., 2.); - assert_eq_m512(expected, _mm512_set1_ps(2.)); + unsafe fn test_mm512_reduce_and_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2); + let e: i32 = _mm512_reduce_and_epi32(a); + assert_eq!(0, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setzero_ps() { - assert_eq_m512(_mm512_setzero_ps(), _mm512_set1_ps(0.)); + unsafe fn test_mm512_mask_reduce_and_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2); + let e: i32 = _mm512_mask_reduce_and_epi32(0b11111111_00000000, a); + assert_eq!(1, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_loadu_pd() { - let a = &[4., 3., 2., 5., 8., 9., 64., 50.]; - let p = a.as_ptr(); - let r = _mm512_loadu_pd(black_box(p)); - let e = _mm512_setr_pd(4., 3., 2., 5., 8., 9., 64., 50.); - assert_eq_m512d(r, e); + unsafe fn test_mm512_reduce_or_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2); + let e: i32 = _mm512_reduce_or_epi32(a); + assert_eq!(3, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_storeu_pd() { - let a = _mm512_set1_pd(9.); - let mut r = _mm512_undefined_pd(); - _mm512_storeu_pd(&mut r as *mut _ as *mut f64, a); - assert_eq_m512d(r, a); + unsafe fn test_mm512_mask_reduce_or_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2); + let e: i32 = _mm512_mask_reduce_or_epi32(0b11111111_00000000, a); + assert_eq!(1, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_loadu_ps() { - let a = &[ - 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., - ]; - let p = a.as_ptr(); - let r = _mm512_loadu_ps(black_box(p)); - let e = _mm512_setr_ps( - 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., + unsafe fn test_mm512_mask_compress_epi32() { + let src = _mm512_set1_epi32(200); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_compress_epi32(src, 0b01010101_01010101, a); + let e = _mm512_set_epi32( + 200, 200, 200, 200, 200, 200, 200, 200, 1, 3, 5, 7, 9, 11, 13, 15, ); - assert_eq_m512(r, e); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_storeu_ps() { - let a = _mm512_set1_ps(9.); - let mut r = _mm512_undefined_ps(); - _mm512_storeu_ps(&mut r as *mut _ as *mut f32, a); - assert_eq_m512(r, a); + unsafe fn test_mm512_maskz_compress_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_compress_epi32(0b01010101_01010101, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, 11, 13, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_setr_pd() { - let r = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); - assert_eq_m512d(r, _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.)); + unsafe fn test_mm512_mask_compress_ps() { + let src = _mm512_set1_ps(200.); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_mask_compress_ps(src, 0b01010101_01010101, a); + let e = _mm512_set_ps( + 200., 200., 200., 200., 200., 200., 200., 200., 1., 3., 5., 7., 9., 11., 13., 15., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_set_pd() { - let r = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); - assert_eq_m512d(r, _mm512_set_pd(7., 6., 5., 4., 3., 2., 1., 0.)); + unsafe fn test_mm512_maskz_compress_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_maskz_compress_ps(0b01010101_01010101, a); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 3., 5., 7., 9., 11., 13., 15., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_rol_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r = _mm512_rol_epi32(a, 1); - let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + unsafe fn test_mm512_mask_expand_epi32() { + let src = _mm512_set1_epi32(200); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_expand_epi32(src, 0b01010101_01010101, a); + let e = _mm512_set_epi32( + 200, 8, 200, 9, 200, 10, 200, 11, 200, 12, 200, 13, 200, 14, 200, 15, + ); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_rol_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r = _mm512_mask_rol_epi32(a, 0, a, 1); - assert_eq_m512i(r, a); - - let r = _mm512_mask_rol_epi32(a, 0b11111111_11111111, a, 1); - let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + unsafe fn test_mm512_maskz_expand_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_expand_epi32(0b01010101_01010101, a); + let e = _mm512_set_epi32(0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_rol_epi32() { - let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); - let r = _mm512_maskz_rol_epi32(0, a, 1); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm512_mask_expand_ps() { + let src = _mm512_set1_ps(200.); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_mask_expand_ps(src, 0b01010101_01010101, a); + let e = _mm512_set_ps( + 200., 8., 200., 9., 200., 10., 200., 11., 200., 12., 200., 13., 200., 14., 200., 15., + ); + assert_eq_m512(r, e); + } - let r = _mm512_maskz_rol_epi32(0b00000000_11111111, a, 1); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_expand_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_maskz_expand_ps(0b01010101_01010101, a); + let e = _mm512_set_ps( + 0., 8., 0., 9., 0., 10., 0., 11., 0., 12., 0., 13., 0., 14., 0., 15., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_ror_epi32() { - let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let r = _mm512_ror_epi32(a, 1); - let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm512_loadu_epi32() { + let a = &[4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50]; + let p = a.as_ptr(); + let r = _mm512_loadu_epi32(black_box(p)); + let e = _mm512_setr_epi32(4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_ror_epi32() { - let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let r = _mm512_mask_ror_epi32(a, 0, a, 1); + unsafe fn test_mm512_storeu_epi32() { + let a = _mm512_set1_epi32(9); + let mut r = _mm512_undefined_epi32(); + _mm512_storeu_epi32(&mut r as *mut _ as *mut i32, a); assert_eq_m512i(r, a); + } - let r = _mm512_mask_ror_epi32(a, 0b11111111_11111111, a, 1); - let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_loadu_si512() { + let a = &[4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50]; + let p = a.as_ptr(); + let r = _mm512_loadu_si512(black_box(p)); + let e = _mm512_setr_epi32(4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_ror_epi32() { - let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); - let r = _mm512_maskz_ror_epi32(0, a, 1); - assert_eq_m512i(r, _mm512_setzero_si512()); - - let r = _mm512_maskz_ror_epi32(0b00000000_11111111, a, 1); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); - assert_eq_m512i(r, e); + unsafe fn test_mm512_storeu_si512() { + let a = _mm512_set1_epi32(9); + let mut r = _mm512_undefined_epi32(); + _mm512_storeu_si512(&mut r as *mut _ as *mut i32, a); + assert_eq_m512i(r, a); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_slli_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r = _mm512_slli_epi32(a, 1); - let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + unsafe fn test_mm512_load_si512() { + #[repr(align(64))] + struct Align { + data: [i32; 16], // 64 bytes + } + let a = Align { + data: [4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50], + }; + let p = (a.data).as_ptr(); + let r = _mm512_load_si512(black_box(p)); + let e = _mm512_setr_epi32(4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_slli_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let r = _mm512_mask_slli_epi32(a, 0, a, 1); + unsafe fn test_mm512_store_si512() { + let a = _mm512_set1_epi32(9); + let mut r = _mm512_undefined_epi32(); + _mm512_store_si512(&mut r as *mut _ as *mut i32, a); assert_eq_m512i(r, a); + } - let r = _mm512_mask_slli_epi32(a, 0b11111111_11111111, a, 1); - let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_load_epi32() { + #[repr(align(64))] + struct Align { + data: [i32; 16], // 64 bytes + } + let a = Align { + data: [4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50], + }; + let p = (a.data).as_ptr(); + let r = _mm512_load_epi32(black_box(p)); + let e = _mm512_setr_epi32(4, 3, 2, 5, 8, 9, 64, 50, -4, -3, -2, -5, -8, -9, -64, -50); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_slli_epi32() { - let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); - let r = _mm512_maskz_slli_epi32(0, a, 1); - assert_eq_m512i(r, _mm512_setzero_si512()); - - let r = _mm512_maskz_slli_epi32(0b00000000_11111111, a, 1); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm512_store_epi32() { + let a = _mm512_set1_epi32(9); + let mut r = _mm512_undefined_epi32(); + _mm512_store_epi32(&mut r as *mut _ as *mut i32, a); + assert_eq_m512i(r, a); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_srli_epi32() { - let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let r = _mm512_srli_epi32(a, 1); - let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - assert_eq_m512i(r, e); + unsafe fn test_mm512_load_ps() { + #[repr(align(64))] + struct Align { + data: [f32; 16], // 64 bytes + } + let a = Align { + data: [ + 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., + ], + }; + let p = (a.data).as_ptr(); + let r = _mm512_load_ps(black_box(p)); + let e = _mm512_setr_ps( + 4., 3., 2., 5., 8., 9., 64., 50., -4., -3., -2., -5., -8., -9., -64., -50., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_srli_epi32() { - let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let r = _mm512_mask_srli_epi32(a, 0, a, 1); - assert_eq_m512i(r, a); + unsafe fn test_mm512_store_ps() { + let a = _mm512_set1_ps(9.); + let mut r = _mm512_undefined_ps(); + _mm512_store_ps(&mut r as *mut _ as *mut f32, a); + assert_eq_m512(r, a); + } - let r = _mm512_mask_srli_epi32(a, 0b11111111_11111111, a, 1); - let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_set1_epi32() { + let src = _mm512_set1_epi32(2); + let a: i32 = 11; + let r = _mm512_mask_set1_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_set1_epi32(src, 0b11111111_11111111, a); + let e = _mm512_set1_epi32(11); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_srli_epi32() { - let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); - let r = _mm512_maskz_srli_epi32(0, a, 1); + unsafe fn test_mm512_maskz_set1_epi32() { + let a: i32 = 11; + let r = _mm512_maskz_set1_epi32(0, a); assert_eq_m512i(r, _mm512_setzero_si512()); - - let r = _mm512_maskz_srli_epi32(0b00000000_11111111, a, 1); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0 << 31); + let r = _mm512_maskz_set1_epi32(0b11111111_11111111, a); + let e = _mm512_set1_epi32(11); assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_rolv_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - - let r = _mm512_rolv_epi32(a, b); - - let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_move_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_move_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_move_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 40.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_rolv_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - - let r = _mm512_mask_rolv_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - - let r = _mm512_mask_rolv_epi32(a, 0b11111111_11111111, a, b); - - let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_move_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_move_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_move_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 40.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_rolv_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); - let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_mask_move_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_move_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_move_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., 4.); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_rolv_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_move_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_move_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_move_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 4.); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_rolv_epi32(0b00000000_11111111, a, b); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_add_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_add_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_add_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 60.); + assert_eq_m128(r, e); + } - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_add_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_add_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_add_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 60.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_rorv_epi32() { - let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_mask_add_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_add_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_add_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., 6.); + assert_eq_m128d(r, e); + } - let r = _mm512_rorv_epi32(a, b); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_add_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_add_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_add_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 6.); + assert_eq_m128d(r, e); + } - let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_sub_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_sub_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_sub_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., -20.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_rorv_epi32() { - let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_maskz_sub_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_sub_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_sub_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., -20.); + assert_eq_m128(r, e); + } - let r = _mm512_mask_rorv_epi32(a, 0, a, b); - assert_eq_m512i(r, a); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_sub_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_sub_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_sub_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., -2.); + assert_eq_m128d(r, e); + } - let r = _mm512_mask_rorv_epi32(a, 0b11111111_11111111, a, b); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_sub_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_sub_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_sub_sd(0b11111111, a, b); + let e = _mm_set_pd(1., -2.); + assert_eq_m128d(r, e); + } - let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_mul_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_mul_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_mul_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 800.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_rorv_epi32() { - let a = _mm512_set_epi32(3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); - let b = _mm512_set_epi32(2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_maskz_mul_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_mul_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_mul_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 800.); + assert_eq_m128(r, e); + } - let r = _mm512_maskz_rorv_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_mul_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_mul_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_mul_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_rorv_epi32(0b00000000_11111111, a, b); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_mul_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_mul_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_mul_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); + } - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_div_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_div_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_div_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sllv_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_maskz_div_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_div_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_div_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); + } - let r = _mm512_sllv_epi32(a, count); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_div_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_div_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_div_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); + } - let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_div_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_div_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_div_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sllv_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_mask_max_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_mask_max_ss(a, 0, a, b); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); + let r = _mm_mask_max_ss(a, 0b11111111, a, b); + let e = _mm_set_ps(0., 1., 2., 7.); + assert_eq_m128(r, e); + } - let r = _mm512_mask_sllv_epi32(a, 0, a, count); - assert_eq_m512i(r, a); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_max_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_maskz_max_ss(0, a, b); + let e = _mm_set_ps(0., 1., 2., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_max_ss(0b11111111, a, b); + let e = _mm_set_ps(0., 1., 2., 7.); + assert_eq_m128(r, e); + } - let r = _mm512_mask_sllv_epi32(a, 0b11111111_11111111, a, count); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_max_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_mask_max_sd(a, 0, a, b); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); + let r = _mm_mask_max_sd(a, 0b11111111, a, b); + let e = _mm_set_pd(0., 3.); + assert_eq_m128d(r, e); + } - let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_max_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_maskz_max_sd(0, a, b); + let e = _mm_set_pd(0., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_max_sd(0b11111111, a, b); + let e = _mm_set_pd(0., 3.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sllv_epi32() { - let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); - let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_mask_min_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_mask_min_ss(a, 0, a, b); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); + let r = _mm_mask_min_ss(a, 0b11111111, a, b); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); + } - let r = _mm512_maskz_sllv_epi32(0, a, count); - assert_eq_m512i(r, _mm512_setzero_si512()); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_min_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_maskz_min_ss(0, a, b); + let e = _mm_set_ps(0., 1., 2., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_min_ss(0b11111111, a, b); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); + } - let r = _mm512_maskz_sllv_epi32(0b00000000_11111111, a, count); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_min_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_mask_min_sd(a, 0, a, b); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); + let r = _mm_mask_min_sd(a, 0b11111111, a, b); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); + } - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_min_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_maskz_min_sd(0, a, b); + let e = _mm_set_pd(0., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_min_sd(0b11111111, a, b); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_srlv_epi32() { - let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_mask_sqrt_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_mask_sqrt_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_sqrt_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 2.); + assert_eq_m128(r, e); + } - let r = _mm512_srlv_epi32(a, count); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_sqrt_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_maskz_sqrt_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_sqrt_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 2.); + assert_eq_m128(r, e); + } - let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_sqrt_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_sqrt_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_sqrt_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., 2.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_srlv_epi32() { - let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); - let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_maskz_sqrt_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_sqrt_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_sqrt_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 2.); + assert_eq_m128d(r, e); + } - let r = _mm512_mask_srlv_epi32(a, 0, a, count); - assert_eq_m512i(r, a); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_rsqrt14_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_rsqrt14_ss(a, b); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); + } - let r = _mm512_mask_srlv_epi32(a, 0b11111111_11111111, a, count); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_rsqrt14_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_mask_rsqrt14_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_rsqrt14_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); + } - let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_rsqrt14_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_maskz_rsqrt14_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_rsqrt14_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_srlv_epi32() { - let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); - let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + unsafe fn test_mm_rsqrt14_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_rsqrt14_sd(a, b); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_srlv_epi32(0, a, count); - assert_eq_m512i(r, _mm512_setzero_si512()); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_rsqrt14_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_rsqrt14_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_rsqrt14_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_srlv_epi32(0b00000000_11111111, a, count); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_rsqrt14_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_rsqrt14_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_rsqrt14_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); + } - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_rcp14_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_rcp14_ss(a, b); + let e = _mm_set_ps(1., 2., 10., 0.25); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sll_epi32() { - let a = _mm512_set_epi32( - 1 << 31, - 1 << 0, - 1 << 1, - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - let count = _mm_set_epi32(0, 0, 0, 2); - let r = _mm512_sll_epi32(a, count); - let e = _mm512_set_epi32( - 0, - 1 << 2, - 1 << 3, - 1 << 4, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_rcp14_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_mask_rcp14_ss(src, 0, a, b); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_rcp14_ss(src, 0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 0.25); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sll_epi32() { - let a = _mm512_set_epi32( - 1 << 31, - 1 << 0, - 1 << 1, - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - let count = _mm_set_epi32(0, 0, 0, 2); - let r = _mm512_mask_sll_epi32(a, 0, a, count); - assert_eq_m512i(r, a); + unsafe fn test_mm_maskz_rcp14_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_maskz_rcp14_ss(0, a, b); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_rcp14_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 2., 10., 0.25); + assert_eq_m128(r, e); + } - let r = _mm512_mask_sll_epi32(a, 0b11111111_11111111, a, count); - let e = _mm512_set_epi32( - 0, - 1 << 2, - 1 << 3, - 1 << 4, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_rcp14_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_rcp14_sd(a, b); + let e = _mm_set_pd(1., 0.25); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sll_epi32() { - let a = _mm512_set_epi32( - 1 << 31, - 1 << 0, - 1 << 1, - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 31, - ); - let count = _mm_set_epi32(2, 0, 0, 2); - let r = _mm512_maskz_sll_epi32(0, a, count); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm_mask_rcp14_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_rcp14_sd(src, 0, a, b); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_rcp14_sd(src, 0b11111111, a, b); + let e = _mm_set_pd(1., 0.25); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_rcp14_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_rcp14_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_rcp14_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 0.25); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_sll_epi32(0b00000000_11111111, a, count); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_getexp_ss() { + let a = _mm_set1_ps(2.); + let b = _mm_set1_ps(3.); + let r = _mm_getexp_ss(a, b); + let e = _mm_set_ps(2., 2., 2., 1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_srl_epi32() { - let a = _mm512_set_epi32( - 1 << 31, - 1 << 0, - 1 << 1, - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - let count = _mm_set_epi32(0, 0, 0, 2); - let r = _mm512_srl_epi32(a, count); - let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_getexp_ss() { + let a = _mm_set1_ps(2.); + let b = _mm_set1_ps(3.); + let r = _mm_mask_getexp_ss(a, 0, a, b); + let e = _mm_set_ps(2., 2., 2., 2.); + assert_eq_m128(r, e); + let r = _mm_mask_getexp_ss(a, 0b11111111, a, b); + let e = _mm_set_ps(2., 2., 2., 1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_srl_epi32() { - let a = _mm512_set_epi32( - 1 << 31, - 1 << 0, - 1 << 1, - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ); - let count = _mm_set_epi32(0, 0, 0, 2); - let r = _mm512_mask_srl_epi32(a, 0, a, count); - assert_eq_m512i(r, a); + unsafe fn test_mm_maskz_getexp_ss() { + let a = _mm_set1_ps(2.); + let b = _mm_set1_ps(3.); + let r = _mm_maskz_getexp_ss(0, a, b); + let e = _mm_set_ps(2., 2., 2., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_getexp_ss(0b11111111, a, b); + let e = _mm_set_ps(2., 2., 2., 1.); + assert_eq_m128(r, e); + } - let r = _mm512_mask_srl_epi32(a, 0b11111111_11111111, a, count); - let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_getexp_sd() { + let a = _mm_set1_pd(2.); + let b = _mm_set1_pd(3.); + let r = _mm_getexp_sd(a, b); + let e = _mm_set_pd(2., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_srl_epi32() { - let a = _mm512_set_epi32( - 1 << 31, - 1 << 0, - 1 << 1, - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 31, - ); - let count = _mm_set_epi32(2, 0, 0, 2); - let r = _mm512_maskz_srl_epi32(0, a, count); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm_mask_getexp_sd() { + let a = _mm_set1_pd(2.); + let b = _mm_set1_pd(3.); + let r = _mm_mask_getexp_sd(a, 0, a, b); + let e = _mm_set_pd(2., 2.); + assert_eq_m128d(r, e); + let r = _mm_mask_getexp_sd(a, 0b11111111, a, b); + let e = _mm_set_pd(2., 1.); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_srl_epi32(0b00000000_11111111, a, count); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 29); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_getexp_sd() { + let a = _mm_set1_pd(2.); + let b = _mm_set1_pd(3.); + let r = _mm_maskz_getexp_sd(0, a, b); + let e = _mm_set_pd(2., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_getexp_sd(0b11111111, a, b); + let e = _mm_set_pd(2., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sra_epi32() { - let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - let count = _mm_set_epi32(1, 0, 0, 2); - let r = _mm512_sra_epi32(a, count); - let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm_getmant_ss() { + let a = _mm_set1_ps(20.); + let b = _mm_set1_ps(10.); + let r = _mm_getmant_ss(a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_ps(20., 20., 20., 1.25); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sra_epi32() { - let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); - let count = _mm_set_epi32(0, 0, 0, 2); - let r = _mm512_mask_sra_epi32(a, 0, a, count); - assert_eq_m512i(r, a); + unsafe fn test_mm_mask_getmant_ss() { + let a = _mm_set1_ps(20.); + let b = _mm_set1_ps(10.); + let r = _mm_mask_getmant_ss(a, 0, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_ps(20., 20., 20., 20.); + assert_eq_m128(r, e); + let r = _mm_mask_getmant_ss(a, 0b11111111, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_ps(20., 20., 20., 1.25); + assert_eq_m128(r, e); + } - let r = _mm512_mask_sra_epi32(a, 0b11111111_11111111, a, count); - let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_getmant_ss() { + let a = _mm_set1_ps(20.); + let b = _mm_set1_ps(10.); + let r = _mm_maskz_getmant_ss(0, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_ps(20., 20., 20., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_getmant_ss(0b11111111, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_ps(20., 20., 20., 1.25); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sra_epi32() { - let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); - let count = _mm_set_epi32(2, 0, 0, 2); - let r = _mm512_maskz_sra_epi32(0, a, count); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm_getmant_sd() { + let a = _mm_set1_pd(20.); + let b = _mm_set1_pd(10.); + let r = _mm_getmant_sd(a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_pd(20., 1.25); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_sra_epi32(0b00000000_11111111, a, count); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_getmant_sd() { + let a = _mm_set1_pd(20.); + let b = _mm_set1_pd(10.); + let r = _mm_mask_getmant_sd(a, 0, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_pd(20., 20.); + assert_eq_m128d(r, e); + let r = _mm_mask_getmant_sd(a, 0b11111111, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_pd(20., 1.25); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_srav_epi32() { - let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - let r = _mm512_srav_epi32(a, count); - let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_getmant_sd() { + let a = _mm_set1_pd(20.); + let b = _mm_set1_pd(10.); + let r = _mm_maskz_getmant_sd(0, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_pd(20., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_getmant_sd(0b11111111, a, b, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm_set_pd(20., 1.25); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_srav_epi32() { - let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); - let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - let r = _mm512_mask_srav_epi32(a, 0, a, count); - assert_eq_m512i(r, a); + unsafe fn test_mm_roundscale_ss() { + let a = _mm_set1_ps(2.2); + let b = _mm_set1_ps(1.1); + let r = _mm_roundscale_ss(a, b, 0); + let e = _mm_set_ps(2.2, 2.2, 2.2, 1.0); + assert_eq_m128(r, e); + } - let r = _mm512_mask_srav_epi32(a, 0b11111111_11111111, a, count); - let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_roundscale_ss() { + let a = _mm_set1_ps(2.2); + let b = _mm_set1_ps(1.1); + let r = _mm_mask_roundscale_ss(a, 0, a, b, 0); + let e = _mm_set_ps(2.2, 2.2, 2.2, 2.2); + assert_eq_m128(r, e); + let r = _mm_mask_roundscale_ss(a, 0b11111111, a, b, 0); + let e = _mm_set_ps(2.2, 2.2, 2.2, 1.0); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_srav_epi32() { - let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); - let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2); - let r = _mm512_maskz_srav_epi32(0, a, count); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm_maskz_roundscale_ss() { + let a = _mm_set1_ps(2.2); + let b = _mm_set1_ps(1.1); + let r = _mm_maskz_roundscale_ss(0, a, b, 0); + let e = _mm_set_ps(2.2, 2.2, 2.2, 0.0); + assert_eq_m128(r, e); + let r = _mm_maskz_roundscale_ss(0b11111111, a, b, 0); + let e = _mm_set_ps(2.2, 2.2, 2.2, 1.0); + assert_eq_m128(r, e); + } - let r = _mm512_maskz_srav_epi32(0b00000000_11111111, a, count); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_roundscale_sd() { + let a = _mm_set1_pd(2.2); + let b = _mm_set1_pd(1.1); + let r = _mm_roundscale_sd(a, b, 0); + let e = _mm_set_pd(2.2, 1.0); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_srai_epi32() { - let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, -15); - let r = _mm512_srai_epi32(a, 2); - let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_roundscale_sd() { + let a = _mm_set1_pd(2.2); + let b = _mm_set1_pd(1.1); + let r = _mm_mask_roundscale_sd(a, 0, a, b, 0); + let e = _mm_set_pd(2.2, 2.2); + assert_eq_m128d(r, e); + let r = _mm_mask_roundscale_sd(a, 0b11111111, a, b, 0); + let e = _mm_set_pd(2.2, 1.0); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_srai_epi32() { - let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); - let r = _mm512_mask_srai_epi32(a, 0, a, 2); - assert_eq_m512i(r, a); + unsafe fn test_mm_maskz_roundscale_sd() { + let a = _mm_set1_pd(2.2); + let b = _mm_set1_pd(1.1); + let r = _mm_maskz_roundscale_sd(0, a, b, 0); + let e = _mm_set_pd(2.2, 0.0); + assert_eq_m128d(r, e); + let r = _mm_maskz_roundscale_sd(0b11111111, a, b, 0); + let e = _mm_set_pd(2.2, 1.0); + assert_eq_m128d(r, e); + } - let r = _mm512_mask_srai_epi32(a, 0b11111111_11111111, a, 2); - let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_scalef_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(3.); + let r = _mm_scalef_ss(a, b); + let e = _mm_set_ps(1., 1., 1., 8.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_srai_epi32() { - let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); - let r = _mm512_maskz_srai_epi32(0, a, 2); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm_mask_scalef_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(3.); + let r = _mm_mask_scalef_ss(a, 0, a, b); + let e = _mm_set_ps(1., 1., 1., 1.); + assert_eq_m128(r, e); + let r = _mm_mask_scalef_ss(a, 0b11111111, a, b); + let e = _mm_set_ps(1., 1., 1., 8.); + assert_eq_m128(r, e); + } - let r = _mm512_maskz_srai_epi32(0b00000000_11111111, a, 2); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_scalef_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(3.); + let r = _mm_maskz_scalef_ss(0, a, b); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_scalef_ss(0b11111111, a, b); + let e = _mm_set_ps(1., 1., 1., 8.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_permute_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let r = _mm512_permute_ps(a, 1); - let e = _mm512_set_ps( - 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_scalef_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(3.); + let r = _mm_scalef_sd(a, b); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_permute_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let r = _mm512_mask_permute_ps(a, 0b00000000_00000000, a, 1); - assert_eq_m512(r, a); - let r = _mm512_mask_permute_ps(a, 0b11111111_11111111, a, 1); - let e = _mm512_set_ps( - 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_scalef_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(3.); + let r = _mm_mask_scalef_sd(a, 0, a, b); + let e = _mm_set_pd(1., 1.); + assert_eq_m128d(r, e); + let r = _mm_mask_scalef_sd(a, 0b11111111, a, b); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_permute_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let r = _mm512_maskz_permute_ps(0, a, 1); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_permute_ps(0b00000000_11111111, a, 1); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_scalef_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(3.); + let r = _mm_maskz_scalef_sd(0, a, b); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_scalef_sd(0b11111111, a, b); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_permutevar_epi32() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let r = _mm512_permutevar_epi32(idx, a); - let e = _mm512_set1_epi32(14); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_fmadd_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fmadd_ss(a, 0, b, c); + assert_eq_m128(r, a); + let r = _mm_mask_fmadd_ss(a, 0b11111111, b, c); + let e = _mm_set_ps(1., 1., 1., 5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_permutevar_epi32() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let r = _mm512_mask_permutevar_epi32(a, 0, idx, a); - assert_eq_m512i(r, a); - let r = _mm512_mask_permutevar_epi32(a, 0b11111111_11111111, idx, a); - let e = _mm512_set1_epi32(14); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_fmadd_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_maskz_fmadd_ss(0, a, b, c); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fmadd_ss(0b11111111, a, b, c); + let e = _mm_set_ps(1., 1., 1., 5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_permutevar_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_permutevar_ps(a, b); - let e = _mm512_set_ps( - 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask3_fmadd_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask3_fmadd_ss(a, b, c, 0); + assert_eq_m128(r, c); + let r = _mm_mask3_fmadd_ss(a, b, c, 0b11111111); + let e = _mm_set_ps(3., 3., 3., 5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_permutevar_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_mask_permutevar_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_permutevar_ps(a, 0b11111111_11111111, a, b); - let e = _mm512_set_ps( - 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_fmadd_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fmadd_sd(a, 0, b, c); + assert_eq_m128d(r, a); + let r = _mm_mask_fmadd_sd(a, 0b11111111, b, c); + let e = _mm_set_pd(1., 5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fmadd_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_maskz_fmadd_sd(0, a, b, c); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fmadd_sd(0b11111111, a, b, c); + let e = _mm_set_pd(1., 5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fmadd_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask3_fmadd_sd(a, b, c, 0); + assert_eq_m128d(r, c); + let r = _mm_mask3_fmadd_sd(a, b, c, 0b11111111); + let e = _mm_set_pd(3., 5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fmsub_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fmsub_ss(a, 0, b, c); + assert_eq_m128(r, a); + let r = _mm_mask_fmsub_ss(a, 0b11111111, b, c); + let e = _mm_set_ps(1., 1., 1., -1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_permutevar_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let b = _mm512_set1_epi32(1); - let r = _mm512_maskz_permutevar_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_permutevar_ps(0b00000000_11111111, a, b); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_fmsub_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_maskz_fmsub_ss(0, a, b, c); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fmsub_ss(0b11111111, a, b, c); + let e = _mm_set_ps(1., 1., 1., -1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_permutexvar_epi32() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let r = _mm512_permutexvar_epi32(idx, a); - let e = _mm512_set1_epi32(14); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask3_fmsub_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask3_fmsub_ss(a, b, c, 0); + assert_eq_m128(r, c); + let r = _mm_mask3_fmsub_ss(a, b, c, 0b11111111); + let e = _mm_set_ps(3., 3., 3., -1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_permutexvar_epi32() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let r = _mm512_mask_permutexvar_epi32(a, 0, idx, a); - assert_eq_m512i(r, a); - let r = _mm512_mask_permutexvar_epi32(a, 0b11111111_11111111, idx, a); - let e = _mm512_set1_epi32(14); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_fmsub_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fmsub_sd(a, 0, b, c); + assert_eq_m128d(r, a); + let r = _mm_mask_fmsub_sd(a, 0b11111111, b, c); + let e = _mm_set_pd(1., -1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_permutexvar_epi32() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let r = _mm512_maskz_permutexvar_epi32(0, idx, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_permutexvar_epi32(0b00000000_11111111, idx, a); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_fmsub_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_maskz_fmsub_sd(0, a, b, c); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fmsub_sd(0b11111111, a, b, c); + let e = _mm_set_pd(1., -1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_permutexvar_ps() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let r = _mm512_permutexvar_ps(idx, a); - let e = _mm512_set1_ps(14.); - assert_eq_m512(r, e); + unsafe fn test_mm_mask3_fmsub_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask3_fmsub_sd(a, b, c, 0); + assert_eq_m128d(r, c); + let r = _mm_mask3_fmsub_sd(a, b, c, 0b11111111); + let e = _mm_set_pd(3., -1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_permutexvar_ps() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let r = _mm512_mask_permutexvar_ps(a, 0, idx, a); - assert_eq_m512(r, a); - let r = _mm512_mask_permutexvar_ps(a, 0b11111111_11111111, idx, a); - let e = _mm512_set1_ps(14.); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_fnmadd_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fnmadd_ss(a, 0, b, c); + assert_eq_m128(r, a); + let r = _mm_mask_fnmadd_ss(a, 0b11111111, b, c); + let e = _mm_set_ps(1., 1., 1., 1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_permutexvar_ps() { - let idx = _mm512_set1_epi32(1); - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let r = _mm512_maskz_permutexvar_ps(0, idx, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_permutexvar_ps(0b00000000_11111111, idx, a); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 14., 14., 14., 14., 14., 14., 14., 14., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_fnmadd_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_maskz_fnmadd_ss(0, a, b, c); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fnmadd_ss(0b11111111, a, b, c); + let e = _mm_set_ps(1., 1., 1., 1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_permutex2var_epi32() { - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let idx = _mm512_set_epi32( - 1, - 1 << 4, - 2, - 1 << 4, - 3, - 1 << 4, - 4, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_epi32(100); - let r = _mm512_permutex2var_epi32(a, idx, b); - let e = _mm512_set_epi32( - 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask3_fnmadd_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask3_fnmadd_ss(a, b, c, 0); + assert_eq_m128(r, c); + let r = _mm_mask3_fnmadd_ss(a, b, c, 0b11111111); + let e = _mm_set_ps(3., 3., 3., 1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_permutex2var_epi32() { - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let idx = _mm512_set_epi32( - 1, - 1 << 4, - 2, - 1 << 4, - 3, - 1 << 4, - 4, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_epi32(100); - let r = _mm512_mask_permutex2var_epi32(a, 0, idx, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_permutex2var_epi32(a, 0b11111111_11111111, idx, b); - let e = _mm512_set_epi32( - 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_fnmadd_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fnmadd_sd(a, 0, b, c); + assert_eq_m128d(r, a); + let r = _mm_mask_fnmadd_sd(a, 0b11111111, b, c); + let e = _mm_set_pd(1., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_permutex2var_epi32() { - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let idx = _mm512_set_epi32( - 1, - 1 << 4, - 2, - 1 << 4, - 3, - 1 << 4, - 4, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_epi32(100); - let r = _mm512_maskz_permutex2var_epi32(0, a, idx, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_permutex2var_epi32(0b00000000_11111111, a, idx, b); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 10, 100, 9, 100, 8, 100, 7, 100); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_fnmadd_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_maskz_fnmadd_sd(0, a, b, c); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fnmadd_sd(0b11111111, a, b, c); + let e = _mm_set_pd(1., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask2_permutex2var_epi32() { - let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - let idx = _mm512_set_epi32( - 1000, - 1 << 4, - 2000, - 1 << 4, - 3000, - 1 << 4, - 4000, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_epi32(100); - let r = _mm512_mask2_permutex2var_epi32(a, idx, 0, b); - assert_eq_m512i(r, idx); - let r = _mm512_mask2_permutex2var_epi32(a, idx, 0b00000000_11111111, b); - let e = _mm512_set_epi32( - 1000, - 1 << 4, - 2000, - 1 << 4, - 3000, - 1 << 4, - 4000, - 1 << 4, - 10, - 100, - 9, - 100, - 8, - 100, - 7, - 100, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask3_fnmadd_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask3_fnmadd_sd(a, b, c, 0); + assert_eq_m128d(r, c); + let r = _mm_mask3_fnmadd_sd(a, b, c, 0b11111111); + let e = _mm_set_pd(3., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_permutex2var_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let idx = _mm512_set_epi32( - 1, - 1 << 4, - 2, - 1 << 4, - 3, - 1 << 4, - 4, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_ps(100.); - let r = _mm512_permutex2var_ps(a, idx, b); - let e = _mm512_set_ps( - 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_fnmsub_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fnmsub_ss(a, 0, b, c); + assert_eq_m128(r, a); + let r = _mm_mask_fnmsub_ss(a, 0b11111111, b, c); + let e = _mm_set_ps(1., 1., 1., -5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_permutex2var_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let idx = _mm512_set_epi32( - 1, - 1 << 4, - 2, - 1 << 4, - 3, - 1 << 4, - 4, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_ps(100.); - let r = _mm512_mask_permutex2var_ps(a, 0, idx, b); - assert_eq_m512(r, a); - let r = _mm512_mask_permutex2var_ps(a, 0b11111111_11111111, idx, b); - let e = _mm512_set_ps( - 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_fnmsub_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_maskz_fnmsub_ss(0, a, b, c); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fnmsub_ss(0b11111111, a, b, c); + let e = _mm_set_ps(1., 1., 1., -5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_permutex2var_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let idx = _mm512_set_epi32( - 1, - 1 << 4, - 2, - 1 << 4, - 3, - 1 << 4, - 4, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_ps(100.); - let r = _mm512_maskz_permutex2var_ps(0, a, idx, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_permutex2var_ps(0b00000000_11111111, a, idx, b); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask3_fnmsub_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask3_fnmsub_ss(a, b, c, 0); + assert_eq_m128(r, c); + let r = _mm_mask3_fnmsub_ss(a, b, c, 0b11111111); + let e = _mm_set_ps(3., 3., 3., -5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask2_permutex2var_ps() { - let a = _mm512_set_ps( - 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., - ); - let idx = _mm512_set_epi32( - 1, - 1 << 4, - 2, - 1 << 4, - 3, - 1 << 4, - 4, - 1 << 4, - 5, - 1 << 4, - 6, - 1 << 4, - 7, - 1 << 4, - 8, - 1 << 4, - ); - let b = _mm512_set1_ps(100.); - let r = _mm512_mask2_permutex2var_ps(a, idx, 0, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_mask2_permutex2var_ps(a, idx, 0b00000000_11111111, b); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_fnmsub_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fnmsub_sd(a, 0, b, c); + assert_eq_m128d(r, a); + let r = _mm_mask_fnmsub_sd(a, 0b11111111, b, c); + let e = _mm_set_pd(1., -5.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_shuffle_epi32() { - let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); - let r = _mm512_shuffle_epi32(a, _MM_PERM_AADD); - let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_fnmsub_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_maskz_fnmsub_sd(0, a, b, c); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fnmsub_sd(0b11111111, a, b, c); + let e = _mm_set_pd(1., -5.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_shuffle_epi32() { - let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); - let r = _mm512_mask_shuffle_epi32(a, 0, a, _MM_PERM_AADD); - assert_eq_m512i(r, a); - let r = _mm512_mask_shuffle_epi32(a, 0b11111111_11111111, a, _MM_PERM_AADD); - let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask3_fnmsub_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask3_fnmsub_sd(a, b, c, 0); + assert_eq_m128d(r, c); + let r = _mm_mask3_fnmsub_sd(a, b, c, 0b11111111); + let e = _mm_set_pd(3., -5.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_shuffle_epi32() { - let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); - let r = _mm512_maskz_shuffle_epi32(0, a, _MM_PERM_AADD); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_shuffle_epi32(0b00000000_11111111, a, _MM_PERM_AADD); - let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm_add_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_add_round_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 60.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_shuffle_ps() { - let a = _mm512_setr_ps( - 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., - ); - let b = _mm512_setr_ps( - 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., - ); - let r = _mm512_shuffle_ps(a, b, 0x0F); - let e = _mm512_setr_ps( - 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., + unsafe fn test_mm_mask_add_round_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_add_round_ss(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_add_round_ss( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, ); - assert_eq_m512(r, e); + let e = _mm_set_ps(1., 2., 10., 60.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_shuffle_ps() { - let a = _mm512_setr_ps( - 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., - ); - let b = _mm512_setr_ps( - 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., - ); - let r = _mm512_mask_shuffle_ps(a, 0, a, b, 0x0F); - assert_eq_m512(r, a); - let r = _mm512_mask_shuffle_ps(a, 0b11111111_11111111, a, b, 0x0F); - let e = _mm512_setr_ps( - 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_add_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_add_round_ss(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_add_round_ss(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 60.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_shuffle_ps() { - let a = _mm512_setr_ps( - 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., - ); - let b = _mm512_setr_ps( - 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., - ); - let r = _mm512_maskz_shuffle_ps(0, a, b, 0x0F); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_shuffle_ps(0b00000000_11111111, a, b, 0x0F); - let e = _mm512_setr_ps( - 8., 8., 2., 2., 16., 16., 10., 10., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_add_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_add_round_sd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 6.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_shuffle_i32x4() { - let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); - let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); - let r = _mm512_shuffle_i32x4(a, b, 0b00000000); - let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_add_round_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_add_round_sd(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_add_round_sd( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + ); + let e = _mm_set_pd(1., 6.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_shuffle_i32x4() { - let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); - let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); - let r = _mm512_mask_shuffle_i32x4(a, 0, a, b, 0b00000000); - assert_eq_m512i(r, a); - let r = _mm512_mask_shuffle_i32x4(a, 0b11111111_11111111, a, b, 0b00000000); - let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_add_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_add_round_sd(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_add_round_sd(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 6.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_shuffle_i32x4() { - let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); - let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); - let r = _mm512_maskz_shuffle_i32x4(0, a, b, 0b00000000); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_shuffle_i32x4(0b00000000_11111111, a, b, 0b00000000); - let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm_sub_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_sub_round_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., -20.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_shuffle_f32x4() { - let a = _mm512_setr_ps( - 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., - ); - let b = _mm512_setr_ps( - 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., - ); - let r = _mm512_shuffle_f32x4(a, b, 0b00000000); - let e = _mm512_setr_ps( - 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., + unsafe fn test_mm_mask_sub_round_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_sub_round_ss(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_sub_round_ss( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, ); - assert_eq_m512(r, e); + let e = _mm_set_ps(1., 2., 10., -20.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_shuffle_f32x4() { - let a = _mm512_setr_ps( - 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., - ); - let b = _mm512_setr_ps( - 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., - ); - let r = _mm512_mask_shuffle_f32x4(a, 0, a, b, 0b00000000); - assert_eq_m512(r, a); - let r = _mm512_mask_shuffle_f32x4(a, 0b11111111_11111111, a, b, 0b00000000); - let e = _mm512_setr_ps( - 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_sub_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_sub_round_ss(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_sub_round_ss(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., -20.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_shuffle_f32x4() { - let a = _mm512_setr_ps( - 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., - ); - let b = _mm512_setr_ps( - 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., - ); - let r = _mm512_maskz_shuffle_f32x4(0, a, b, 0b00000000); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_shuffle_f32x4(0b00000000_11111111, a, b, 0b00000000); - let e = _mm512_setr_ps( - 1., 4., 5., 8., 1., 4., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_sub_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_sub_round_sd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., -2.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_extractf32x4_ps() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + unsafe fn test_mm_mask_sub_round_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_sub_round_sd(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_sub_round_sd( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, ); - let r = _mm512_extractf32x4_ps(a, 0x1); - let e = _mm_setr_ps(5., 6., 7., 8.); + let e = _mm_set_pd(1., -2.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_sub_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_sub_round_sd(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_sub_round_sd(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., -2.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mul_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mul_round_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 800.); assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_moveldup_ps() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let r = _mm512_moveldup_ps(a); - let e = _mm512_setr_ps( - 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., + unsafe fn test_mm_mask_mul_round_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_mul_round_ss(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_mul_round_ss( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, ); - assert_eq_m512(r, e); + let e = _mm_set_ps(1., 2., 10., 800.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_moveldup_ps() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let r = _mm512_mask_moveldup_ps(a, 0, a); - assert_eq_m512(r, a); - let r = _mm512_mask_moveldup_ps(a, 0b11111111_11111111, a); - let e = _mm512_setr_ps( - 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_mul_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_mul_round_ss(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_mul_round_ss(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 800.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_moveldup_ps() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let r = _mm512_maskz_moveldup_ps(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_moveldup_ps(0b00000000_11111111, a); - let e = _mm512_setr_ps( - 1., 1., 3., 3., 5., 5., 7., 7., 0., 0., 0., 0., 0., 0., 0., 0., + unsafe fn test_mm_mul_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mul_round_sd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_mul_round_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_mul_round_sd(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_mul_round_sd( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, ); - assert_eq_m512(r, e); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_movehdup_ps() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let r = _mm512_movehdup_ps(a); - let e = _mm512_setr_ps( - 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_mul_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_mul_round_sd(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_mul_round_sd(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_movehdup_ps() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let r = _mm512_mask_movehdup_ps(a, 0, a); - assert_eq_m512(r, a); - let r = _mm512_mask_movehdup_ps(a, 0b11111111_11111111, a); - let e = _mm512_setr_ps( - 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_div_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_div_round_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_movehdup_ps() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let r = _mm512_maskz_movehdup_ps(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_movehdup_ps(0b00000000_11111111, a); - let e = _mm512_setr_ps( - 2., 2., 4., 4., 6., 6., 8., 8., 0., 0., 0., 0., 0., 0., 0., 0., + unsafe fn test_mm_mask_div_round_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_mask_div_round_ss(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_div_round_ss( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, ); - assert_eq_m512(r, e); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_inserti32x4() { - let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm_setr_epi32(17, 18, 19, 20); - let r = _mm512_inserti32x4(a, b, 0); - let e = _mm512_setr_epi32(17, 18, 19, 20, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_div_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 40.); + let r = _mm_maskz_div_round_ss(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_div_round_ss(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 0.5); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_inserti32x4() { - let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm_setr_epi32(17, 18, 19, 20); - let r = _mm512_mask_inserti32x4(a, 0, a, b, 0); - assert_eq_m512i(r, a); - let r = _mm512_mask_inserti32x4(a, 0b11111111_11111111, a, b, 0); - let e = _mm512_setr_epi32(17, 18, 19, 20, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - assert_eq_m512i(r, e); + unsafe fn test_mm_div_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_div_round_sd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_inserti32x4() { - let a = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm_setr_epi32(17, 18, 19, 20); - let r = _mm512_maskz_inserti32x4(0, a, b, 0); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_inserti32x4(0b00000000_11111111, a, b, 0); - let e = _mm512_setr_epi32(17, 18, 19, 20, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_div_round_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_div_round_sd(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_div_round_sd( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + ); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_insertf32x4() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm_setr_ps(17., 18., 19., 20.); - let r = _mm512_insertf32x4(a, b, 0); - let e = _mm512_setr_ps( - 17., 18., 19., 20., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_div_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_div_round_sd(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_div_round_sd(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.5); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_insertf32x4() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm_setr_ps(17., 18., 19., 20.); - let r = _mm512_mask_insertf32x4(a, 0, a, b, 0); - assert_eq_m512(r, a); - let r = _mm512_mask_insertf32x4(a, 0b11111111_11111111, a, b, 0); - let e = _mm512_setr_ps( - 17., 18., 19., 20., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_max_round_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_max_round_ss(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 7.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_insertf32x4() { - let a = _mm512_setr_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm_setr_ps(17., 18., 19., 20.); - let r = _mm512_maskz_insertf32x4(0, a, b, 0); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_insertf32x4(0b00000000_11111111, a, b, 0); - let e = _mm512_setr_ps( - 17., 18., 19., 20., 5., 6., 7., 8., 0., 0., 0., 0., 0., 0., 0., 0., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_max_round_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_mask_max_round_ss(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); + let r = _mm_mask_max_round_ss(a, 0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 7.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castps128_ps512() { - let a = _mm_setr_ps(17., 18., 19., 20.); - let r = _mm512_castps128_ps512(a); - let e = _mm512_setr_ps( - 17., 18., 19., 20., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_max_round_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_maskz_max_round_ss(0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_max_round_ss(0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 7.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castps256_ps512() { - let a = _mm256_setr_ps(17., 18., 19., 20., 21., 22., 23., 24.); - let r = _mm512_castps256_ps512(a); - let e = _mm512_setr_ps( - 17., 18., 19., 20., 21., 22., 23., 24., -1., -1., -1., -1., -1., -1., -1., -1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_max_round_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_max_round_sd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 3.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castps512_ps128() { - let a = _mm512_setr_ps( - 17., 18., 19., 20., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., - ); - let r = _mm512_castps512_ps128(a); - let e = _mm_setr_ps(17., 18., 19., 20.); - assert_eq_m128(r, e); + unsafe fn test_mm_mask_max_round_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_mask_max_round_sd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); + let r = _mm_mask_max_round_sd(a, 0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 3.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castps512_ps256() { - let a = _mm512_setr_ps( - 17., 18., 19., 20., 21., 22., 23., 24., -1., -1., -1., -1., -1., -1., -1., -1., - ); - let r = _mm512_castps512_ps256(a); - let e = _mm256_setr_ps(17., 18., 19., 20., 21., 22., 23., 24.); - assert_eq_m256(r, e); + unsafe fn test_mm_maskz_max_round_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_maskz_max_round_sd(0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_max_round_sd(0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 3.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castps_pd() { - let a = _mm512_set1_ps(1.); - let r = _mm512_castps_pd(a); - let e = _mm512_set1_pd(0.007812501848093234); - assert_eq_m512d(r, e); + unsafe fn test_mm_min_round_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_min_round_ss(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castps_si512() { - let a = _mm512_set1_ps(1.); - let r = _mm512_castps_si512(a); - let e = _mm512_set1_epi32(1065353216); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_min_round_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_mask_min_round_ss(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); + let r = _mm_mask_min_round_ss(a, 0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_broadcastd_epi32() { - let a = _mm_set_epi32(17, 18, 19, 20); - let r = _mm512_broadcastd_epi32(a); - let e = _mm512_set1_epi32(20); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_min_round_ss() { + let a = _mm_set_ps(0., 1., 2., 3.); + let b = _mm_set_ps(4., 5., 6., 7.); + let r = _mm_maskz_min_round_ss(0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_min_round_ss(0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 1., 2., 3.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_broadcastd_epi32() { - let src = _mm512_set1_epi32(20); - let a = _mm_set_epi32(17, 18, 19, 20); - let r = _mm512_mask_broadcastd_epi32(src, 0, a); - assert_eq_m512i(r, src); - let r = _mm512_mask_broadcastd_epi32(src, 0b11111111_11111111, a); - let e = _mm512_set1_epi32(20); - assert_eq_m512i(r, e); + unsafe fn test_mm_min_round_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_min_round_sd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_broadcastd_epi32() { - let a = _mm_set_epi32(17, 18, 19, 20); - let r = _mm512_maskz_broadcastd_epi32(0, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_broadcastd_epi32(0b00000000_11111111, a); - let e = _mm512_setr_epi32(20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_min_round_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_mask_min_round_sd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); + let r = _mm_mask_min_round_sd(a, 0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_broadcastss_ps() { - let a = _mm_set_ps(17., 18., 19., 20.); - let r = _mm512_broadcastss_ps(a); - let e = _mm512_set1_ps(20.); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_min_round_sd() { + let a = _mm_set_pd(0., 1.); + let b = _mm_set_pd(2., 3.); + let r = _mm_maskz_min_round_sd(0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_min_round_sd(0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_broadcastss_ps() { - let src = _mm512_set1_ps(20.); - let a = _mm_set_ps(17., 18., 19., 20.); - let r = _mm512_mask_broadcastss_ps(src, 0, a); - assert_eq_m512(r, src); - let r = _mm512_mask_broadcastss_ps(src, 0b11111111_11111111, a); - let e = _mm512_set1_ps(20.); - assert_eq_m512(r, e); + unsafe fn test_mm_sqrt_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_sqrt_round_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 2.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_broadcastss_ps() { - let a = _mm_set_ps(17., 18., 19., 20.); - let r = _mm512_maskz_broadcastss_ps(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_broadcastss_ps(0b00000000_11111111, a); - let e = _mm512_setr_ps( - 20., 20., 20., 20., 20., 20., 20., 20., 0., 0., 0., 0., 0., 0., 0., 0., + unsafe fn test_mm_mask_sqrt_round_ss() { + let src = _mm_set_ps(10., 11., 100., 110.); + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_mask_sqrt_round_ss(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 110.); + assert_eq_m128(r, e); + let r = _mm_mask_sqrt_round_ss( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, ); - assert_eq_m512(r, e); + let e = _mm_set_ps(1., 2., 10., 2.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_broadcast_i32x4() { - let a = _mm_set_epi32(17, 18, 19, 20); - let r = _mm512_broadcast_i32x4(a); - let e = _mm512_set_epi32( - 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_sqrt_round_ss() { + let a = _mm_set_ps(1., 2., 10., 20.); + let b = _mm_set_ps(3., 4., 30., 4.); + let r = _mm_maskz_sqrt_round_ss(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_sqrt_round_ss(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 2., 10., 2.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_broadcast_i32x4() { - let src = _mm512_set1_epi32(20); - let a = _mm_set_epi32(17, 18, 19, 20); - let r = _mm512_mask_broadcast_i32x4(src, 0, a); - assert_eq_m512i(r, src); - let r = _mm512_mask_broadcast_i32x4(src, 0b11111111_11111111, a); - let e = _mm512_set_epi32( - 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, 17, 18, 19, 20, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_sqrt_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_sqrt_round_sd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 2.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_broadcast_i32x4() { - let a = _mm_set_epi32(17, 18, 19, 20); - let r = _mm512_maskz_broadcast_i32x4(0, a); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_broadcast_i32x4(0b00000000_11111111, a); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 20, 17, 18, 19, 20); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_sqrt_round_sd() { + let src = _mm_set_pd(10., 11.); + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_mask_sqrt_round_sd(src, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 11.); + assert_eq_m128d(r, e); + let r = _mm_mask_sqrt_round_sd( + src, + 0b11111111, + a, + b, + _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC, + ); + let e = _mm_set_pd(1., 2.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_broadcast_f32x4() { - let a = _mm_set_ps(17., 18., 19., 20.); - let r = _mm512_broadcast_f32x4(a); - let e = _mm512_set_ps( - 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_sqrt_round_sd() { + let a = _mm_set_pd(1., 2.); + let b = _mm_set_pd(3., 4.); + let r = _mm_maskz_sqrt_round_sd(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_sqrt_round_sd(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 2.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_broadcast_f32x4() { - let src = _mm512_set1_ps(20.); - let a = _mm_set_ps(17., 18., 19., 20.); - let r = _mm512_mask_broadcast_f32x4(src, 0, a); - assert_eq_m512(r, src); - let r = _mm512_mask_broadcast_f32x4(src, 0b11111111_11111111, a); - let e = _mm512_set_ps( - 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., 17., 18., 19., 20., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_getexp_round_ss() { + let a = _mm_set1_ps(2.); + let b = _mm_set1_ps(3.); + let r = _mm_getexp_round_ss(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2., 2., 2., 1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_broadcast_f32x4() { - let a = _mm_set_ps(17., 18., 19., 20.); - let r = _mm512_maskz_broadcast_f32x4(0, a); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_broadcast_f32x4(0b00000000_11111111, a); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 17., 18., 19., 20., 17., 18., 19., 20., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_getexp_round_ss() { + let a = _mm_set1_ps(2.); + let b = _mm_set1_ps(3.); + let r = _mm_mask_getexp_round_ss(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2., 2., 2., 2.); + assert_eq_m128(r, e); + let r = _mm_mask_getexp_round_ss(a, 0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2., 2., 2., 1.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_getexp_round_ss() { + let a = _mm_set1_ps(2.); + let b = _mm_set1_ps(3.); + let r = _mm_maskz_getexp_round_ss(0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2., 2., 2., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_getexp_round_ss(0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2., 2., 2., 1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_blend_epi32() { - let a = _mm512_set1_epi32(1); - let b = _mm512_set1_epi32(2); - let r = _mm512_mask_blend_epi32(0b11111111_00000000, a, b); - let e = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); - assert_eq_m512i(r, e); + unsafe fn test_mm_getexp_round_sd() { + let a = _mm_set1_pd(2.); + let b = _mm_set1_pd(3.); + let r = _mm_getexp_round_sd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_blend_ps() { - let a = _mm512_set1_ps(1.); - let b = _mm512_set1_ps(2.); - let r = _mm512_mask_blend_ps(0b11111111_00000000, a, b); - let e = _mm512_set_ps( - 2., 2., 2., 2., 2., 2., 2., 2., 1., 1., 1., 1., 1., 1., 1., 1., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_getexp_round_sd() { + let a = _mm_set1_pd(2.); + let b = _mm_set1_pd(3.); + let r = _mm_mask_getexp_round_sd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2., 2.); + assert_eq_m128d(r, e); + let r = _mm_mask_getexp_round_sd(a, 0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_unpackhi_epi32() { - let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm512_set_epi32( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - ); - let r = _mm512_unpackhi_epi32(a, b); - let e = _mm512_set_epi32(17, 1, 18, 2, 21, 5, 22, 6, 25, 9, 26, 10, 29, 13, 30, 14); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_getexp_round_sd() { + let a = _mm_set1_pd(2.); + let b = _mm_set1_pd(3.); + let r = _mm_maskz_getexp_round_sd(0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_getexp_round_sd(0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_unpackhi_epi32() { - let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm512_set_epi32( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + unsafe fn test_mm_getmant_round_ss() { + let a = _mm_set1_ps(20.); + let b = _mm_set1_ps(10.); + let r = _mm_getmant_round_ss( + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - let r = _mm512_mask_unpackhi_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_unpackhi_epi32(a, 0b11111111_11111111, a, b); - let e = _mm512_set_epi32(17, 1, 18, 2, 21, 5, 22, 6, 25, 9, 26, 10, 29, 13, 30, 14); - assert_eq_m512i(r, e); + let e = _mm_set_ps(20., 20., 20., 1.25); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_unpackhi_epi32() { - let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm512_set_epi32( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + unsafe fn test_mm_mask_getmant_round_ss() { + let a = _mm_set1_ps(20.); + let b = _mm_set1_ps(10.); + let r = _mm_mask_getmant_round_ss( + a, + 0, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - let r = _mm512_maskz_unpackhi_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_unpackhi_epi32(0b00000000_11111111, a, b); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 25, 9, 26, 10, 29, 13, 30, 14); - assert_eq_m512i(r, e); + let e = _mm_set_ps(20., 20., 20., 20.); + assert_eq_m128(r, e); + let r = _mm_mask_getmant_round_ss( + a, + 0b11111111, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm_set_ps(20., 20., 20., 1.25); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_unpackhi_ps() { - let a = _mm512_set_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm512_set_ps( - 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + unsafe fn test_mm_maskz_getmant_round_ss() { + let a = _mm_set1_ps(20.); + let b = _mm_set1_ps(10.); + let r = _mm_maskz_getmant_round_ss( + 0, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - let r = _mm512_unpackhi_ps(a, b); - let e = _mm512_set_ps( - 17., 1., 18., 2., 21., 5., 22., 6., 25., 9., 26., 10., 29., 13., 30., 14., + let e = _mm_set_ps(20., 20., 20., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_getmant_round_ss( + 0b11111111, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - assert_eq_m512(r, e); + let e = _mm_set_ps(20., 20., 20., 1.25); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_unpackhi_ps() { - let a = _mm512_set_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + unsafe fn test_mm_getmant_round_sd() { + let a = _mm_set1_pd(20.); + let b = _mm_set1_pd(10.); + let r = _mm_getmant_round_sd( + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - let b = _mm512_set_ps( - 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + let e = _mm_set_pd(20., 1.25); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_getmant_round_sd() { + let a = _mm_set1_pd(20.); + let b = _mm_set1_pd(10.); + let r = _mm_mask_getmant_round_sd( + a, + 0, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - let r = _mm512_mask_unpackhi_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_unpackhi_ps(a, 0b11111111_11111111, a, b); - let e = _mm512_set_ps( - 17., 1., 18., 2., 21., 5., 22., 6., 25., 9., 26., 10., 29., 13., 30., 14., + let e = _mm_set_pd(20., 20.); + assert_eq_m128d(r, e); + let r = _mm_mask_getmant_round_sd( + a, + 0b11111111, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - assert_eq_m512(r, e); + let e = _mm_set_pd(20., 1.25); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_unpackhi_ps() { - let a = _mm512_set_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm512_set_ps( - 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + unsafe fn test_mm_maskz_getmant_round_sd() { + let a = _mm_set1_pd(20.); + let b = _mm_set1_pd(10.); + let r = _mm_maskz_getmant_round_sd( + 0, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - let r = _mm512_maskz_unpackhi_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_unpackhi_ps(0b00000000_11111111, a, b); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 25., 9., 26., 10., 29., 13., 30., 14., + let e = _mm_set_pd(20., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_getmant_round_sd( + 0b11111111, + a, + b, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, ); - assert_eq_m512(r, e); + let e = _mm_set_pd(20., 1.25); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_unpacklo_epi32() { - let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm512_set_epi32( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - ); - let r = _mm512_unpacklo_epi32(a, b); - let e = _mm512_set_epi32(19, 3, 20, 4, 23, 7, 24, 8, 27, 11, 28, 12, 31, 15, 32, 16); - assert_eq_m512i(r, e); + unsafe fn test_mm_roundscale_round_ss() { + let a = _mm_set1_ps(2.2); + let b = _mm_set1_ps(1.1); + let r = _mm_roundscale_round_ss(a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2.2, 2.2, 2.2, 1.0); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_unpacklo_epi32() { - let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm512_set_epi32( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - ); - let r = _mm512_mask_unpacklo_epi32(a, 0, a, b); - assert_eq_m512i(r, a); - let r = _mm512_mask_unpacklo_epi32(a, 0b11111111_11111111, a, b); - let e = _mm512_set_epi32(19, 3, 20, 4, 23, 7, 24, 8, 27, 11, 28, 12, 31, 15, 32, 16); - assert_eq_m512i(r, e); + unsafe fn test_mm_mask_roundscale_round_ss() { + let a = _mm_set1_ps(2.2); + let b = _mm_set1_ps(1.1); + let r = _mm_mask_roundscale_round_ss(a, 0, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2.2, 2.2, 2.2, 2.2); + assert_eq_m128(r, e); + let r = _mm_mask_roundscale_round_ss(a, 0b11111111, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2.2, 2.2, 2.2, 1.0); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_unpacklo_epi32() { - let a = _mm512_set_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); - let b = _mm512_set_epi32( - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - ); - let r = _mm512_maskz_unpacklo_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_unpacklo_epi32(0b00000000_11111111, a, b); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 27, 11, 28, 12, 31, 15, 32, 16); - assert_eq_m512i(r, e); + unsafe fn test_mm_maskz_roundscale_round_ss() { + let a = _mm_set1_ps(2.2); + let b = _mm_set1_ps(1.1); + let r = _mm_maskz_roundscale_round_ss(0, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2.2, 2.2, 2.2, 0.0); + assert_eq_m128(r, e); + let r = _mm_maskz_roundscale_round_ss(0b11111111, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(2.2, 2.2, 2.2, 1.0); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_unpacklo_ps() { - let a = _mm512_set_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm512_set_ps( - 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., - ); - let r = _mm512_unpacklo_ps(a, b); - let e = _mm512_set_ps( - 19., 3., 20., 4., 23., 7., 24., 8., 27., 11., 28., 12., 31., 15., 32., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_roundscale_round_sd() { + let a = _mm_set1_pd(2.2); + let b = _mm_set1_pd(1.1); + let r = _mm_roundscale_round_sd(a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2.2, 1.0); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_unpacklo_ps() { - let a = _mm512_set_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm512_set_ps( - 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., - ); - let r = _mm512_mask_unpacklo_ps(a, 0, a, b); - assert_eq_m512(r, a); - let r = _mm512_mask_unpacklo_ps(a, 0b11111111_11111111, a, b); - let e = _mm512_set_ps( - 19., 3., 20., 4., 23., 7., 24., 8., 27., 11., 28., 12., 31., 15., 32., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_mask_roundscale_round_sd() { + let a = _mm_set1_pd(2.2); + let b = _mm_set1_pd(1.1); + let r = _mm_mask_roundscale_round_sd(a, 0, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2.2, 2.2); + assert_eq_m128d(r, e); + let r = _mm_mask_roundscale_round_sd(a, 0b11111111, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2.2, 1.0); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_unpacklo_ps() { - let a = _mm512_set_ps( - 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., - ); - let b = _mm512_set_ps( - 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., - ); - let r = _mm512_maskz_unpacklo_ps(0, a, b); - assert_eq_m512(r, _mm512_setzero_ps()); - let r = _mm512_maskz_unpacklo_ps(0b00000000_11111111, a, b); - let e = _mm512_set_ps( - 0., 0., 0., 0., 0., 0., 0., 0., 27., 11., 28., 12., 31., 15., 32., 16., - ); - assert_eq_m512(r, e); + unsafe fn test_mm_maskz_roundscale_round_sd() { + let a = _mm_set1_pd(2.2); + let b = _mm_set1_pd(1.1); + let r = _mm_maskz_roundscale_round_sd(0, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2.2, 0.0); + assert_eq_m128d(r, e); + let r = _mm_maskz_roundscale_round_sd(0b11111111, a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(2.2, 1.0); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_and_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, - ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, - ); - let r = _mm512_and_epi32(a, b); - let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); - assert_eq_m512i(r, e); + unsafe fn test_mm_scalef_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(3.); + let r = _mm_scalef_round_ss(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 8.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_and_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, - ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + unsafe fn test_mm_mask_scalef_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(3.); + let r = _mm_mask_scalef_round_ss(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 1.); + assert_eq_m128(r, e); + let r = _mm_mask_scalef_round_ss( + a, + 0b11111111, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_mask_and_epi32(a, 0, a, b); - assert_eq_m512i(r, a); + let e = _mm_set_ps(1., 1., 1., 8.); + assert_eq_m128(r, e); + } - let r = _mm512_mask_and_epi32(a, 0b01111111_11111111, a, b); - let e = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3, + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_scalef_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(3.); + let r = _mm_maskz_scalef_round_ss(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_scalef_round_ss( + 0b11111111, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - assert_eq_m512i(r, e); + let e = _mm_set_ps(1., 1., 1., 8.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_and_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_scalef_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(3.); + let r = _mm_scalef_round_sd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_scalef_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(3.); + let r = _mm_mask_scalef_round_sd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 1.); + assert_eq_m128d(r, e); + let r = _mm_mask_scalef_round_sd( + a, + 0b11111111, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_scalef_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(3.); + let r = _mm_maskz_scalef_round_sd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_scalef_round_sd( + 0b11111111, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_maskz_and_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); + let e = _mm_set_pd(1., 8.); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_and_epi32(0b00000000_11111111, a, b); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_fmadd_round_ss(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_and_si512() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_mask_fmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fmadd_round_ss(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, a); + let r = _mm_mask_fmadd_round_ss( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_ps(1., 1., 1., 5.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_maskz_fmadd_round_ss(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fmadd_round_ss( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_and_epi32(a, b); - let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); - assert_eq_m512i(r, e); + let e = _mm_set_ps(1., 1., 1., 5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_or_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_mask3_fmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask3_fmadd_round_ss(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, c); + let r = _mm_mask3_fmadd_round_ss( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_ps(3., 3., 3., 5.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_fmadd_round_sd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fmadd_round_sd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, a); + let r = _mm_mask_fmadd_round_sd( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_or_epi32(a, b); - let e = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3 | 1 << 4, + let e = _mm_set_pd(1., 5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_maskz_fmadd_round_sd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fmadd_round_sd( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm_set_pd(1., 5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask3_fmadd_round_sd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, c); + let r = _mm_mask3_fmadd_round_sd( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - assert_eq_m512i(r, e); + let e = _mm_set_pd(3., 5.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_or_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_fmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_fmsub_round_ss(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., -1.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fmsub_round_ss(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, a); + let r = _mm_mask_fmsub_round_ss( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_ps(1., 1., 1., -1.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_maskz_fmsub_round_ss(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fmsub_round_ss( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_mask_or_epi32(a, 0, a, b); - assert_eq_m512i(r, a); + let e = _mm_set_ps(1., 1., 1., -1.); + assert_eq_m128(r, e); + } - let r = _mm512_mask_or_epi32(a, 0b11111111_11111111, a, b); - let e = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3 | 1 << 4, + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask3_fmsub_round_ss(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, c); + let r = _mm_mask3_fmsub_round_ss( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - assert_eq_m512i(r, e); + let e = _mm_set_ps(3., 3., 3., -1.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_or_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_fmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_fmsub_round_sd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., -1.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fmsub_round_sd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, a); + let r = _mm_mask_fmsub_round_sd( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_pd(1., -1.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_maskz_fmsub_round_sd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fmsub_round_sd( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_maskz_or_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); + let e = _mm_set_pd(1., -1.); + assert_eq_m128d(r, e); + } - let r = _mm512_maskz_or_epi32(0b00000000_11111111, a, b); - let e = _mm512_set_epi32( - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3 | 1 << 4, + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask3_fmsub_round_sd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, c); + let r = _mm_mask3_fmsub_round_sd( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - assert_eq_m512i(r, e); + let e = _mm_set_pd(3., -1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_or_si512() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_fnmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_fnmadd_round_ss(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 1.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fnmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fnmadd_round_ss(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, a); + let r = _mm_mask_fnmadd_round_ss( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_ps(1., 1., 1., 1.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fnmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = + _mm_maskz_fnmadd_round_ss(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fnmadd_round_ss( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_or_epi32(a, b); - let e = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3 | 1 << 4, + let e = _mm_set_ps(1., 1., 1., 1.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fnmadd_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = + _mm_mask3_fnmadd_round_ss(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, c); + let r = _mm_mask3_fnmadd_round_ss( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm_set_ps(3., 3., 3., 1.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fnmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_fnmadd_round_sd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 1.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fnmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fnmadd_round_sd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, a); + let r = _mm_mask_fnmadd_round_sd( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - assert_eq_m512i(r, e); + let e = _mm_set_pd(1., 1.); + assert_eq_m128d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_xor_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_maskz_fnmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = + _mm_maskz_fnmadd_round_sd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fnmadd_round_sd( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_pd(1., 1.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fnmadd_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = + _mm_mask3_fnmadd_round_sd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, c); + let r = _mm_mask3_fnmadd_round_sd( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_xor_epi32(a, b); - let e = _mm512_set_epi32( - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 4, + let e = _mm_set_pd(3., 1.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fnmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_fnmsub_round_ss(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., -5.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fnmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = _mm_mask_fnmsub_round_ss(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, a); + let r = _mm_mask_fnmsub_round_ss( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - assert_eq_m512i(r, e); + let e = _mm_set_ps(1., 1., 1., -5.); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_xor_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, + unsafe fn test_mm_maskz_fnmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = + _mm_maskz_fnmsub_round_ss(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(1., 1., 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_fnmsub_round_ss( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, + let e = _mm_set_ps(1., 1., 1., -5.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fnmsub_round_ss() { + let a = _mm_set1_ps(1.); + let b = _mm_set1_ps(2.); + let c = _mm_set1_ps(3.); + let r = + _mm_mask3_fnmsub_round_ss(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128(r, c); + let r = _mm_mask3_fnmsub_round_ss( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - let r = _mm512_mask_xor_epi32(a, 0, a, b); - assert_eq_m512i(r, a); + let e = _mm_set_ps(3., 3., 3., -5.); + assert_eq_m128(r, e); + } - let r = _mm512_mask_xor_epi32(a, 0b01111111_11111111, a, b); - let e = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 4, + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fnmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_fnmsub_round_sd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., -5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fnmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = _mm_mask_fnmsub_round_sd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, a); + let r = _mm_mask_fnmsub_round_sd( + a, + 0b11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); - assert_eq_m512i(r, e); + let e = _mm_set_pd(1., -5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fnmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = + _mm_maskz_fnmsub_round_sd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm_set_pd(1., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_fnmsub_round_sd( + 0b11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm_set_pd(1., -5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask3_fnmsub_round_sd() { + let a = _mm_set1_pd(1.); + let b = _mm_set1_pd(2.); + let c = _mm_set1_pd(3.); + let r = + _mm_mask3_fnmsub_round_sd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m128d(r, c); + let r = _mm_mask3_fnmsub_round_sd( + a, + b, + c, + 0b11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm_set_pd(3., -5.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fixupimm_ss() { + let a = _mm_set_ps(0., 0., 0., f32::NAN); + let b = _mm_set1_ps(f32::MAX); + let c = _mm_set1_epi32(i32::MAX); + let r = _mm_fixupimm_ss(a, b, c, 5); + let e = _mm_set_ps(0., 0., 0., -0.0); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fixupimm_ss() { + let a = _mm_set_ps(0., 0., 0., f32::NAN); + let b = _mm_set1_ps(f32::MAX); + let c = _mm_set1_epi32(i32::MAX); + let r = _mm_mask_fixupimm_ss(a, 0b11111111, b, c, 5); + let e = _mm_set_ps(0., 0., 0., -0.0); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fixupimm_ss() { + let a = _mm_set_ps(0., 0., 0., f32::NAN); + let b = _mm_set1_ps(f32::MAX); + let c = _mm_set1_epi32(i32::MAX); + let r = _mm_maskz_fixupimm_ss(0b00000000, a, b, c, 5); + let e = _mm_set_ps(0., 0., 0., 0.0); + assert_eq_m128(r, e); + let r = _mm_maskz_fixupimm_ss(0b11111111, a, b, c, 5); + let e = _mm_set_ps(0., 0., 0., -0.0); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fixupimm_sd() { + let a = _mm_set_pd(0., f64::NAN); + let b = _mm_set1_pd(f64::MAX); + let c = _mm_set1_epi64x(i32::MAX as i64); + let r = _mm_fixupimm_sd(a, b, c, 5); + let e = _mm_set_pd(0., -0.0); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fixupimm_sd() { + let a = _mm_set_pd(0., f64::NAN); + let b = _mm_set1_pd(f64::MAX); + let c = _mm_set1_epi64x(i32::MAX as i64); + let r = _mm_mask_fixupimm_sd(a, 0b11111111, b, c, 5); + let e = _mm_set_pd(0., -0.0); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fixupimm_sd() { + let a = _mm_set_pd(0., f64::NAN); + let b = _mm_set1_pd(f64::MAX); + let c = _mm_set1_epi64x(i32::MAX as i64); + let r = _mm_maskz_fixupimm_sd(0b00000000, a, b, c, 5); + let e = _mm_set_pd(0., 0.0); + assert_eq_m128d(r, e); + let r = _mm_maskz_fixupimm_sd(0b11111111, a, b, c, 5); + let e = _mm_set_pd(0., -0.0); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fixupimm_round_ss() { + let a = _mm_set_ps(0., 0., 0., f32::NAN); + let b = _mm_set1_ps(f32::MAX); + let c = _mm_set1_epi32(i32::MAX); + let r = _mm_fixupimm_round_ss(a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 0., 0., -0.0); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fixupimm_round_ss() { + let a = _mm_set_ps(0., 0., 0., f32::NAN); + let b = _mm_set1_ps(f32::MAX); + let c = _mm_set1_epi32(i32::MAX); + let r = _mm_mask_fixupimm_round_ss(a, 0b11111111, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 0., 0., -0.0); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fixupimm_round_ss() { + let a = _mm_set_ps(0., 0., 0., f32::NAN); + let b = _mm_set1_ps(f32::MAX); + let c = _mm_set1_epi32(i32::MAX); + let r = _mm_maskz_fixupimm_round_ss(0b00000000, a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 0., 0., 0.0); + assert_eq_m128(r, e); + let r = _mm_maskz_fixupimm_round_ss(0b11111111, a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_ps(0., 0., 0., -0.0); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_fixupimm_round_sd() { + let a = _mm_set_pd(0., f64::NAN); + let b = _mm_set1_pd(f64::MAX); + let c = _mm_set1_epi64x(i32::MAX as i64); + let r = _mm_fixupimm_round_sd(a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., -0.0); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_fixupimm_round_sd() { + let a = _mm_set_pd(0., f64::NAN); + let b = _mm_set1_pd(f64::MAX); + let c = _mm_set1_epi64x(i32::MAX as i64); + let r = _mm_mask_fixupimm_round_sd(a, 0b11111111, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., -0.0); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_fixupimm_round_sd() { + let a = _mm_set_pd(0., f64::NAN); + let b = _mm_set1_pd(f64::MAX); + let c = _mm_set1_epi64x(i32::MAX as i64); + let r = _mm_maskz_fixupimm_round_sd(0b00000000, a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., 0.0); + assert_eq_m128d(r, e); + let r = _mm_maskz_fixupimm_round_sd(0b11111111, a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(0., -0.0); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cvtss_sd() { + let a = _mm_set_pd(6., -7.5); + let b = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_mask_cvtss_sd(a, 0, a, b); + assert_eq_m128d(r, a); + let r = _mm_mask_cvtss_sd(a, 0b11111111, a, b); + let e = _mm_set_pd(6., -1.5); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_cvtss_sd() { + let a = _mm_set_pd(6., -7.5); + let b = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_maskz_cvtss_sd(0, a, b); + let e = _mm_set_pd(6., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_cvtss_sd(0b11111111, a, b); + let e = _mm_set_pd(6., -1.5); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cvtsd_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b = _mm_set_pd(6., -7.5); + let r = _mm_mask_cvtsd_ss(a, 0, a, b); + assert_eq_m128(r, a); + let r = _mm_mask_cvtsd_ss(a, 0b11111111, a, b); + let e = _mm_set_ps(0., -0.5, 1., -7.5); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_cvtsd_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b = _mm_set_pd(6., -7.5); + let r = _mm_maskz_cvtsd_ss(0, a, b); + let e = _mm_set_ps(0., -0.5, 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_cvtsd_ss(0b11111111, a, b); + let e = _mm_set_ps(0., -0.5, 1., -7.5); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvt_roundss_sd() { + let a = _mm_set_pd(6., -7.5); + let b = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvt_roundss_sd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(6., -1.5); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cvt_roundss_sd() { + let a = _mm_set_pd(6., -7.5); + let b = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_mask_cvt_roundss_sd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m128d(r, a); + let r = _mm_mask_cvt_roundss_sd(a, 0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(6., -1.5); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_maskz_cvt_roundss_sd() { + let a = _mm_set_pd(6., -7.5); + let b = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_maskz_cvt_roundss_sd(0, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(6., 0.); + assert_eq_m128d(r, e); + let r = _mm_maskz_cvt_roundss_sd(0b11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm_set_pd(6., -1.5); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvt_roundsd_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b = _mm_set_pd(6., -7.5); + let r = _mm_cvt_roundsd_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(0., -0.5, 1., -7.5); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_mask_cvt_roundsd_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b = _mm_set_pd(6., -7.5); + let r = _mm_mask_cvt_roundsd_ss(a, 0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + assert_eq_m128(r, a); + let r = + _mm_mask_cvt_roundsd_ss(a, 0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(0., -0.5, 1., -7.5); + assert_eq_m128(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_xor_epi32() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, - ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, - ); - let r = _mm512_maskz_xor_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm_maskz_cvt_roundsd_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b = _mm_set_pd(6., -7.5); + let r = _mm_maskz_cvt_roundsd_ss(0, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(0., -0.5, 1., 0.); + assert_eq_m128(r, e); + let r = _mm_maskz_cvt_roundsd_ss(0b11111111, a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(0., -0.5, 1., -7.5); + assert_eq_m128(r, e); + } - let r = _mm512_maskz_xor_epi32(0b00000000_11111111, a, b); - let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 4); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvt_roundss_si32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvt_roundss_si32(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e: i32 = -1; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_xor_si512() { - let a = _mm512_set_epi32( - 1 << 1 | 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 3, - ); - let b = _mm512_set_epi32( - 1 << 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, - ); - let r = _mm512_xor_epi32(a, b); - let e = _mm512_set_epi32( - 1 << 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 1 | 1 << 4, - ); - assert_eq_m512i(r, e); + unsafe fn test_mm_cvt_roundss_i32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvt_roundss_i32(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e: i32 = -1; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_andnot_epi32() { - let a = _mm512_set1_epi32(0); - let b = _mm512_set1_epi32(1 << 3 | 1 << 4); - let r = _mm512_andnot_epi32(a, b); - let e = _mm512_set1_epi32(1 << 3 | 1 << 4); - assert_eq_m512i(r, e); + unsafe fn test_mm_cvt_roundss_u32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvt_roundss_u32(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e: u32 = u32::MAX; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_andnot_epi32() { - let a = _mm512_set1_epi32(1 << 1 | 1 << 2); - let b = _mm512_set1_epi32(1 << 3 | 1 << 4); - let r = _mm512_mask_andnot_epi32(a, 0, a, b); - assert_eq_m512i(r, a); + unsafe fn test_mm_cvtss_i32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvtss_i32(a); + let e: i32 = -2; + assert_eq!(r, e); + } - let r = _mm512_mask_andnot_epi32(a, 0b11111111_11111111, a, b); - let e = _mm512_set1_epi32(1 << 3 | 1 << 4); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvtss_u32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvtss_u32(a); + let e: u32 = u32::MAX; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_andnot_epi32() { - let a = _mm512_set1_epi32(1 << 1 | 1 << 2); - let b = _mm512_set1_epi32(1 << 3 | 1 << 4); - let r = _mm512_maskz_andnot_epi32(0, a, b); - assert_eq_m512i(r, _mm512_setzero_si512()); + unsafe fn test_mm_cvt_roundsd_si32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvt_roundsd_si32(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e: i32 = -1; + assert_eq!(r, e); + } - let r = _mm512_maskz_andnot_epi32(0b00000000_11111111, a, b); - let e = _mm512_set_epi32( - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1 << 3 | 1 << 4, - 1 << 3 | 1 << 4, - 1 << 3 | 1 << 4, - 1 << 3 | 1 << 4, - 1 << 3 | 1 << 4, - 1 << 3 | 1 << 4, - 1 << 3 | 1 << 4, - 1 << 3 | 1 << 4, - ); - assert_eq_m512i(r, e); + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvt_roundsd_i32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvt_roundsd_i32(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e: i32 = -1; + assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_kand() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b11001100_00110011; - let r = _mm512_kand(a, b); - let e: u16 = 0b11001100_00110011; + unsafe fn test_mm_cvt_roundsd_u32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvt_roundsd_u32(a, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e: u32 = u32::MAX; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_kand_mask16() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b11001100_00110011; - let r = _kand_mask16(a, b); - let e: u16 = 0b11001100_00110011; + unsafe fn test_mm_cvtsd_i32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvtsd_i32(a); + let e: i32 = -2; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_kor() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _mm512_kor(a, b); - let e: u16 = 0b11101110_00111011; + unsafe fn test_mm_cvtsd_u32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvtsd_u32(a); + let e: u32 = u32::MAX; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_kor_mask16() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _kor_mask16(a, b); - let e: u16 = 0b11101110_00111011; + unsafe fn test_mm_cvt_roundi32_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b: i32 = 9; + let r = _mm_cvt_roundi32_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(0., -0.5, 1., 9.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvt_roundsi32_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b: i32 = 9; + let r = _mm_cvt_roundsi32_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(0., -0.5, 1., 9.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvt_roundu32_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b: u32 = 9; + let r = _mm_cvt_roundu32_ss(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm_set_ps(0., -0.5, 1., 9.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvti32_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b: i32 = 9; + let r = _mm_cvti32_ss(a, b); + let e = _mm_set_ps(0., -0.5, 1., 9.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvti32_sd() { + let a = _mm_set_pd(1., -1.5); + let b: i32 = 9; + let r = _mm_cvti32_sd(a, b); + let e = _mm_set_pd(1., 9.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvtt_roundss_si32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvtt_roundss_si32(a, _MM_FROUND_CUR_DIRECTION); + let e: i32 = -2; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_kxor() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _mm512_kxor(a, b); - let e: u16 = 0b11100010_00111000; + unsafe fn test_mm_cvtt_roundss_i32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvtt_roundss_i32(a, _MM_FROUND_CUR_DIRECTION); + let e: i32 = -2; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_kxor_mask16() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _kxor_mask16(a, b); - let e: u16 = 0b11100010_00111000; + unsafe fn test_mm_cvtt_roundss_u32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvtt_roundss_u32(a, _MM_FROUND_CUR_DIRECTION); + let e: u32 = u32::MAX; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_knot() { - let a: u16 = 0b11001100_00110011; - let r = _mm512_knot(a); - let e: u16 = 0b00110011_11001100; + unsafe fn test_mm_cvttss_i32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvttss_i32(a); + let e: i32 = -2; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_knot_mask16() { - let a: u16 = 0b11001100_00110011; - let r = _knot_mask16(a); - let e: u16 = 0b00110011_11001100; + unsafe fn test_mm_cvttss_u32() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let r = _mm_cvttss_u32(a); + let e: u32 = u32::MAX; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_kandn() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _mm512_kandn(a, b); - let e: u16 = 0b00100010_00001000; + unsafe fn test_mm_cvtt_roundsd_si32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvtt_roundsd_si32(a, _MM_FROUND_CUR_DIRECTION); + let e: i32 = -2; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_kandn_mask16() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _kandn_mask16(a, b); - let e: u16 = 0b00100010_00001000; + unsafe fn test_mm_cvtt_roundsd_i32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvtt_roundsd_i32(a, _MM_FROUND_CUR_DIRECTION); + let e: i32 = -2; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_kxnor() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _mm512_kxnor(a, b); - let e: u16 = 0b00011101_11000111; + unsafe fn test_mm_cvtt_roundsd_u32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvtt_roundsd_u32(a, _MM_FROUND_CUR_DIRECTION); + let e: u32 = u32::MAX; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_kxnor_mask16() { - let a: u16 = 0b11001100_00110011; - let b: u16 = 0b00101110_00001011; - let r = _kxnor_mask16(a, b); - let e: u16 = 0b00011101_11000111; + unsafe fn test_mm_cvttsd_i32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvttsd_i32(a); + let e: i32 = -2; assert_eq!(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_kmov() { - let a: u16 = 0b11001100_00110011; - let r = _mm512_kmov(a); - let e: u16 = 0b11001100_00110011; + unsafe fn test_mm_cvttsd_u32() { + let a = _mm_set_pd(1., -1.5); + let r = _mm_cvttsd_u32(a); + let e: u32 = u32::MAX; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvtu32_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b: u32 = 9; + let r = _mm_cvtu32_ss(a, b); + let e = _mm_set_ps(0., -0.5, 1., 9.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvtu32_sd() { + let a = _mm_set_pd(1., -1.5); + let b: u32 = 9; + let r = _mm_cvtu32_sd(a, b); + let e = _mm_set_pd(1., 9.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvtu64_ss() { + let a = _mm_set_ps(0., -0.5, 1., -1.5); + let b: u64 = 9; + let r = _mm_cvtu64_ss(a, b); + let e = _mm_set_ps(0., -0.5, 1., 9.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_cvtu64_sd() { + let a = _mm_set_pd(1., -1.5); + let b: u64 = 9; + let r = _mm_cvtu64_sd(a, b); + let e = _mm_set_pd(1., 9.); + assert_eq_m128d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_comi_round_ss() { + let a = _mm_set1_ps(2.2); + let b = _mm_set1_ps(1.1); + let r = _mm_comi_round_ss(a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e: i32 = 0; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm_comi_round_sd() { + let a = _mm_set1_pd(2.2); + let b = _mm_set1_pd(1.1); + let r = _mm_comi_round_sd(a, b, 0, _MM_FROUND_CUR_DIRECTION); + let e: i32 = 0; assert_eq!(r, e); } } diff --git a/library/stdarch/crates/core_arch/src/x86/avx512gfni.rs b/library/stdarch/crates/core_arch/src/x86/avx512gfni.rs new file mode 100644 index 0000000000..6647601f09 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/avx512gfni.rs @@ -0,0 +1,1567 @@ +//! Galois Field New Instructions (GFNI) +//! +//! The intrinsics here correspond to those in the `immintrin.h` C header. +//! +//! The reference is [Intel 64 and IA-32 Architectures Software Developer's +//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref]. +//! +//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + +use crate::core_arch::simd::i8x16; +use crate::core_arch::simd::i8x32; +use crate::core_arch::simd::i8x64; +use crate::core_arch::simd_llvm::simd_select_bitmask; +use crate::core_arch::x86::__m128i; +use crate::core_arch::x86::__m256i; +use crate::core_arch::x86::__m512i; +use crate::core_arch::x86::__mmask16; +use crate::core_arch::x86::__mmask32; +use crate::core_arch::x86::__mmask64; +use crate::core_arch::x86::_mm256_setzero_si256; +use crate::core_arch::x86::_mm512_setzero_si512; +use crate::core_arch::x86::_mm_setzero_si128; +use crate::core_arch::x86::m128iExt; +use crate::core_arch::x86::m256iExt; +use crate::core_arch::x86::m512iExt; +use crate::mem::transmute; + +#[cfg(test)] +use stdarch_test::assert_instr; + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.vgf2p8affineinvqb.512"] + fn vgf2p8affineinvqb_512(x: i8x64, a: i8x64, imm8: u8) -> i8x64; + #[link_name = "llvm.x86.vgf2p8affineinvqb.256"] + fn vgf2p8affineinvqb_256(x: i8x32, a: i8x32, imm8: u8) -> i8x32; + #[link_name = "llvm.x86.vgf2p8affineinvqb.128"] + fn vgf2p8affineinvqb_128(x: i8x16, a: i8x16, imm8: u8) -> i8x16; + #[link_name = "llvm.x86.vgf2p8affineqb.512"] + fn vgf2p8affineqb_512(x: i8x64, a: i8x64, imm8: u8) -> i8x64; + #[link_name = "llvm.x86.vgf2p8affineqb.256"] + fn vgf2p8affineqb_256(x: i8x32, a: i8x32, imm8: u8) -> i8x32; + #[link_name = "llvm.x86.vgf2p8affineqb.128"] + fn vgf2p8affineqb_128(x: i8x16, a: i8x16, imm8: u8) -> i8x16; + #[link_name = "llvm.x86.vgf2p8mulb.512"] + fn vgf2p8mulb_512(a: i8x64, b: i8x64) -> i8x64; + #[link_name = "llvm.x86.vgf2p8mulb.256"] + fn vgf2p8mulb_256(a: i8x32, b: i8x32) -> i8x32; + #[link_name = "llvm.x86.vgf2p8mulb.128"] + fn vgf2p8mulb_128(a: i8x16, b: i8x16) -> i8x16; +} + +// LLVM requires AVX512BW for a lot of these instructions, see +// https://github.com/llvm/llvm-project/blob/release/9.x/clang/include/clang/Basic/BuiltinsX86.def#L457 +// however our tests also require the target feature list to match Intel's +// which *doesn't* require AVX512BW but only AVX512F, so we added the redundant AVX512F +// requirement (for now) +// also see +// https://github.com/llvm/llvm-project/blob/release/9.x/clang/lib/Headers/gfniintrin.h +// for forcing GFNI, BW and optionally VL extension + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm512_gf2p8mul_epi8(a: __m512i, b: __m512i) -> __m512i { + transmute(vgf2p8mulb_512(a.as_i8x64(), b.as_i8x64())) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm512_mask_gf2p8mul_epi8( + src: __m512i, + k: __mmask64, + a: __m512i, + b: __m512i, +) -> __m512i { + transmute(simd_select_bitmask( + k, + vgf2p8mulb_512(a.as_i8x64(), b.as_i8x64()), + src.as_i8x64(), + )) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm512_maskz_gf2p8mul_epi8(k: __mmask64, a: __m512i, b: __m512i) -> __m512i { + let zero = _mm512_setzero_si512().as_i8x64(); + transmute(simd_select_bitmask( + k, + vgf2p8mulb_512(a.as_i8x64(), b.as_i8x64()), + zero, + )) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm256_gf2p8mul_epi8(a: __m256i, b: __m256i) -> __m256i { + transmute(vgf2p8mulb_256(a.as_i8x32(), b.as_i8x32())) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm256_mask_gf2p8mul_epi8( + src: __m256i, + k: __mmask32, + a: __m256i, + b: __m256i, +) -> __m256i { + transmute(simd_select_bitmask( + k, + vgf2p8mulb_256(a.as_i8x32(), b.as_i8x32()), + src.as_i8x32(), + )) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm256_maskz_gf2p8mul_epi8(k: __mmask32, a: __m256i, b: __m256i) -> __m256i { + let zero = _mm256_setzero_si256().as_i8x32(); + transmute(simd_select_bitmask( + k, + vgf2p8mulb_256(a.as_i8x32(), b.as_i8x32()), + zero, + )) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm_gf2p8mul_epi8(a: __m128i, b: __m128i) -> __m128i { + transmute(vgf2p8mulb_128(a.as_i8x16(), b.as_i8x16())) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm_mask_gf2p8mul_epi8( + src: __m128i, + k: __mmask16, + a: __m128i, + b: __m128i, +) -> __m128i { + transmute(simd_select_bitmask( + k, + vgf2p8mulb_128(a.as_i8x16(), b.as_i8x16()), + src.as_i8x16(), + )) +} + +/// Performs a multiplication in GF(2^8) on the packed bytes. +/// The field is in polynomial representation with the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_gf2p8mul_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8mulb))] +pub unsafe fn _mm_maskz_gf2p8mul_epi8(k: __mmask16, a: __m128i, b: __m128i) -> __m128i { + let zero = _mm_setzero_si128().as_i8x16(); + transmute(simd_select_bitmask( + k, + vgf2p8mulb_128(a.as_i8x16(), b.as_i8x16()), + zero, + )) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_gf2p8affine_epi64_epi8(x: __m512i, a: __m512i, b: i32) -> __m512i { + assert!(0 <= b && b < 256); + let x = x.as_i8x64(); + let a = a.as_i8x64(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_512(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(r) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_gf2p8affine_epi64_epi8( + k: __mmask64, + x: __m512i, + a: __m512i, + b: i32, +) -> __m512i { + let zero = _mm512_setzero_si512().as_i8x64(); + assert!(0 <= b && b < 256); + let x = x.as_i8x64(); + let a = a.as_i8x64(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_512(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_gf2p8affine_epi64_epi8( + src: __m512i, + k: __mmask64, + x: __m512i, + a: __m512i, + b: i32, +) -> __m512i { + assert!(0 <= b && b < 256); + let x = x.as_i8x64(); + let a = a.as_i8x64(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_512(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, src.as_i8x64())) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm256_gf2p8affine_epi64_epi8(x: __m256i, a: __m256i, b: i32) -> __m256i { + assert!(0 <= b && b < 256); + let x = x.as_i8x32(); + let a = a.as_i8x32(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_256(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(r) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm256_maskz_gf2p8affine_epi64_epi8( + k: __mmask32, + x: __m256i, + a: __m256i, + b: i32, +) -> __m256i { + let zero = _mm256_setzero_si256().as_i8x32(); + assert!(0 <= b && b < 256); + let x = x.as_i8x32(); + let a = a.as_i8x32(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_256(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm256_mask_gf2p8affine_epi64_epi8( + src: __m256i, + k: __mmask32, + x: __m256i, + a: __m256i, + b: i32, +) -> __m256i { + assert!(0 <= b && b < 256); + let x = x.as_i8x32(); + let a = a.as_i8x32(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_256(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, src.as_i8x32())) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_gf2p8affine_epi64_epi8(x: __m128i, a: __m128i, b: i32) -> __m128i { + assert!(0 <= b && b < 256); + let x = x.as_i8x16(); + let a = a.as_i8x16(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_128(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(r) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_gf2p8affine_epi64_epi8( + k: __mmask16, + x: __m128i, + a: __m128i, + b: i32, +) -> __m128i { + let zero = _mm_setzero_si128().as_i8x16(); + assert!(0 <= b && b < 256); + let x = x.as_i8x16(); + let a = a.as_i8x16(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_128(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Performs an affine transformation on the packed bytes in x. +/// That is computes a*x+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_gf2p8affine_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineqb, b = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_gf2p8affine_epi64_epi8( + src: __m128i, + k: __mmask16, + x: __m128i, + a: __m128i, + b: i32, +) -> __m128i { + assert!(0 <= b && b < 256); + let x = x.as_i8x16(); + let a = a.as_i8x16(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineqb_128(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, src.as_i8x16())) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_gf2p8affineinv_epi64_epi8(x: __m512i, a: __m512i, b: i32) -> __m512i { + assert!(0 <= b && b < 256); + let x = x.as_i8x64(); + let a = a.as_i8x64(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_512(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(r) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_gf2p8affineinv_epi64_epi8( + k: __mmask64, + x: __m512i, + a: __m512i, + b: i32, +) -> __m512i { + assert!(0 <= b && b < 256); + let zero = _mm512_setzero_si512().as_i8x64(); + let x = x.as_i8x64(); + let a = a.as_i8x64(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_512(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512f")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_gf2p8affineinv_epi64_epi8( + src: __m512i, + k: __mmask64, + x: __m512i, + a: __m512i, + b: i32, +) -> __m512i { + assert!(0 <= b && b < 256); + let x = x.as_i8x64(); + let a = a.as_i8x64(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_512(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, src.as_i8x64())) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm256_gf2p8affineinv_epi64_epi8(x: __m256i, a: __m256i, b: i32) -> __m256i { + assert!(0 <= b && b < 256); + let x = x.as_i8x32(); + let a = a.as_i8x32(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_256(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(r) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm256_maskz_gf2p8affineinv_epi64_epi8( + k: __mmask32, + x: __m256i, + a: __m256i, + b: i32, +) -> __m256i { + assert!(0 <= b && b < 256); + let zero = _mm256_setzero_si256().as_i8x32(); + let x = x.as_i8x32(); + let a = a.as_i8x32(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_256(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm256_mask_gf2p8affineinv_epi64_epi8( + src: __m256i, + k: __mmask32, + x: __m256i, + a: __m256i, + b: i32, +) -> __m256i { + assert!(0 <= b && b < 256); + let x = x.as_i8x32(); + let a = a.as_i8x32(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_256(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, src.as_i8x32())) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm_gf2p8affineinv_epi64_epi8(x: __m128i, a: __m128i, b: i32) -> __m128i { + assert!(0 <= b && b < 256); + let x = x.as_i8x16(); + let a = a.as_i8x16(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_128(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(r) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm_maskz_gf2p8affineinv_epi64_epi8( + k: __mmask16, + x: __m128i, + a: __m128i, + b: i32, +) -> __m128i { + assert!(0 <= b && b < 256); + let zero = _mm_setzero_si128().as_i8x16(); + let x = x.as_i8x16(); + let a = a.as_i8x16(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_128(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, zero)) +} + +/// Performs an affine transformation on the inverted packed bytes in x. +/// That is computes a*inv(x)+b over the Galois Field 2^8 for each packed byte with a being a 8x8 bit matrix +/// and b being a constant 8-bit immediate value. +/// The inverse of a byte is defined with respect to the reduction polynomial x^8+x^4+x^3+x+1. +/// The inverse of 0 is 0. +/// Each pack of 8 bytes in x is paired with the 64-bit word at the same position in a. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_gf2p8affineinv_epi64_epi8) +#[inline] +#[target_feature(enable = "avx512gfni,avx512bw,avx512vl")] +#[cfg_attr(test, assert_instr(vgf2p8affineinvqb, b = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm_mask_gf2p8affineinv_epi64_epi8( + src: __m128i, + k: __mmask16, + x: __m128i, + a: __m128i, + b: i32, +) -> __m128i { + assert!(0 <= b && b < 256); + let x = x.as_i8x16(); + let a = a.as_i8x16(); + macro_rules! call { + ($imm8:expr) => { + vgf2p8affineinvqb_128(x, a, $imm8) + }; + } + let r = constify_imm8_sae!(b, call); + transmute(simd_select_bitmask(k, r, src.as_i8x16())) +} + +#[cfg(test)] +mod tests { + // The constants in the tests below are just bit patterns. They should not + // be interpreted as integers; signedness does not make sense for them, but + // __mXXXi happens to be defined in terms of signed integers. + #![allow(overflowing_literals)] + + use core::hint::black_box; + use core::intrinsics::size_of; + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + + fn mulbyte(left: u8, right: u8) -> u8 { + // this implementation follows the description in + // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_gf2p8mul_epi8 + const REDUCTION_POLYNOMIAL: u16 = 0x11b; + let left: u16 = left.into(); + let right: u16 = right.into(); + let mut carryless_product: u16 = 0; + + // Carryless multiplication + for i in 0..8 { + if ((left >> i) & 0x01) != 0 { + carryless_product ^= right << i; + } + } + + // reduction, adding in "0" where appropriate to clear out high bits + // note that REDUCTION_POLYNOMIAL is zero in this context + for i in (8..=14).rev() { + if ((carryless_product >> i) & 0x01) != 0 { + carryless_product ^= REDUCTION_POLYNOMIAL << (i - 8); + } + } + + carryless_product as u8 + } + + const NUM_TEST_WORDS_512: usize = 4; + const NUM_TEST_WORDS_256: usize = NUM_TEST_WORDS_512 * 2; + const NUM_TEST_WORDS_128: usize = NUM_TEST_WORDS_256 * 2; + const NUM_TEST_ENTRIES: usize = NUM_TEST_WORDS_512 * 64; + const NUM_TEST_WORDS_64: usize = NUM_TEST_WORDS_128 * 2; + const NUM_BYTES: usize = 256; + const NUM_BYTES_WORDS_128: usize = NUM_BYTES / 16; + const NUM_BYTES_WORDS_256: usize = NUM_BYTES_WORDS_128 / 2; + const NUM_BYTES_WORDS_512: usize = NUM_BYTES_WORDS_256 / 2; + + fn parity(input: u8) -> u8 { + let mut accumulator = 0; + for i in 0..8 { + accumulator ^= (input >> i) & 0x01; + } + accumulator + } + + fn mat_vec_multiply_affine(matrix: u64, x: u8, b: u8) -> u8 { + // this implementation follows the description in + // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_gf2p8affine_epi64_epi8 + let mut accumulator = 0; + + for bit in 0..8 { + accumulator |= parity(x & matrix.to_le_bytes()[bit]) << (7 - bit); + } + + accumulator ^ b + } + + fn generate_affine_mul_test_data( + immediate: u8, + ) -> ( + [u64; NUM_TEST_WORDS_64], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ) { + let mut left: [u64; NUM_TEST_WORDS_64] = [0; NUM_TEST_WORDS_64]; + let mut right: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + let mut result: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + + for i in 0..NUM_TEST_WORDS_64 { + left[i] = (i as u64) * 103 * 101; + for j in 0..8 { + let j64 = j as u64; + right[i * 8 + j] = ((left[i] + j64) % 256) as u8; + result[i * 8 + j] = mat_vec_multiply_affine(left[i], right[i * 8 + j], immediate); + } + } + + (left, right, result) + } + + fn generate_inv_tests_data() -> ([u8; NUM_BYTES], [u8; NUM_BYTES]) { + let mut input: [u8; NUM_BYTES] = [0; NUM_BYTES]; + let mut result: [u8; NUM_BYTES] = [0; NUM_BYTES]; + + for i in 0..NUM_BYTES { + input[i] = (i % 256) as u8; + result[i] = if i == 0 { 0 } else { 1 }; + } + + (input, result) + } + + const AES_S_BOX: [u8; NUM_BYTES] = [ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, + 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, + 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, + 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, + 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, + 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, + 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, + 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, + 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, + 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, + 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, + 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, + 0x16, + ]; + + fn generate_byte_mul_test_data() -> ( + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ) { + let mut left: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + let mut right: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + let mut result: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + + for i in 0..NUM_TEST_ENTRIES { + left[i] = (i % 256) as u8; + right[i] = left[i] * 101; + result[i] = mulbyte(left[i], right[i]); + } + + (left, right, result) + } + + #[target_feature(enable = "sse2")] + unsafe fn load_m128i_word(data: &[T], word_index: usize) -> __m128i { + let byte_offset = word_index * 16 / size_of::(); + let pointer = data.as_ptr().offset(byte_offset as isize) as *const __m128i; + _mm_loadu_si128(black_box(pointer)) + } + + #[target_feature(enable = "avx")] + unsafe fn load_m256i_word(data: &[T], word_index: usize) -> __m256i { + let byte_offset = word_index * 32 / size_of::(); + let pointer = data.as_ptr().offset(byte_offset as isize) as *const __m256i; + _mm256_loadu_si256(black_box(pointer)) + } + + #[target_feature(enable = "avx512f")] + unsafe fn load_m512i_word(data: &[T], word_index: usize) -> __m512i { + let byte_offset = word_index * 64 / size_of::(); + let pointer = data.as_ptr().offset(byte_offset as isize) as *const i32; + _mm512_loadu_si512(black_box(pointer)) + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_gf2p8mul_epi8() { + let (left, right, expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_512 { + let left = load_m512i_word(&left, i); + let right = load_m512i_word(&right, i); + let expected = load_m512i_word(&expected, i); + let result = _mm512_gf2p8mul_epi8(left, right); + assert_eq_m512i(result, expected); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_maskz_gf2p8mul_epi8() { + let (left, right, _expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_512 { + let left = load_m512i_word(&left, i); + let right = load_m512i_word(&right, i); + let result_zero = _mm512_maskz_gf2p8mul_epi8(0, left, right); + assert_eq_m512i(result_zero, _mm512_setzero_si512()); + let mask_bytes: __mmask64 = 0x0F_0F_0F_0F_FF_FF_00_00; + let mask_words: __mmask16 = 0b01_01_01_01_11_11_00_00; + let expected_result = _mm512_gf2p8mul_epi8(left, right); + let result_masked = _mm512_maskz_gf2p8mul_epi8(mask_bytes, left, right); + let expected_masked = + _mm512_mask_blend_epi32(mask_words, _mm512_setzero_si512(), expected_result); + assert_eq_m512i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_mask_gf2p8mul_epi8() { + let (left, right, _expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_512 { + let left = load_m512i_word(&left, i); + let right = load_m512i_word(&right, i); + let result_left = _mm512_mask_gf2p8mul_epi8(left, 0, left, right); + assert_eq_m512i(result_left, left); + let mask_bytes: __mmask64 = 0x0F_0F_0F_0F_FF_FF_00_00; + let mask_words: __mmask16 = 0b01_01_01_01_11_11_00_00; + let expected_result = _mm512_gf2p8mul_epi8(left, right); + let result_masked = _mm512_mask_gf2p8mul_epi8(left, mask_bytes, left, right); + let expected_masked = _mm512_mask_blend_epi32(mask_words, left, expected_result); + assert_eq_m512i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_gf2p8mul_epi8() { + let (left, right, expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_256 { + let left = load_m256i_word(&left, i); + let right = load_m256i_word(&right, i); + let expected = load_m256i_word(&expected, i); + let result = _mm256_gf2p8mul_epi8(left, right); + assert_eq_m256i(result, expected); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_gf2p8mul_epi8() { + let (left, right, _expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_256 { + let left = load_m256i_word(&left, i); + let right = load_m256i_word(&right, i); + let result_zero = _mm256_maskz_gf2p8mul_epi8(0, left, right); + assert_eq_m256i(result_zero, _mm256_setzero_si256()); + let mask_bytes: __mmask32 = 0x0F_F0_FF_00; + const MASK_WORDS: i32 = 0b01_10_11_00; + let expected_result = _mm256_gf2p8mul_epi8(left, right); + let result_masked = _mm256_maskz_gf2p8mul_epi8(mask_bytes, left, right); + let expected_masked = + _mm256_blend_epi32(_mm256_setzero_si256(), expected_result, MASK_WORDS); + assert_eq_m256i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_mask_gf2p8mul_epi8() { + let (left, right, _expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_256 { + let left = load_m256i_word(&left, i); + let right = load_m256i_word(&right, i); + let result_left = _mm256_mask_gf2p8mul_epi8(left, 0, left, right); + assert_eq_m256i(result_left, left); + let mask_bytes: __mmask32 = 0x0F_F0_FF_00; + const MASK_WORDS: i32 = 0b01_10_11_00; + let expected_result = _mm256_gf2p8mul_epi8(left, right); + let result_masked = _mm256_mask_gf2p8mul_epi8(left, mask_bytes, left, right); + let expected_masked = _mm256_blend_epi32(left, expected_result, MASK_WORDS); + assert_eq_m256i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_gf2p8mul_epi8() { + let (left, right, expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_128 { + let left = load_m128i_word(&left, i); + let right = load_m128i_word(&right, i); + let expected = load_m128i_word(&expected, i); + let result = _mm_gf2p8mul_epi8(left, right); + assert_eq_m128i(result, expected); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_maskz_gf2p8mul_epi8() { + let (left, right, _expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_128 { + let left = load_m128i_word(&left, i); + let right = load_m128i_word(&right, i); + let result_zero = _mm_maskz_gf2p8mul_epi8(0, left, right); + assert_eq_m128i(result_zero, _mm_setzero_si128()); + let mask_bytes: __mmask16 = 0x0F_F0; + const MASK_WORDS: i32 = 0b01_10; + let expected_result = _mm_gf2p8mul_epi8(left, right); + let result_masked = _mm_maskz_gf2p8mul_epi8(mask_bytes, left, right); + let expected_masked = _mm_blend_epi32(_mm_setzero_si128(), expected_result, MASK_WORDS); + assert_eq_m128i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_mask_gf2p8mul_epi8() { + let (left, right, _expected) = generate_byte_mul_test_data(); + + for i in 0..NUM_TEST_WORDS_128 { + let left = load_m128i_word(&left, i); + let right = load_m128i_word(&right, i); + let result_left = _mm_mask_gf2p8mul_epi8(left, 0, left, right); + assert_eq_m128i(result_left, left); + let mask_bytes: __mmask16 = 0x0F_F0; + const MASK_WORDS: i32 = 0b01_10; + let expected_result = _mm_gf2p8mul_epi8(left, right); + let result_masked = _mm_mask_gf2p8mul_epi8(left, mask_bytes, left, right); + let expected_masked = _mm_blend_epi32(left, expected_result, MASK_WORDS); + assert_eq_m128i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_gf2p8affine_epi64_epi8() { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + const IDENTITY_BYTE: i32 = 0; + let constant: i64 = 0; + const CONSTANT_BYTE: i32 = 0x63; + let identity = _mm512_set1_epi64(identity); + let constant = _mm512_set1_epi64(constant); + let constant_reference = _mm512_set1_epi8(CONSTANT_BYTE as i8); + + let (bytes, more_bytes, _) = generate_byte_mul_test_data(); + let (matrices, vectors, references) = generate_affine_mul_test_data(IDENTITY_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_512 { + let data = load_m512i_word(&bytes, i); + let result = _mm512_gf2p8affine_epi64_epi8(data, identity, IDENTITY_BYTE); + assert_eq_m512i(result, data); + let result = _mm512_gf2p8affine_epi64_epi8(data, constant, CONSTANT_BYTE); + assert_eq_m512i(result, constant_reference); + let data = load_m512i_word(&more_bytes, i); + let result = _mm512_gf2p8affine_epi64_epi8(data, identity, IDENTITY_BYTE); + assert_eq_m512i(result, data); + let result = _mm512_gf2p8affine_epi64_epi8(data, constant, CONSTANT_BYTE); + assert_eq_m512i(result, constant_reference); + + let matrix = load_m512i_word(&matrices, i); + let vector = load_m512i_word(&vectors, i); + let reference = load_m512i_word(&references, i); + + let result = _mm512_gf2p8affine_epi64_epi8(vector, matrix, IDENTITY_BYTE); + assert_eq_m512i(result, reference); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_maskz_gf2p8affine_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_512 { + let matrix = load_m512i_word(&matrices, i); + let vector = load_m512i_word(&vectors, i); + let result_zero = _mm512_maskz_gf2p8affine_epi64_epi8(0, vector, matrix, CONSTANT_BYTE); + assert_eq_m512i(result_zero, _mm512_setzero_si512()); + let mask_bytes: __mmask64 = 0x0F_0F_0F_0F_FF_FF_00_00; + let mask_words: __mmask16 = 0b01_01_01_01_11_11_00_00; + let expected_result = _mm512_gf2p8affine_epi64_epi8(vector, matrix, CONSTANT_BYTE); + let result_masked = + _mm512_maskz_gf2p8affine_epi64_epi8(mask_bytes, vector, matrix, CONSTANT_BYTE); + let expected_masked = + _mm512_mask_blend_epi32(mask_words, _mm512_setzero_si512(), expected_result); + assert_eq_m512i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_mask_gf2p8affine_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_512 { + let left = load_m512i_word(&vectors, i); + let right = load_m512i_word(&matrices, i); + let result_left = + _mm512_mask_gf2p8affine_epi64_epi8(left, 0, left, right, CONSTANT_BYTE); + assert_eq_m512i(result_left, left); + let mask_bytes: __mmask64 = 0x0F_0F_0F_0F_FF_FF_00_00; + let mask_words: __mmask16 = 0b01_01_01_01_11_11_00_00; + let expected_result = _mm512_gf2p8affine_epi64_epi8(left, right, CONSTANT_BYTE); + let result_masked = + _mm512_mask_gf2p8affine_epi64_epi8(left, mask_bytes, left, right, CONSTANT_BYTE); + let expected_masked = _mm512_mask_blend_epi32(mask_words, left, expected_result); + assert_eq_m512i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_gf2p8affine_epi64_epi8() { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + const IDENTITY_BYTE: i32 = 0; + let constant: i64 = 0; + const CONSTANT_BYTE: i32 = 0x63; + let identity = _mm256_set1_epi64x(identity); + let constant = _mm256_set1_epi64x(constant); + let constant_reference = _mm256_set1_epi8(CONSTANT_BYTE as i8); + + let (bytes, more_bytes, _) = generate_byte_mul_test_data(); + let (matrices, vectors, references) = generate_affine_mul_test_data(IDENTITY_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_256 { + let data = load_m256i_word(&bytes, i); + let result = _mm256_gf2p8affine_epi64_epi8(data, identity, IDENTITY_BYTE); + assert_eq_m256i(result, data); + let result = _mm256_gf2p8affine_epi64_epi8(data, constant, CONSTANT_BYTE); + assert_eq_m256i(result, constant_reference); + let data = load_m256i_word(&more_bytes, i); + let result = _mm256_gf2p8affine_epi64_epi8(data, identity, IDENTITY_BYTE); + assert_eq_m256i(result, data); + let result = _mm256_gf2p8affine_epi64_epi8(data, constant, CONSTANT_BYTE); + assert_eq_m256i(result, constant_reference); + + let matrix = load_m256i_word(&matrices, i); + let vector = load_m256i_word(&vectors, i); + let reference = load_m256i_word(&references, i); + + let result = _mm256_gf2p8affine_epi64_epi8(vector, matrix, IDENTITY_BYTE); + assert_eq_m256i(result, reference); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_gf2p8affine_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_256 { + let matrix = load_m256i_word(&matrices, i); + let vector = load_m256i_word(&vectors, i); + let result_zero = _mm256_maskz_gf2p8affine_epi64_epi8(0, vector, matrix, CONSTANT_BYTE); + assert_eq_m256i(result_zero, _mm256_setzero_si256()); + let mask_bytes: __mmask32 = 0xFF_0F_F0_00; + const MASK_WORDS: i32 = 0b11_01_10_00; + let expected_result = _mm256_gf2p8affine_epi64_epi8(vector, matrix, CONSTANT_BYTE); + let result_masked = + _mm256_maskz_gf2p8affine_epi64_epi8(mask_bytes, vector, matrix, CONSTANT_BYTE); + let expected_masked = + _mm256_blend_epi32(_mm256_setzero_si256(), expected_result, MASK_WORDS); + assert_eq_m256i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_mask_gf2p8affine_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_256 { + let left = load_m256i_word(&vectors, i); + let right = load_m256i_word(&matrices, i); + let result_left = + _mm256_mask_gf2p8affine_epi64_epi8(left, 0, left, right, CONSTANT_BYTE); + assert_eq_m256i(result_left, left); + let mask_bytes: __mmask32 = 0xFF_0F_F0_00; + const MASK_WORDS: i32 = 0b11_01_10_00; + let expected_result = _mm256_gf2p8affine_epi64_epi8(left, right, CONSTANT_BYTE); + let result_masked = + _mm256_mask_gf2p8affine_epi64_epi8(left, mask_bytes, left, right, CONSTANT_BYTE); + let expected_masked = _mm256_blend_epi32(left, expected_result, MASK_WORDS); + assert_eq_m256i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_gf2p8affine_epi64_epi8() { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + const IDENTITY_BYTE: i32 = 0; + let constant: i64 = 0; + const CONSTANT_BYTE: i32 = 0x63; + let identity = _mm_set1_epi64x(identity); + let constant = _mm_set1_epi64x(constant); + let constant_reference = _mm_set1_epi8(CONSTANT_BYTE as i8); + + let (bytes, more_bytes, _) = generate_byte_mul_test_data(); + let (matrices, vectors, references) = generate_affine_mul_test_data(IDENTITY_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_128 { + let data = load_m128i_word(&bytes, i); + let result = _mm_gf2p8affine_epi64_epi8(data, identity, IDENTITY_BYTE); + assert_eq_m128i(result, data); + let result = _mm_gf2p8affine_epi64_epi8(data, constant, CONSTANT_BYTE); + assert_eq_m128i(result, constant_reference); + let data = load_m128i_word(&more_bytes, i); + let result = _mm_gf2p8affine_epi64_epi8(data, identity, IDENTITY_BYTE); + assert_eq_m128i(result, data); + let result = _mm_gf2p8affine_epi64_epi8(data, constant, CONSTANT_BYTE); + assert_eq_m128i(result, constant_reference); + + let matrix = load_m128i_word(&matrices, i); + let vector = load_m128i_word(&vectors, i); + let reference = load_m128i_word(&references, i); + + let result = _mm_gf2p8affine_epi64_epi8(vector, matrix, IDENTITY_BYTE); + assert_eq_m128i(result, reference); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_maskz_gf2p8affine_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_128 { + let matrix = load_m128i_word(&matrices, i); + let vector = load_m128i_word(&vectors, i); + let result_zero = _mm_maskz_gf2p8affine_epi64_epi8(0, vector, matrix, CONSTANT_BYTE); + assert_eq_m128i(result_zero, _mm_setzero_si128()); + let mask_bytes: __mmask16 = 0x0F_F0; + const MASK_WORDS: i32 = 0b01_10; + let expected_result = _mm_gf2p8affine_epi64_epi8(vector, matrix, CONSTANT_BYTE); + let result_masked = + _mm_maskz_gf2p8affine_epi64_epi8(mask_bytes, vector, matrix, CONSTANT_BYTE); + let expected_masked = _mm_blend_epi32(_mm_setzero_si128(), expected_result, MASK_WORDS); + assert_eq_m128i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_mask_gf2p8affine_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_128 { + let left = load_m128i_word(&vectors, i); + let right = load_m128i_word(&matrices, i); + let result_left = _mm_mask_gf2p8affine_epi64_epi8(left, 0, left, right, CONSTANT_BYTE); + assert_eq_m128i(result_left, left); + let mask_bytes: __mmask16 = 0x0F_F0; + const MASK_WORDS: i32 = 0b01_10; + let expected_result = _mm_gf2p8affine_epi64_epi8(left, right, CONSTANT_BYTE); + let result_masked = + _mm_mask_gf2p8affine_epi64_epi8(left, mask_bytes, left, right, CONSTANT_BYTE); + let expected_masked = _mm_blend_epi32(left, expected_result, MASK_WORDS); + assert_eq_m128i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_gf2p8affineinv_epi64_epi8() { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + const IDENTITY_BYTE: i32 = 0; + const CONSTANT_BYTE: i32 = 0x63; + let identity = _mm512_set1_epi64(identity); + + // validate inversion + let (inputs, results) = generate_inv_tests_data(); + + for i in 0..NUM_BYTES_WORDS_512 { + let input = load_m512i_word(&inputs, i); + let reference = load_m512i_word(&results, i); + let result = _mm512_gf2p8affineinv_epi64_epi8(input, identity, IDENTITY_BYTE); + let remultiplied = _mm512_gf2p8mul_epi8(result, input); + assert_eq_m512i(remultiplied, reference); + } + + // validate subsequent affine operation + let (matrices, vectors, _affine_expected) = + generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_512 { + let vector = load_m512i_word(&vectors, i); + let matrix = load_m512i_word(&matrices, i); + + let inv_vec = _mm512_gf2p8affineinv_epi64_epi8(vector, identity, IDENTITY_BYTE); + let reference = _mm512_gf2p8affine_epi64_epi8(inv_vec, matrix, CONSTANT_BYTE); + let result = _mm512_gf2p8affineinv_epi64_epi8(vector, matrix, CONSTANT_BYTE); + assert_eq_m512i(result, reference); + } + + // validate everything by virtue of checking against the AES SBox + const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8; + let sbox_matrix = _mm512_set1_epi64(AES_S_BOX_MATRIX); + + for i in 0..NUM_BYTES_WORDS_512 { + let reference = load_m512i_word(&AES_S_BOX, i); + let input = load_m512i_word(&inputs, i); + let result = _mm512_gf2p8affineinv_epi64_epi8(input, sbox_matrix, CONSTANT_BYTE); + assert_eq_m512i(result, reference); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_maskz_gf2p8affineinv_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_512 { + let matrix = load_m512i_word(&matrices, i); + let vector = load_m512i_word(&vectors, i); + let result_zero = + _mm512_maskz_gf2p8affineinv_epi64_epi8(0, vector, matrix, CONSTANT_BYTE); + assert_eq_m512i(result_zero, _mm512_setzero_si512()); + let mask_bytes: __mmask64 = 0x0F_0F_0F_0F_FF_FF_00_00; + let mask_words: __mmask16 = 0b01_01_01_01_11_11_00_00; + let expected_result = _mm512_gf2p8affineinv_epi64_epi8(vector, matrix, CONSTANT_BYTE); + let result_masked = + _mm512_maskz_gf2p8affineinv_epi64_epi8(mask_bytes, vector, matrix, CONSTANT_BYTE); + let expected_masked = + _mm512_mask_blend_epi32(mask_words, _mm512_setzero_si512(), expected_result); + assert_eq_m512i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw")] + unsafe fn test_mm512_mask_gf2p8affineinv_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_512 { + let left = load_m512i_word(&vectors, i); + let right = load_m512i_word(&matrices, i); + let result_left = + _mm512_mask_gf2p8affineinv_epi64_epi8(left, 0, left, right, CONSTANT_BYTE); + assert_eq_m512i(result_left, left); + let mask_bytes: __mmask64 = 0x0F_0F_0F_0F_FF_FF_00_00; + let mask_words: __mmask16 = 0b01_01_01_01_11_11_00_00; + let expected_result = _mm512_gf2p8affineinv_epi64_epi8(left, right, CONSTANT_BYTE); + let result_masked = + _mm512_mask_gf2p8affineinv_epi64_epi8(left, mask_bytes, left, right, CONSTANT_BYTE); + let expected_masked = _mm512_mask_blend_epi32(mask_words, left, expected_result); + assert_eq_m512i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_gf2p8affineinv_epi64_epi8() { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + const IDENTITY_BYTE: i32 = 0; + const CONSTANT_BYTE: i32 = 0x63; + let identity = _mm256_set1_epi64x(identity); + + // validate inversion + let (inputs, results) = generate_inv_tests_data(); + + for i in 0..NUM_BYTES_WORDS_256 { + let input = load_m256i_word(&inputs, i); + let reference = load_m256i_word(&results, i); + let result = _mm256_gf2p8affineinv_epi64_epi8(input, identity, IDENTITY_BYTE); + let remultiplied = _mm256_gf2p8mul_epi8(result, input); + assert_eq_m256i(remultiplied, reference); + } + + // validate subsequent affine operation + let (matrices, vectors, _affine_expected) = + generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_256 { + let vector = load_m256i_word(&vectors, i); + let matrix = load_m256i_word(&matrices, i); + + let inv_vec = _mm256_gf2p8affineinv_epi64_epi8(vector, identity, IDENTITY_BYTE); + let reference = _mm256_gf2p8affine_epi64_epi8(inv_vec, matrix, CONSTANT_BYTE); + let result = _mm256_gf2p8affineinv_epi64_epi8(vector, matrix, CONSTANT_BYTE); + assert_eq_m256i(result, reference); + } + + // validate everything by virtue of checking against the AES SBox + const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8; + let sbox_matrix = _mm256_set1_epi64x(AES_S_BOX_MATRIX); + + for i in 0..NUM_BYTES_WORDS_256 { + let reference = load_m256i_word(&AES_S_BOX, i); + let input = load_m256i_word(&inputs, i); + let result = _mm256_gf2p8affineinv_epi64_epi8(input, sbox_matrix, CONSTANT_BYTE); + assert_eq_m256i(result, reference); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_maskz_gf2p8affineinv_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_256 { + let matrix = load_m256i_word(&matrices, i); + let vector = load_m256i_word(&vectors, i); + let result_zero = + _mm256_maskz_gf2p8affineinv_epi64_epi8(0, vector, matrix, CONSTANT_BYTE); + assert_eq_m256i(result_zero, _mm256_setzero_si256()); + let mask_bytes: __mmask32 = 0xFF_0F_F0_00; + const MASK_WORDS: i32 = 0b11_01_10_00; + let expected_result = _mm256_gf2p8affineinv_epi64_epi8(vector, matrix, CONSTANT_BYTE); + let result_masked = + _mm256_maskz_gf2p8affineinv_epi64_epi8(mask_bytes, vector, matrix, CONSTANT_BYTE); + let expected_masked = + _mm256_blend_epi32(_mm256_setzero_si256(), expected_result, MASK_WORDS); + assert_eq_m256i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm256_mask_gf2p8affineinv_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_256 { + let left = load_m256i_word(&vectors, i); + let right = load_m256i_word(&matrices, i); + let result_left = + _mm256_mask_gf2p8affineinv_epi64_epi8(left, 0, left, right, CONSTANT_BYTE); + assert_eq_m256i(result_left, left); + let mask_bytes: __mmask32 = 0xFF_0F_F0_00; + const MASK_WORDS: i32 = 0b11_01_10_00; + let expected_result = _mm256_gf2p8affineinv_epi64_epi8(left, right, CONSTANT_BYTE); + let result_masked = + _mm256_mask_gf2p8affineinv_epi64_epi8(left, mask_bytes, left, right, CONSTANT_BYTE); + let expected_masked = _mm256_blend_epi32(left, expected_result, MASK_WORDS); + assert_eq_m256i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_gf2p8affineinv_epi64_epi8() { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + const IDENTITY_BYTE: i32 = 0; + const CONSTANT_BYTE: i32 = 0x63; + let identity = _mm_set1_epi64x(identity); + + // validate inversion + let (inputs, results) = generate_inv_tests_data(); + + for i in 0..NUM_BYTES_WORDS_128 { + let input = load_m128i_word(&inputs, i); + let reference = load_m128i_word(&results, i); + let result = _mm_gf2p8affineinv_epi64_epi8(input, identity, IDENTITY_BYTE); + let remultiplied = _mm_gf2p8mul_epi8(result, input); + assert_eq_m128i(remultiplied, reference); + } + + // validate subsequent affine operation + let (matrices, vectors, _affine_expected) = + generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_128 { + let vector = load_m128i_word(&vectors, i); + let matrix = load_m128i_word(&matrices, i); + + let inv_vec = _mm_gf2p8affineinv_epi64_epi8(vector, identity, IDENTITY_BYTE); + let reference = _mm_gf2p8affine_epi64_epi8(inv_vec, matrix, CONSTANT_BYTE); + let result = _mm_gf2p8affineinv_epi64_epi8(vector, matrix, CONSTANT_BYTE); + assert_eq_m128i(result, reference); + } + + // validate everything by virtue of checking against the AES SBox + const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8; + let sbox_matrix = _mm_set1_epi64x(AES_S_BOX_MATRIX); + + for i in 0..NUM_BYTES_WORDS_128 { + let reference = load_m128i_word(&AES_S_BOX, i); + let input = load_m128i_word(&inputs, i); + let result = _mm_gf2p8affineinv_epi64_epi8(input, sbox_matrix, CONSTANT_BYTE); + assert_eq_m128i(result, reference); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_maskz_gf2p8affineinv_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_128 { + let matrix = load_m128i_word(&matrices, i); + let vector = load_m128i_word(&vectors, i); + let result_zero = _mm_maskz_gf2p8affineinv_epi64_epi8(0, vector, matrix, CONSTANT_BYTE); + assert_eq_m128i(result_zero, _mm_setzero_si128()); + let mask_bytes: __mmask16 = 0x0F_F0; + const MASK_WORDS: i32 = 0b01_10; + let expected_result = _mm_gf2p8affineinv_epi64_epi8(vector, matrix, CONSTANT_BYTE); + let result_masked = + _mm_maskz_gf2p8affineinv_epi64_epi8(mask_bytes, vector, matrix, CONSTANT_BYTE); + let expected_masked = _mm_blend_epi32(_mm_setzero_si128(), expected_result, MASK_WORDS); + assert_eq_m128i(result_masked, expected_masked); + } + } + + #[simd_test(enable = "avx512gfni,avx512bw,avx512vl")] + unsafe fn test_mm_mask_gf2p8affineinv_epi64_epi8() { + const CONSTANT_BYTE: i32 = 0x63; + let (matrices, vectors, _expected) = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + + for i in 0..NUM_TEST_WORDS_128 { + let left = load_m128i_word(&vectors, i); + let right = load_m128i_word(&matrices, i); + let result_left = + _mm_mask_gf2p8affineinv_epi64_epi8(left, 0, left, right, CONSTANT_BYTE); + assert_eq_m128i(result_left, left); + let mask_bytes: __mmask16 = 0x0F_F0; + const MASK_WORDS: i32 = 0b01_10; + let expected_result = _mm_gf2p8affineinv_epi64_epi8(left, right, CONSTANT_BYTE); + let result_masked = + _mm_mask_gf2p8affineinv_epi64_epi8(left, mask_bytes, left, right, CONSTANT_BYTE); + let expected_masked = _mm_blend_epi32(left, expected_result, MASK_WORDS); + assert_eq_m128i(result_masked, expected_masked); + } + } +} diff --git a/library/stdarch/crates/core_arch/src/x86/avx512ifma.rs b/library/stdarch/crates/core_arch/src/x86/avx512ifma.rs index 425d0ff7e5..26aa0320f2 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512ifma.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512ifma.rs @@ -105,7 +105,7 @@ extern "C" { #[cfg(test)] mod tests { - use std; + use stdarch_test::simd_test; use crate::core_arch::x86::*; diff --git a/library/stdarch/crates/core_arch/src/x86/avx512vaes.rs b/library/stdarch/crates/core_arch/src/x86/avx512vaes.rs new file mode 100644 index 0000000000..b9d8433b4b --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/avx512vaes.rs @@ -0,0 +1,332 @@ +//! Vectorized AES Instructions (VAES) +//! +//! The intrinsics here correspond to those in the `immintrin.h` C header. +//! +//! The reference is [Intel 64 and IA-32 Architectures Software Developer's +//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref]. +//! +//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + +use crate::core_arch::x86::__m256i; +use crate::core_arch::x86::__m512i; + +#[cfg(test)] +use stdarch_test::assert_instr; + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.aesni.aesenc.256"] + fn aesenc_256(a: __m256i, round_key: __m256i) -> __m256i; + #[link_name = "llvm.x86.aesni.aesenclast.256"] + fn aesenclast_256(a: __m256i, round_key: __m256i) -> __m256i; + #[link_name = "llvm.x86.aesni.aesdec.256"] + fn aesdec_256(a: __m256i, round_key: __m256i) -> __m256i; + #[link_name = "llvm.x86.aesni.aesdeclast.256"] + fn aesdeclast_256(a: __m256i, round_key: __m256i) -> __m256i; + #[link_name = "llvm.x86.aesni.aesenc.512"] + fn aesenc_512(a: __m512i, round_key: __m512i) -> __m512i; + #[link_name = "llvm.x86.aesni.aesenclast.512"] + fn aesenclast_512(a: __m512i, round_key: __m512i) -> __m512i; + #[link_name = "llvm.x86.aesni.aesdec.512"] + fn aesdec_512(a: __m512i, round_key: __m512i) -> __m512i; + #[link_name = "llvm.x86.aesni.aesdeclast.512"] + fn aesdeclast_512(a: __m512i, round_key: __m512i) -> __m512i; +} + +/// Performs one round of an AES encryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_aesenc_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512vl")] +#[cfg_attr(test, assert_instr(vaesenc))] +pub unsafe fn _mm256_aesenc_epi128(a: __m256i, round_key: __m256i) -> __m256i { + aesenc_256(a, round_key) +} + +/// Performs the last round of an AES encryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_aesenclast_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512vl")] +#[cfg_attr(test, assert_instr(vaesenclast))] +pub unsafe fn _mm256_aesenclast_epi128(a: __m256i, round_key: __m256i) -> __m256i { + aesenclast_256(a, round_key) +} + +/// Performs one round of an AES decryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_aesdec_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512vl")] +#[cfg_attr(test, assert_instr(vaesdec))] +pub unsafe fn _mm256_aesdec_epi128(a: __m256i, round_key: __m256i) -> __m256i { + aesdec_256(a, round_key) +} + +/// Performs the last round of an AES decryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_aesdeclast_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512vl")] +#[cfg_attr(test, assert_instr(vaesdeclast))] +pub unsafe fn _mm256_aesdeclast_epi128(a: __m256i, round_key: __m256i) -> __m256i { + aesdeclast_256(a, round_key) +} + +/// Performs one round of an AES encryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_aesenc_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512f")] +#[cfg_attr(test, assert_instr(vaesenc))] +pub unsafe fn _mm512_aesenc_epi128(a: __m512i, round_key: __m512i) -> __m512i { + aesenc_512(a, round_key) +} + +/// Performs the last round of an AES encryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_aesenclast_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512f")] +#[cfg_attr(test, assert_instr(vaesenclast))] +pub unsafe fn _mm512_aesenclast_epi128(a: __m512i, round_key: __m512i) -> __m512i { + aesenclast_512(a, round_key) +} + +/// Performs one round of an AES decryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_aesdec_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512f")] +#[cfg_attr(test, assert_instr(vaesdec))] +pub unsafe fn _mm512_aesdec_epi128(a: __m512i, round_key: __m512i) -> __m512i { + aesdec_512(a, round_key) +} + +/// Performs the last round of an AES decryption flow on each 128-bit word (state) in `a` using +/// the corresponding 128-bit word (key) in `round_key`. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_aesdeclast_epi128) +#[inline] +#[target_feature(enable = "avx512vaes,avx512f")] +#[cfg_attr(test, assert_instr(vaesdeclast))] +pub unsafe fn _mm512_aesdeclast_epi128(a: __m512i, round_key: __m512i) -> __m512i { + aesdeclast_512(a, round_key) +} + +#[cfg(test)] +mod tests { + // The constants in the tests below are just bit patterns. They should not + // be interpreted as integers; signedness does not make sense for them, but + // __mXXXi happens to be defined in terms of signed integers. + #![allow(overflowing_literals)] + + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + + // the first parts of these tests are straight ports from the AES-NI tests + // the second parts directly compare the two, for inputs that are different across lanes + // and "more random" than the standard test vectors + // ideally we'd be using quickcheck here instead + + #[target_feature(enable = "avx2")] + unsafe fn helper_for_256_avx512vaes( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m256i, __m256i) -> __m256i, + ) { + let a = _mm256_set_epi64x( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + ); + let k = _mm256_set_epi64x( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + ); + let mut a_decomp = [_mm_setzero_si128(); 2]; + a_decomp[0] = _mm256_extracti128_si256(a, 0); + a_decomp[1] = _mm256_extracti128_si256(a, 1); + let mut k_decomp = [_mm_setzero_si128(); 2]; + k_decomp[0] = _mm256_extracti128_si256(k, 0); + k_decomp[1] = _mm256_extracti128_si256(k, 1); + let r = vectorized(a, k); + let mut e_decomp = [_mm_setzero_si128(); 2]; + for i in 0..2 { + e_decomp[i] = linear(a_decomp[i], k_decomp[i]); + } + assert_eq_m128i(_mm256_extracti128_si256(r, 0), e_decomp[0]); + assert_eq_m128i(_mm256_extracti128_si256(r, 1), e_decomp[1]); + } + + #[target_feature(enable = "sse2")] + unsafe fn setup_state_key(broadcast: unsafe fn(__m128i) -> T) -> (T, T) { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc664949.aspx. + let a = _mm_set_epi64x(0x0123456789abcdef, 0x8899aabbccddeeff); + let k = _mm_set_epi64x(0x1133557799bbddff, 0x0022446688aaccee); + (broadcast(a), broadcast(k)) + } + + #[target_feature(enable = "avx2")] + unsafe fn setup_state_key_256() -> (__m256i, __m256i) { + setup_state_key(_mm256_broadcastsi128_si256) + } + + #[target_feature(enable = "avx512f")] + unsafe fn setup_state_key_512() -> (__m512i, __m512i) { + setup_state_key(_mm512_broadcast_i32x4) + } + + #[simd_test(enable = "avx512vaes,avx512vl")] + unsafe fn test_mm256_aesdec_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc664949.aspx. + let (a, k) = setup_state_key_256(); + let e = _mm_set_epi64x(0x044e4f5176fec48f, 0xb57ecfa381da39ee); + let e = _mm256_broadcastsi128_si256(e); + let r = _mm256_aesdec_epi128(a, k); + assert_eq_m256i(r, e); + + helper_for_256_avx512vaes(_mm_aesdec_si128, _mm256_aesdec_epi128); + } + + #[simd_test(enable = "avx512vaes,avx512vl")] + unsafe fn test_mm256_aesdeclast_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc714178.aspx. + let (a, k) = setup_state_key_256(); + let e = _mm_set_epi64x(0x36cad57d9072bf9e, 0xf210dd981fa4a493); + let e = _mm256_broadcastsi128_si256(e); + let r = _mm256_aesdeclast_epi128(a, k); + assert_eq_m256i(r, e); + + helper_for_256_avx512vaes(_mm_aesdeclast_si128, _mm256_aesdeclast_epi128); + } + + #[simd_test(enable = "avx512vaes,avx512vl")] + unsafe fn test_mm256_aesenc_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc664810.aspx. + // they are repeated appropriately + let (a, k) = setup_state_key_256(); + let e = _mm_set_epi64x(0x16ab0e57dfc442ed, 0x28e4ee1884504333); + let e = _mm256_broadcastsi128_si256(e); + let r = _mm256_aesenc_epi128(a, k); + assert_eq_m256i(r, e); + + helper_for_256_avx512vaes(_mm_aesenc_si128, _mm256_aesenc_epi128); + } + + #[simd_test(enable = "avx512vaes,avx512vl")] + unsafe fn test_mm256_aesenclast_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc714136.aspx. + let (a, k) = setup_state_key_256(); + let e = _mm_set_epi64x(0xb6dd7df25d7ab320, 0x4b04f98cf4c860f8); + let e = _mm256_broadcastsi128_si256(e); + let r = _mm256_aesenclast_epi128(a, k); + assert_eq_m256i(r, e); + + helper_for_256_avx512vaes(_mm_aesenclast_si128, _mm256_aesenclast_epi128); + } + + #[target_feature(enable = "avx512f")] + unsafe fn helper_for_512_avx512vaes( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m512i, __m512i) -> __m512i, + ) { + let a = _mm512_set_epi64( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + 0xAB05CFFA2621154C, + 0x1171B47A186174C9, + 0x8C6B6C0E7595CEC9, + 0xBE3E7D4934E961BD, + ); + let k = _mm512_set_epi64( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + 0xB1927AB22F31D0EC, + 0xA9A5DA619BE4D7AF, + 0xCA2590F56884FDC6, + 0x19BE9F660038BDB5, + ); + let mut a_decomp = [_mm_setzero_si128(); 4]; + a_decomp[0] = _mm512_extracti32x4_epi32(a, 0); + a_decomp[1] = _mm512_extracti32x4_epi32(a, 1); + a_decomp[2] = _mm512_extracti32x4_epi32(a, 2); + a_decomp[3] = _mm512_extracti32x4_epi32(a, 3); + let mut k_decomp = [_mm_setzero_si128(); 4]; + k_decomp[0] = _mm512_extracti32x4_epi32(k, 0); + k_decomp[1] = _mm512_extracti32x4_epi32(k, 1); + k_decomp[2] = _mm512_extracti32x4_epi32(k, 2); + k_decomp[3] = _mm512_extracti32x4_epi32(k, 3); + let r = vectorized(a, k); + let mut e_decomp = [_mm_setzero_si128(); 4]; + for i in 0..4 { + e_decomp[i] = linear(a_decomp[i], k_decomp[i]); + } + assert_eq_m128i(_mm512_extracti32x4_epi32(r, 0), e_decomp[0]); + assert_eq_m128i(_mm512_extracti32x4_epi32(r, 1), e_decomp[1]); + assert_eq_m128i(_mm512_extracti32x4_epi32(r, 2), e_decomp[2]); + assert_eq_m128i(_mm512_extracti32x4_epi32(r, 3), e_decomp[3]); + } + + #[simd_test(enable = "avx512vaes,avx512f")] + unsafe fn test_mm512_aesdec_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc664949.aspx. + let (a, k) = setup_state_key_512(); + let e = _mm_set_epi64x(0x044e4f5176fec48f, 0xb57ecfa381da39ee); + let e = _mm512_broadcast_i32x4(e); + let r = _mm512_aesdec_epi128(a, k); + assert_eq_m512i(r, e); + + helper_for_512_avx512vaes(_mm_aesdec_si128, _mm512_aesdec_epi128); + } + + #[simd_test(enable = "avx512vaes,avx512f")] + unsafe fn test_mm512_aesdeclast_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc714178.aspx. + let (a, k) = setup_state_key_512(); + let e = _mm_set_epi64x(0x36cad57d9072bf9e, 0xf210dd981fa4a493); + let e = _mm512_broadcast_i32x4(e); + let r = _mm512_aesdeclast_epi128(a, k); + assert_eq_m512i(r, e); + + helper_for_512_avx512vaes(_mm_aesdeclast_si128, _mm512_aesdeclast_epi128); + } + + #[simd_test(enable = "avx512vaes,avx512f")] + unsafe fn test_mm512_aesenc_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc664810.aspx. + let (a, k) = setup_state_key_512(); + let e = _mm_set_epi64x(0x16ab0e57dfc442ed, 0x28e4ee1884504333); + let e = _mm512_broadcast_i32x4(e); + let r = _mm512_aesenc_epi128(a, k); + assert_eq_m512i(r, e); + + helper_for_512_avx512vaes(_mm_aesenc_si128, _mm512_aesenc_epi128); + } + + #[simd_test(enable = "avx512vaes,avx512f")] + unsafe fn test_mm512_aesenclast_epi128() { + // Constants taken from https://msdn.microsoft.com/en-us/library/cc714136.aspx. + let (a, k) = setup_state_key_512(); + let e = _mm_set_epi64x(0xb6dd7df25d7ab320, 0x4b04f98cf4c860f8); + let e = _mm512_broadcast_i32x4(e); + let r = _mm512_aesenclast_epi128(a, k); + assert_eq_m512i(r, e); + + helper_for_512_avx512vaes(_mm_aesenclast_si128, _mm512_aesenclast_epi128); + } +} diff --git a/library/stdarch/crates/core_arch/src/x86/avx512vpclmulqdq.rs b/library/stdarch/crates/core_arch/src/x86/avx512vpclmulqdq.rs new file mode 100644 index 0000000000..831ab7f642 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/avx512vpclmulqdq.rs @@ -0,0 +1,266 @@ +//! Vectorized Carry-less Multiplication (VCLMUL) +//! +//! The reference is [Intel 64 and IA-32 Architectures Software Developer's +//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref] (p. 4-241). +//! +//! [intel64_ref]: http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + +use crate::core_arch::x86::__m256i; +use crate::core_arch::x86::__m512i; + +#[cfg(test)] +use crate::stdarch_test::assert_instr; + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.x86.pclmulqdq.256"] + fn pclmulqdq_256(a: __m256i, round_key: __m256i, imm8: u8) -> __m256i; + #[link_name = "llvm.x86.pclmulqdq.512"] + fn pclmulqdq_512(a: __m512i, round_key: __m512i, imm8: u8) -> __m512i; +} + +// for some odd reason on x86_64 we generate the correct long name instructions +// but on i686 we generate the short name + imm8 +// so we need to special-case on that... + +/// Performs a carry-less multiplication of two 64-bit polynomials over the +/// finite field GF(2^k) - in each of the 4 128-bit lanes. +/// +/// The immediate byte is used for determining which halves of each lane `a` and `b` +/// should be used. Immediate bits other than 0 and 4 are ignored. +/// All lanes share immediate byte. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_clmulepi64_epi128) +#[inline] +#[target_feature(enable = "avx512vpclmulqdq,avx512f")] +// technically according to Intel's documentation we don't need avx512f here, however LLVM gets confused otherwise +#[cfg_attr(test, assert_instr(vpclmul, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_clmulepi64_epi128(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + pclmulqdq_512(a, b, $imm8) + }; + } + constify_imm8!(imm8, call) +} + +/// Performs a carry-less multiplication of two 64-bit polynomials over the +/// finite field GF(2^k) - in each of the 2 128-bit lanes. +/// +/// The immediate byte is used for determining which halves of each lane `a` and `b` +/// should be used. Immediate bits other than 0 and 4 are ignored. +/// All lanes share immediate byte. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_clmulepi64_epi128) +#[inline] +#[target_feature(enable = "avx512vpclmulqdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpclmul, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm256_clmulepi64_epi128(a: __m256i, b: __m256i, imm8: i32) -> __m256i { + macro_rules! call { + ($imm8:expr) => { + pclmulqdq_256(a, b, $imm8) + }; + } + constify_imm8!(imm8, call) +} + +#[cfg(test)] +mod tests { + // The constants in the tests below are just bit patterns. They should not + // be interpreted as integers; signedness does not make sense for them, but + // __mXXXi happens to be defined in terms of signed integers. + #![allow(overflowing_literals)] + + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + + macro_rules! verify_kat_pclmul { + ($broadcast:ident, $clmul:ident, $assert:ident) => { + // Constants taken from https://software.intel.com/sites/default/files/managed/72/cc/clmul-wp-rev-2.02-2014-04-20.pdf + let a = _mm_set_epi64x(0x7b5b546573745665, 0x63746f725d53475d); + let a = $broadcast(a); + let b = _mm_set_epi64x(0x4869285368617929, 0x5b477565726f6e5d); + let b = $broadcast(b); + let r00 = _mm_set_epi64x(0x1d4d84c85c3440c0, 0x929633d5d36f0451); + let r00 = $broadcast(r00); + let r01 = _mm_set_epi64x(0x1bd17c8d556ab5a1, 0x7fa540ac2a281315); + let r01 = $broadcast(r01); + let r10 = _mm_set_epi64x(0x1a2bf6db3a30862f, 0xbabf262df4b7d5c9); + let r10 = $broadcast(r10); + let r11 = _mm_set_epi64x(0x1d1e1f2c592e7c45, 0xd66ee03e410fd4ed); + let r11 = $broadcast(r11); + + $assert($clmul(a, b, 0x00), r00); + $assert($clmul(a, b, 0x10), r01); + $assert($clmul(a, b, 0x01), r10); + $assert($clmul(a, b, 0x11), r11); + + let a0 = _mm_set_epi64x(0x0000000000000000, 0x8000000000000000); + let a0 = $broadcast(a0); + let r = _mm_set_epi64x(0x4000000000000000, 0x0000000000000000); + let r = $broadcast(r); + $assert($clmul(a0, a0, 0x00), r); + } + } + + macro_rules! unroll { + ($target:ident[4] = $op:ident($source:ident,4);) => { + $target[3] = $op($source, 3); + $target[2] = $op($source, 2); + unroll! {$target[2] = $op($source,2);} + }; + ($target:ident[2] = $op:ident($source:ident,2);) => { + $target[1] = $op($source, 1); + $target[0] = $op($source, 0); + }; + (assert_eq_m128i($op:ident($vec_res:ident,4),$lin_res:ident[4]);) => { + assert_eq_m128i($op($vec_res, 3), $lin_res[3]); + assert_eq_m128i($op($vec_res, 2), $lin_res[2]); + unroll! {assert_eq_m128i($op($vec_res,2),$lin_res[2]);} + }; + (assert_eq_m128i($op:ident($vec_res:ident,2),$lin_res:ident[2]);) => { + assert_eq_m128i($op($vec_res, 1), $lin_res[1]); + assert_eq_m128i($op($vec_res, 0), $lin_res[0]); + }; + } + + // this function tests one of the possible 4 instances + // with different inputs across lanes + #[target_feature(enable = "avx512vpclmulqdq,avx512f")] + unsafe fn verify_512_helper( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m512i, __m512i) -> __m512i, + ) { + let a = _mm512_set_epi64( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + 0xAB05CFFA2621154C, + 0x1171B47A186174C9, + 0x8C6B6C0E7595CEC9, + 0xBE3E7D4934E961BD, + ); + let b = _mm512_set_epi64( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + 0xB1927AB22F31D0EC, + 0xA9A5DA619BE4D7AF, + 0xCA2590F56884FDC6, + 0x19BE9F660038BDB5, + ); + + let mut a_decomp = [_mm_setzero_si128(); 4]; + unroll! {a_decomp[4] = _mm512_extracti32x4_epi32(a,4);} + let mut b_decomp = [_mm_setzero_si128(); 4]; + unroll! {b_decomp[4] = _mm512_extracti32x4_epi32(b,4);} + + let r = vectorized(a, b); + let mut e_decomp = [_mm_setzero_si128(); 4]; + for i in 0..4 { + e_decomp[i] = linear(a_decomp[i], b_decomp[i]); + } + unroll! {assert_eq_m128i(_mm512_extracti32x4_epi32(r,4),e_decomp[4]);} + } + + // this function tests one of the possible 4 instances + // with different inputs across lanes for the VL version + #[target_feature(enable = "avx512vpclmulqdq,avx512vl")] + unsafe fn verify_256_helper( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m256i, __m256i) -> __m256i, + ) { + let a = _mm512_set_epi64( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + 0xAB05CFFA2621154C, + 0x1171B47A186174C9, + 0x8C6B6C0E7595CEC9, + 0xBE3E7D4934E961BD, + ); + let b = _mm512_set_epi64( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + 0xB1927AB22F31D0EC, + 0xA9A5DA619BE4D7AF, + 0xCA2590F56884FDC6, + 0x19BE9F660038BDB5, + ); + + let mut a_decomp = [_mm_setzero_si128(); 2]; + unroll! {a_decomp[2] = _mm512_extracti32x4_epi32(a,2);} + let mut b_decomp = [_mm_setzero_si128(); 2]; + unroll! {b_decomp[2] = _mm512_extracti32x4_epi32(b,2);} + + let r = vectorized( + _mm512_extracti64x4_epi64(a, 0), + _mm512_extracti64x4_epi64(b, 0), + ); + let mut e_decomp = [_mm_setzero_si128(); 2]; + for i in 0..2 { + e_decomp[i] = linear(a_decomp[i], b_decomp[i]); + } + unroll! {assert_eq_m128i(_mm256_extracti128_si256(r,2),e_decomp[2]);} + } + + #[simd_test(enable = "avx512vpclmulqdq,avx512f")] + unsafe fn test_mm512_clmulepi64_epi128() { + verify_kat_pclmul!( + _mm512_broadcast_i32x4, + _mm512_clmulepi64_epi128, + assert_eq_m512i + ); + + verify_512_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x00), + |a, b| _mm512_clmulepi64_epi128(a, b, 0x00), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x01), + |a, b| _mm512_clmulepi64_epi128(a, b, 0x01), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x10), + |a, b| _mm512_clmulepi64_epi128(a, b, 0x10), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x11), + |a, b| _mm512_clmulepi64_epi128(a, b, 0x11), + ); + } + + #[simd_test(enable = "avx512vpclmulqdq,avx512vl")] + unsafe fn test_mm256_clmulepi64_epi128() { + verify_kat_pclmul!( + _mm256_broadcastsi128_si256, + _mm256_clmulepi64_epi128, + assert_eq_m256i + ); + + verify_256_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x00), + |a, b| _mm256_clmulepi64_epi128(a, b, 0x00), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x01), + |a, b| _mm256_clmulepi64_epi128(a, b, 0x01), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x10), + |a, b| _mm256_clmulepi64_epi128(a, b, 0x10), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128(a, b, 0x11), + |a, b| _mm256_clmulepi64_epi128(a, b, 0x11), + ); + } +} diff --git a/library/stdarch/crates/core_arch/src/x86/avx512vpopcntdq.rs b/library/stdarch/crates/core_arch/src/x86/avx512vpopcntdq.rs new file mode 100644 index 0000000000..3b97c4c19d --- /dev/null +++ b/library/stdarch/crates/core_arch/src/x86/avx512vpopcntdq.rs @@ -0,0 +1,541 @@ +//! Vectorized Population Count Instructions for Double- and Quadwords (VPOPCNTDQ) +//! +//! The intrinsics here correspond to those in the `immintrin.h` C header. +//! +//! The reference is [Intel 64 and IA-32 Architectures Software Developer's +//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref]. +//! +//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + +use crate::core_arch::simd::i32x16; +use crate::core_arch::simd::i32x4; +use crate::core_arch::simd::i32x8; +use crate::core_arch::simd::i64x2; +use crate::core_arch::simd::i64x4; +use crate::core_arch::simd::i64x8; +use crate::core_arch::simd_llvm::simd_select_bitmask; +use crate::core_arch::x86::__m128i; +use crate::core_arch::x86::__m256i; +use crate::core_arch::x86::__m512i; +use crate::core_arch::x86::__mmask16; +use crate::core_arch::x86::__mmask8; +use crate::core_arch::x86::_mm256_setzero_si256; +use crate::core_arch::x86::_mm512_setzero_si512; +use crate::core_arch::x86::_mm_setzero_si128; +use crate::core_arch::x86::m128iExt; +use crate::core_arch::x86::m256iExt; +use crate::core_arch::x86::m512iExt; +use crate::mem::transmute; + +#[cfg(test)] +use stdarch_test::assert_instr; + +#[allow(improper_ctypes)] +extern "C" { + #[link_name = "llvm.ctpop.v16i32"] + fn popcnt_v16i32(x: i32x16) -> i32x16; + #[link_name = "llvm.ctpop.v8i32"] + fn popcnt_v8i32(x: i32x8) -> i32x8; + #[link_name = "llvm.ctpop.v4i32"] + fn popcnt_v4i32(x: i32x4) -> i32x4; + + #[link_name = "llvm.ctpop.v8i64"] + fn popcnt_v8i64(x: i64x8) -> i64x8; + #[link_name = "llvm.ctpop.v4i64"] + fn popcnt_v4i64(x: i64x4) -> i64x4; + #[link_name = "llvm.ctpop.v2i64"] + fn popcnt_v2i64(x: i64x2) -> i64x2; +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm512_popcnt_epi32(a: __m512i) -> __m512i { + transmute(popcnt_v16i32(a.as_i32x16())) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm512_maskz_popcnt_epi32(k: __mmask16, a: __m512i) -> __m512i { + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, popcnt_v16i32(a.as_i32x16()), zero)) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm512_mask_popcnt_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i { + transmute(simd_select_bitmask( + k, + popcnt_v16i32(a.as_i32x16()), + src.as_i32x16(), + )) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm256_popcnt_epi32(a: __m256i) -> __m256i { + transmute(popcnt_v8i32(a.as_i32x8())) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm256_maskz_popcnt_epi32(k: __mmask8, a: __m256i) -> __m256i { + let zero = _mm256_setzero_si256().as_i32x8(); + transmute(simd_select_bitmask(k, popcnt_v8i32(a.as_i32x8()), zero)) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm256_mask_popcnt_epi32(src: __m256i, k: __mmask8, a: __m256i) -> __m256i { + transmute(simd_select_bitmask( + k, + popcnt_v8i32(a.as_i32x8()), + src.as_i32x8(), + )) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm_popcnt_epi32(a: __m128i) -> __m128i { + transmute(popcnt_v4i32(a.as_i32x4())) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm_maskz_popcnt_epi32(k: __mmask8, a: __m128i) -> __m128i { + let zero = _mm_setzero_si128().as_i32x4(); + transmute(simd_select_bitmask(k, popcnt_v4i32(a.as_i32x4()), zero)) +} + +/// For each packed 32-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_popcnt_epi32) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntd))] +pub unsafe fn _mm_mask_popcnt_epi32(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + transmute(simd_select_bitmask( + k, + popcnt_v4i32(a.as_i32x4()), + src.as_i32x4(), + )) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm512_popcnt_epi64(a: __m512i) -> __m512i { + transmute(popcnt_v8i64(a.as_i64x8())) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm512_maskz_popcnt_epi64(k: __mmask8, a: __m512i) -> __m512i { + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, popcnt_v8i64(a.as_i64x8()), zero)) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm512_mask_popcnt_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + transmute(simd_select_bitmask( + k, + popcnt_v8i64(a.as_i64x8()), + src.as_i64x8(), + )) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm256_popcnt_epi64(a: __m256i) -> __m256i { + transmute(popcnt_v4i64(a.as_i64x4())) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_maskz_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm256_maskz_popcnt_epi64(k: __mmask8, a: __m256i) -> __m256i { + let zero = _mm256_setzero_si256().as_i64x4(); + transmute(simd_select_bitmask(k, popcnt_v4i64(a.as_i64x4()), zero)) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_mask_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm256_mask_popcnt_epi64(src: __m256i, k: __mmask8, a: __m256i) -> __m256i { + transmute(simd_select_bitmask( + k, + popcnt_v4i64(a.as_i64x4()), + src.as_i64x4(), + )) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm_popcnt_epi64(a: __m128i) -> __m128i { + transmute(popcnt_v2i64(a.as_i64x2())) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are zeroed in the result if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm_maskz_popcnt_epi64(k: __mmask8, a: __m128i) -> __m128i { + let zero = _mm_setzero_si128().as_i64x2(); + transmute(simd_select_bitmask(k, popcnt_v2i64(a.as_i64x2()), zero)) +} + +/// For each packed 64-bit integer maps the value to the number of logical 1 bits. +/// +/// Uses the writemask in k - elements are copied from src if the corresponding mask bit is not set. +/// Otherwise the computation result is written into the result. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_popcnt_epi64) +#[inline] +#[target_feature(enable = "avx512vpopcntdq,avx512vl")] +#[cfg_attr(test, assert_instr(vpopcntq))] +pub unsafe fn _mm_mask_popcnt_epi64(src: __m128i, k: __mmask8, a: __m128i) -> __m128i { + transmute(simd_select_bitmask( + k, + popcnt_v2i64(a.as_i64x2()), + src.as_i64x2(), + )) +} + +#[cfg(test)] +mod tests { + use stdarch_test::simd_test; + + use crate::core_arch::x86::*; + + #[simd_test(enable = "avx512vpopcntdq,avx512f")] + unsafe fn test_mm512_popcnt_epi32() { + let test_data = _mm512_set_epi32( + 0, + 1, + -1, + 2, + 7, + 0xFF_FE, + 0x7F_FF_FF_FF, + -100, + 0x40_00_00_00, + 103, + 371, + 552, + 432_948, + 818_826_998, + 255, + 256, + ); + let actual_result = _mm512_popcnt_epi32(test_data); + let reference_result = + _mm512_set_epi32(0, 1, 32, 1, 3, 15, 31, 28, 1, 5, 6, 3, 10, 17, 8, 1); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f")] + unsafe fn test_mm512_mask_popcnt_epi32() { + let test_data = _mm512_set_epi32( + 0, + 1, + -1, + 2, + 7, + 0xFF_FE, + 0x7F_FF_FF_FF, + -100, + 0x40_00_00_00, + 103, + 371, + 552, + 432_948, + 818_826_998, + 255, + 256, + ); + let mask = 0xFF_00; + let actual_result = _mm512_mask_popcnt_epi32(test_data, mask, test_data); + let reference_result = _mm512_set_epi32( + 0, + 1, + 32, + 1, + 3, + 15, + 31, + 28, + 0x40_00_00_00, + 103, + 371, + 552, + 432_948, + 818_826_998, + 255, + 256, + ); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f")] + unsafe fn test_mm512_maskz_popcnt_epi32() { + let test_data = _mm512_set_epi32( + 0, + 1, + -1, + 2, + 7, + 0xFF_FE, + 0x7F_FF_FF_FF, + -100, + 0x40_00_00_00, + 103, + 371, + 552, + 432_948, + 818_826_998, + 255, + 256, + ); + let mask = 0xFF_00; + let actual_result = _mm512_maskz_popcnt_epi32(mask, test_data); + let reference_result = _mm512_set_epi32(0, 1, 32, 1, 3, 15, 31, 28, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f,avx512vl")] + unsafe fn test_mm256_popcnt_epi32() { + let test_data = _mm256_set_epi32(0, 1, -1, 2, 7, 0xFF_FE, 0x7F_FF_FF_FF, -100); + let actual_result = _mm256_popcnt_epi32(test_data); + let reference_result = _mm256_set_epi32(0, 1, 32, 1, 3, 15, 31, 28); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f,avx512vl")] + unsafe fn test_mm256_mask_popcnt_epi32() { + let test_data = _mm256_set_epi32(0, 1, -1, 2, 7, 0xFF_FE, 0x7F_FF_FF_FF, -100); + let mask = 0xF0; + let actual_result = _mm256_mask_popcnt_epi32(test_data, mask, test_data); + let reference_result = _mm256_set_epi32(0, 1, 32, 1, 7, 0xFF_FE, 0x7F_FF_FF_FF, -100); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f,avx512vl")] + unsafe fn test_mm256_maskz_popcnt_epi32() { + let test_data = _mm256_set_epi32(0, 1, -1, 2, 7, 0xFF_FE, 0x7F_FF_FF_FF, -100); + let mask = 0xF0; + let actual_result = _mm256_maskz_popcnt_epi32(mask, test_data); + let reference_result = _mm256_set_epi32(0, 1, 32, 1, 0, 0, 0, 0); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f,avx512vl")] + unsafe fn test_mm_popcnt_epi32() { + let test_data = _mm_set_epi32(0, 1, -1, -100); + let actual_result = _mm_popcnt_epi32(test_data); + let reference_result = _mm_set_epi32(0, 1, 32, 28); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f,avx512vl")] + unsafe fn test_mm_mask_popcnt_epi32() { + let test_data = _mm_set_epi32(0, 1, -1, -100); + let mask = 0xE; + let actual_result = _mm_mask_popcnt_epi32(test_data, mask, test_data); + let reference_result = _mm_set_epi32(0, 1, 32, -100); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f,avx512vl")] + unsafe fn test_mm_maskz_popcnt_epi32() { + let test_data = _mm_set_epi32(0, 1, -1, -100); + let mask = 0xE; + let actual_result = _mm_maskz_popcnt_epi32(mask, test_data); + let reference_result = _mm_set_epi32(0, 1, 32, 0); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f")] + unsafe fn test_mm512_popcnt_epi64() { + let test_data = _mm512_set_epi64(0, 1, -1, 2, 7, 0xFF_FE, 0x7F_FF_FF_FF_FF_FF_FF_FF, -100); + let actual_result = _mm512_popcnt_epi64(test_data); + let reference_result = _mm512_set_epi64(0, 1, 64, 1, 3, 15, 63, 60); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f")] + unsafe fn test_mm512_mask_popcnt_epi64() { + let test_data = _mm512_set_epi64(0, 1, -1, 2, 7, 0xFF_FE, 0x7F_FF_FF_FF_FF_FF_FF_FF, -100); + let mask = 0xF0; + let actual_result = _mm512_mask_popcnt_epi64(test_data, mask, test_data); + let reference_result = + _mm512_set_epi64(0, 1, 64, 1, 7, 0xFF_FE, 0x7F_FF_FF_FF_FF_FF_FF_FF, -100); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512f")] + unsafe fn test_mm512_maskz_popcnt_epi64() { + let test_data = _mm512_set_epi64(0, 1, -1, 2, 7, 0xFF_FE, 0x7F_FF_FF_FF_FF_FF_FF_FF, -100); + let mask = 0xF0; + let actual_result = _mm512_maskz_popcnt_epi64(mask, test_data); + let reference_result = _mm512_set_epi64(0, 1, 64, 1, 0, 0, 0, 0); + assert_eq_m512i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512vl")] + unsafe fn test_mm256_popcnt_epi64() { + let test_data = _mm256_set_epi64x(0, 1, -1, -100); + let actual_result = _mm256_popcnt_epi64(test_data); + let reference_result = _mm256_set_epi64x(0, 1, 64, 60); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512vl")] + unsafe fn test_mm256_mask_popcnt_epi64() { + let test_data = _mm256_set_epi64x(0, 1, -1, -100); + let mask = 0xE; + let actual_result = _mm256_mask_popcnt_epi64(test_data, mask, test_data); + let reference_result = _mm256_set_epi64x(0, 1, 64, -100); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512vl")] + unsafe fn test_mm256_maskz_popcnt_epi64() { + let test_data = _mm256_set_epi64x(0, 1, -1, -100); + let mask = 0xE; + let actual_result = _mm256_maskz_popcnt_epi64(mask, test_data); + let reference_result = _mm256_set_epi64x(0, 1, 64, 0); + assert_eq_m256i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512vl")] + unsafe fn test_mm_popcnt_epi64() { + let test_data = _mm_set_epi64x(0, 1); + let actual_result = _mm_popcnt_epi64(test_data); + let reference_result = _mm_set_epi64x(0, 1); + assert_eq_m128i(actual_result, reference_result); + let test_data = _mm_set_epi64x(-1, -100); + let actual_result = _mm_popcnt_epi64(test_data); + let reference_result = _mm_set_epi64x(64, 60); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512vl")] + unsafe fn test_mm_mask_popcnt_epi64() { + let test_data = _mm_set_epi64x(0, -100); + let mask = 0x2; + let actual_result = _mm_mask_popcnt_epi64(test_data, mask, test_data); + let reference_result = _mm_set_epi64x(0, -100); + assert_eq_m128i(actual_result, reference_result); + let test_data = _mm_set_epi64x(-1, 1); + let mask = 0x2; + let actual_result = _mm_mask_popcnt_epi64(test_data, mask, test_data); + let reference_result = _mm_set_epi64x(64, 1); + assert_eq_m128i(actual_result, reference_result); + } + + #[simd_test(enable = "avx512vpopcntdq,avx512vl")] + unsafe fn test_mm_maskz_popcnt_epi64() { + let test_data = _mm_set_epi64x(0, 1); + let mask = 0x2; + let actual_result = _mm_maskz_popcnt_epi64(mask, test_data); + let reference_result = _mm_set_epi64x(0, 0); + assert_eq_m128i(actual_result, reference_result); + let test_data = _mm_set_epi64x(-1, -100); + let mask = 0x2; + let actual_result = _mm_maskz_popcnt_epi64(mask, test_data); + let reference_result = _mm_set_epi64x(64, 0); + assert_eq_m128i(actual_result, reference_result); + } +} diff --git a/library/stdarch/crates/core_arch/src/x86/fma.rs b/library/stdarch/crates/core_arch/src/x86/fma.rs index f3dda6d527..476f4538c4 100644 --- a/library/stdarch/crates/core_arch/src/x86/fma.rs +++ b/library/stdarch/crates/core_arch/src/x86/fma.rs @@ -500,7 +500,7 @@ extern "C" { #[cfg(test)] mod tests { - use std; + use stdarch_test::simd_test; use crate::core_arch::x86::*; diff --git a/library/stdarch/crates/core_arch/src/x86/fxsr.rs b/library/stdarch/crates/core_arch/src/x86/fxsr.rs index 83d53f4773..b1bac1a0ac 100644 --- a/library/stdarch/crates/core_arch/src/x86/fxsr.rs +++ b/library/stdarch/crates/core_arch/src/x86/fxsr.rs @@ -6,9 +6,9 @@ use stdarch_test::assert_instr; #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.fxsave"] - fn fxsave(p: *mut u8) -> (); + fn fxsave(p: *mut u8); #[link_name = "llvm.x86.fxrstor"] - fn fxrstor(p: *const u8) -> (); + fn fxrstor(p: *const u8); } /// Saves the `x87` FPU, `MMX` technology, `XMM`, and `MXCSR` registers to the diff --git a/library/stdarch/crates/core_arch/src/x86/macros.rs b/library/stdarch/crates/core_arch/src/x86/macros.rs index 891286df4e..46d248bdc4 100644 --- a/library/stdarch/crates/core_arch/src/x86/macros.rs +++ b/library/stdarch/crates/core_arch/src/x86/macros.rs @@ -333,132 +333,196 @@ macro_rules! constify_imm4_mantissas_sae { match ($imm4_1, $imm2, $imm4_2) { (0, 0, 4) => $expand!(0, 0, 4), (0, 0, 8) => $expand!(0, 0, 8), + (0, 0, 12) => $expand!(0, 0, 12), (0, 1, 4) => $expand!(0, 1, 4), (0, 1, 8) => $expand!(0, 1, 8), + (0, 1, 12) => $expand!(0, 1, 12), (0, 2, 4) => $expand!(0, 2, 4), (0, 2, 8) => $expand!(0, 2, 8), + (0, 2, 12) => $expand!(0, 2, 12), (0, 3, 4) => $expand!(0, 3, 4), (0, 3, 8) => $expand!(0, 3, 8), + (0, 3, 12) => $expand!(0, 3, 12), (1, 0, 4) => $expand!(1, 0, 4), (1, 0, 8) => $expand!(1, 0, 8), + (1, 0, 12) => $expand!(1, 0, 12), (1, 1, 4) => $expand!(1, 1, 4), (1, 1, 8) => $expand!(1, 1, 8), + (1, 1, 12) => $expand!(1, 1, 12), (1, 2, 4) => $expand!(1, 2, 4), (1, 2, 8) => $expand!(1, 2, 8), + (1, 2, 12) => $expand!(1, 2, 12), (1, 3, 4) => $expand!(1, 3, 4), (1, 3, 8) => $expand!(1, 3, 8), + (1, 3, 12) => $expand!(1, 3, 12), (2, 0, 4) => $expand!(2, 0, 4), (2, 0, 8) => $expand!(2, 0, 8), + (2, 0, 12) => $expand!(2, 0, 12), (2, 1, 4) => $expand!(2, 1, 4), (2, 1, 8) => $expand!(2, 1, 8), + (2, 1, 12) => $expand!(2, 1, 12), (2, 2, 4) => $expand!(2, 2, 4), (2, 2, 8) => $expand!(2, 2, 8), + (2, 2, 12) => $expand!(2, 2, 12), (2, 3, 4) => $expand!(2, 3, 4), (2, 3, 8) => $expand!(2, 3, 8), + (2, 3, 12) => $expand!(2, 3, 12), (3, 0, 4) => $expand!(3, 0, 4), (3, 0, 8) => $expand!(3, 0, 8), + (3, 0, 12) => $expand!(3, 0, 12), (3, 1, 4) => $expand!(3, 1, 4), (3, 1, 8) => $expand!(3, 1, 8), + (3, 1, 12) => $expand!(3, 1, 12), (3, 2, 4) => $expand!(3, 2, 4), (3, 2, 8) => $expand!(3, 2, 8), + (3, 2, 12) => $expand!(3, 2, 12), (3, 3, 4) => $expand!(3, 3, 4), (3, 3, 8) => $expand!(3, 3, 8), + (3, 3, 12) => $expand!(3, 3, 12), (4, 0, 4) => $expand!(4, 0, 4), (4, 0, 8) => $expand!(4, 0, 8), + (4, 0, 12) => $expand!(4, 0, 12), (4, 1, 4) => $expand!(4, 1, 4), (4, 1, 8) => $expand!(4, 1, 8), + (4, 1, 12) => $expand!(4, 1, 12), (4, 2, 4) => $expand!(4, 2, 4), (4, 2, 8) => $expand!(4, 2, 8), + (4, 2, 12) => $expand!(4, 2, 12), (4, 3, 4) => $expand!(4, 3, 4), (4, 3, 8) => $expand!(4, 3, 8), + (4, 3, 12) => $expand!(4, 3, 12), (5, 0, 4) => $expand!(5, 0, 4), (5, 0, 8) => $expand!(5, 0, 8), + (5, 0, 12) => $expand!(5, 0, 12), (5, 1, 4) => $expand!(5, 1, 4), (5, 1, 8) => $expand!(5, 1, 8), + (5, 1, 12) => $expand!(5, 1, 12), (5, 2, 4) => $expand!(5, 2, 4), (5, 2, 8) => $expand!(5, 2, 8), + (5, 2, 12) => $expand!(5, 2, 12), (5, 3, 4) => $expand!(5, 3, 4), (5, 3, 8) => $expand!(5, 3, 8), + (5, 3, 12) => $expand!(5, 3, 12), (6, 0, 4) => $expand!(6, 0, 4), (6, 0, 8) => $expand!(6, 0, 8), + (6, 0, 12) => $expand!(6, 0, 12), (6, 1, 4) => $expand!(6, 1, 4), (6, 1, 8) => $expand!(6, 1, 8), + (6, 1, 12) => $expand!(6, 1, 12), (6, 2, 4) => $expand!(6, 2, 4), (6, 2, 8) => $expand!(6, 2, 8), + (6, 2, 12) => $expand!(6, 2, 12), (6, 3, 4) => $expand!(6, 3, 4), (6, 3, 8) => $expand!(6, 3, 8), + (6, 3, 12) => $expand!(6, 3, 12), (7, 0, 4) => $expand!(7, 0, 4), (7, 0, 8) => $expand!(7, 0, 8), + (7, 0, 12) => $expand!(7, 0, 12), (7, 1, 4) => $expand!(7, 1, 4), (7, 1, 8) => $expand!(7, 1, 8), + (7, 1, 12) => $expand!(7, 1, 12), (7, 2, 4) => $expand!(7, 2, 4), (7, 2, 8) => $expand!(7, 2, 8), + (7, 2, 12) => $expand!(7, 2, 12), (7, 3, 4) => $expand!(7, 3, 4), (7, 3, 8) => $expand!(7, 3, 8), + (7, 3, 12) => $expand!(7, 3, 12), (8, 0, 4) => $expand!(8, 0, 4), (8, 0, 8) => $expand!(8, 0, 8), + (8, 0, 12) => $expand!(8, 0, 12), (8, 1, 4) => $expand!(8, 1, 4), (8, 1, 8) => $expand!(8, 1, 8), + (8, 1, 12) => $expand!(8, 1, 12), (8, 2, 4) => $expand!(8, 2, 4), (8, 2, 8) => $expand!(8, 2, 8), + (8, 2, 12) => $expand!(8, 2, 12), (8, 3, 4) => $expand!(8, 3, 4), (8, 3, 8) => $expand!(8, 3, 8), + (8, 3, 12) => $expand!(8, 3, 12), (9, 0, 4) => $expand!(9, 0, 4), (9, 0, 8) => $expand!(9, 0, 8), + (9, 0, 12) => $expand!(9, 0, 12), (9, 1, 4) => $expand!(9, 1, 4), (9, 1, 8) => $expand!(9, 1, 8), + (9, 1, 12) => $expand!(9, 1, 12), (9, 2, 4) => $expand!(9, 2, 4), (9, 2, 8) => $expand!(9, 2, 8), + (9, 2, 12) => $expand!(9, 2, 12), (9, 3, 4) => $expand!(9, 3, 4), (9, 3, 8) => $expand!(9, 3, 8), + (9, 3, 12) => $expand!(9, 3, 12), (10, 0, 4) => $expand!(10, 0, 4), (10, 0, 8) => $expand!(10, 0, 8), + (10, 0, 12) => $expand!(10, 0, 12), (10, 1, 4) => $expand!(10, 1, 4), (10, 1, 8) => $expand!(10, 1, 8), + (10, 1, 12) => $expand!(10, 1, 12), (10, 2, 4) => $expand!(10, 2, 4), (10, 2, 8) => $expand!(10, 2, 8), + (10, 2, 12) => $expand!(10, 2, 12), (10, 3, 4) => $expand!(10, 3, 4), (10, 3, 8) => $expand!(10, 3, 8), + (10, 3, 12) => $expand!(10, 3, 12), (11, 0, 4) => $expand!(11, 0, 4), (11, 0, 8) => $expand!(11, 0, 8), + (11, 0, 12) => $expand!(11, 0, 12), (11, 1, 4) => $expand!(11, 1, 4), (11, 1, 8) => $expand!(11, 1, 8), + (11, 1, 12) => $expand!(11, 1, 12), (11, 2, 4) => $expand!(11, 2, 4), (11, 2, 8) => $expand!(11, 2, 8), + (11, 2, 12) => $expand!(11, 2, 12), (11, 3, 4) => $expand!(11, 3, 4), (11, 3, 8) => $expand!(11, 3, 8), + (11, 3, 12) => $expand!(11, 3, 12), (12, 0, 4) => $expand!(12, 0, 4), (12, 0, 8) => $expand!(12, 0, 8), + (12, 0, 12) => $expand!(12, 0, 12), (12, 1, 4) => $expand!(12, 1, 4), (12, 1, 8) => $expand!(12, 1, 8), + (12, 1, 12) => $expand!(12, 1, 12), (12, 2, 4) => $expand!(12, 2, 4), (12, 2, 8) => $expand!(12, 2, 8), + (12, 2, 12) => $expand!(12, 2, 12), (12, 3, 4) => $expand!(12, 3, 4), (12, 3, 8) => $expand!(12, 3, 8), + (12, 3, 12) => $expand!(12, 3, 12), (13, 0, 4) => $expand!(13, 0, 4), (13, 0, 8) => $expand!(13, 0, 8), + (13, 0, 12) => $expand!(13, 0, 12), (13, 1, 4) => $expand!(13, 1, 4), (13, 1, 8) => $expand!(13, 1, 8), + (13, 1, 12) => $expand!(13, 1, 12), (13, 2, 4) => $expand!(13, 2, 4), (13, 2, 8) => $expand!(13, 2, 8), + (13, 2, 12) => $expand!(13, 2, 12), (13, 3, 4) => $expand!(13, 3, 4), (13, 3, 8) => $expand!(13, 3, 8), + (13, 3, 12) => $expand!(13, 3, 12), (14, 0, 4) => $expand!(14, 0, 4), (14, 0, 8) => $expand!(14, 0, 8), + (14, 0, 12) => $expand!(14, 0, 12), (14, 1, 4) => $expand!(14, 1, 4), (14, 1, 8) => $expand!(14, 1, 8), + (14, 1, 12) => $expand!(14, 1, 12), (14, 2, 4) => $expand!(14, 2, 4), (14, 2, 8) => $expand!(14, 2, 8), + (14, 2, 12) => $expand!(14, 2, 12), (14, 3, 4) => $expand!(14, 3, 4), (14, 3, 8) => $expand!(14, 3, 8), + (14, 3, 12) => $expand!(14, 3, 12), (15, 0, 4) => $expand!(15, 0, 4), (15, 0, 8) => $expand!(15, 0, 8), + (15, 0, 12) => $expand!(15, 0, 12), (15, 1, 4) => $expand!(15, 1, 4), (15, 1, 8) => $expand!(15, 1, 8), + (15, 1, 12) => $expand!(15, 1, 12), (15, 2, 4) => $expand!(15, 2, 4), (15, 2, 8) => $expand!(15, 2, 8), + (15, 2, 12) => $expand!(15, 2, 12), (15, 3, 4) => $expand!(15, 3, 4), (15, 3, 8) => $expand!(15, 3, 8), + (15, 3, 12) => $expand!(15, 3, 12), (_, _, _) => panic!("Invalid sae value"), } }; @@ -733,6 +797,786 @@ macro_rules! constify_imm8_sae { }; } +// Two sae parameters. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm8_roundscale { + ($imm8:expr, $imm4:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm8 & 0b11111111, $imm4) { + (0, 4) => $expand!(0, 4), + (0, 8) => $expand!(0, 8), + (0, 12) => $expand!(0, 12), + (1, 4) => $expand!(1, 4), + (1, 8) => $expand!(1, 8), + (1, 12) => $expand!(1, 12), + (2, 4) => $expand!(2, 4), + (2, 8) => $expand!(2, 8), + (2, 12) => $expand!(2, 12), + (3, 4) => $expand!(3, 4), + (3, 8) => $expand!(3, 8), + (3, 12) => $expand!(3, 12), + (4, 4) => $expand!(4, 4), + (4, 8) => $expand!(4, 8), + (4, 12) => $expand!(4, 12), + (5, 4) => $expand!(5, 4), + (5, 8) => $expand!(5, 8), + (5, 12) => $expand!(5, 12), + (6, 4) => $expand!(6, 4), + (6, 8) => $expand!(6, 8), + (6, 12) => $expand!(6, 12), + (7, 4) => $expand!(7, 4), + (7, 8) => $expand!(7, 8), + (7, 12) => $expand!(7, 12), + (8, 4) => $expand!(8, 4), + (8, 8) => $expand!(8, 8), + (8, 12) => $expand!(8, 12), + (9, 4) => $expand!(9, 4), + (9, 8) => $expand!(9, 8), + (9, 12) => $expand!(9, 12), + (10, 4) => $expand!(10, 4), + (10, 8) => $expand!(10, 8), + (10, 12) => $expand!(10, 12), + (11, 4) => $expand!(11, 4), + (11, 8) => $expand!(11, 8), + (11, 12) => $expand!(11, 12), + (12, 4) => $expand!(12, 4), + (12, 8) => $expand!(12, 8), + (12, 12) => $expand!(12, 12), + (13, 4) => $expand!(13, 4), + (13, 8) => $expand!(13, 8), + (13, 12) => $expand!(13, 12), + (14, 4) => $expand!(14, 4), + (14, 8) => $expand!(14, 8), + (14, 12) => $expand!(14, 12), + (15, 4) => $expand!(15, 4), + (15, 8) => $expand!(15, 8), + (15, 12) => $expand!(15, 12), + (16, 4) => $expand!(16, 4), + (16, 8) => $expand!(16, 8), + (16, 12) => $expand!(16, 12), + (17, 4) => $expand!(17, 4), + (17, 8) => $expand!(17, 8), + (17, 12) => $expand!(17, 12), + (18, 4) => $expand!(18, 4), + (18, 8) => $expand!(18, 8), + (18, 12) => $expand!(18, 12), + (19, 4) => $expand!(19, 4), + (19, 8) => $expand!(19, 8), + (19, 12) => $expand!(19, 12), + (20, 4) => $expand!(20, 4), + (20, 8) => $expand!(20, 8), + (20, 12) => $expand!(20, 12), + (21, 4) => $expand!(21, 4), + (21, 8) => $expand!(21, 8), + (21, 12) => $expand!(21, 12), + (22, 4) => $expand!(22, 4), + (22, 8) => $expand!(22, 8), + (22, 12) => $expand!(22, 12), + (23, 4) => $expand!(23, 4), + (23, 8) => $expand!(23, 8), + (23, 12) => $expand!(23, 12), + (24, 4) => $expand!(24, 4), + (24, 8) => $expand!(24, 8), + (24, 12) => $expand!(24, 12), + (25, 4) => $expand!(25, 4), + (25, 8) => $expand!(25, 8), + (25, 12) => $expand!(25, 12), + (26, 4) => $expand!(26, 4), + (26, 8) => $expand!(26, 8), + (26, 12) => $expand!(26, 12), + (27, 4) => $expand!(27, 4), + (27, 8) => $expand!(27, 8), + (27, 12) => $expand!(27, 12), + (28, 4) => $expand!(28, 4), + (28, 8) => $expand!(28, 8), + (28, 12) => $expand!(28, 12), + (29, 4) => $expand!(29, 4), + (29, 8) => $expand!(29, 8), + (29, 12) => $expand!(29, 12), + (30, 4) => $expand!(30, 4), + (30, 8) => $expand!(30, 8), + (30, 12) => $expand!(30, 12), + (31, 4) => $expand!(31, 4), + (31, 8) => $expand!(31, 8), + (31, 12) => $expand!(31, 12), + (32, 4) => $expand!(32, 4), + (32, 8) => $expand!(32, 8), + (32, 12) => $expand!(32, 12), + (33, 4) => $expand!(33, 4), + (33, 8) => $expand!(33, 8), + (33, 12) => $expand!(33, 12), + (34, 4) => $expand!(34, 4), + (34, 8) => $expand!(34, 8), + (34, 12) => $expand!(34, 12), + (35, 4) => $expand!(35, 4), + (35, 8) => $expand!(35, 8), + (35, 12) => $expand!(35, 12), + (36, 4) => $expand!(36, 4), + (36, 8) => $expand!(36, 8), + (36, 12) => $expand!(36, 12), + (37, 4) => $expand!(37, 4), + (37, 8) => $expand!(37, 8), + (37, 12) => $expand!(37, 12), + (38, 4) => $expand!(38, 4), + (38, 8) => $expand!(38, 8), + (38, 12) => $expand!(38, 12), + (39, 4) => $expand!(39, 4), + (39, 8) => $expand!(39, 8), + (39, 12) => $expand!(39, 12), + (40, 4) => $expand!(40, 4), + (40, 8) => $expand!(40, 8), + (40, 12) => $expand!(40, 12), + (41, 4) => $expand!(41, 4), + (41, 8) => $expand!(41, 8), + (41, 12) => $expand!(41, 12), + (42, 4) => $expand!(42, 4), + (42, 8) => $expand!(42, 8), + (42, 12) => $expand!(42, 12), + (43, 4) => $expand!(43, 4), + (43, 8) => $expand!(43, 8), + (43, 12) => $expand!(43, 12), + (44, 4) => $expand!(44, 4), + (44, 8) => $expand!(44, 8), + (44, 12) => $expand!(44, 12), + (45, 4) => $expand!(45, 4), + (45, 8) => $expand!(45, 8), + (45, 12) => $expand!(45, 12), + (46, 4) => $expand!(46, 4), + (46, 8) => $expand!(46, 8), + (46, 12) => $expand!(46, 12), + (47, 4) => $expand!(47, 4), + (47, 8) => $expand!(47, 8), + (47, 12) => $expand!(47, 12), + (48, 4) => $expand!(48, 4), + (48, 8) => $expand!(48, 8), + (48, 12) => $expand!(48, 12), + (49, 4) => $expand!(49, 4), + (49, 8) => $expand!(49, 8), + (49, 12) => $expand!(49, 12), + (50, 4) => $expand!(50, 4), + (50, 8) => $expand!(50, 8), + (50, 12) => $expand!(50, 12), + (51, 4) => $expand!(51, 4), + (51, 8) => $expand!(51, 8), + (51, 12) => $expand!(51, 12), + (52, 4) => $expand!(52, 4), + (52, 8) => $expand!(52, 8), + (52, 12) => $expand!(52, 12), + (53, 4) => $expand!(53, 4), + (53, 8) => $expand!(53, 8), + (53, 12) => $expand!(53, 12), + (54, 4) => $expand!(54, 4), + (54, 8) => $expand!(54, 8), + (54, 12) => $expand!(54, 12), + (55, 4) => $expand!(55, 4), + (55, 8) => $expand!(55, 8), + (55, 12) => $expand!(55, 12), + (56, 4) => $expand!(56, 4), + (56, 8) => $expand!(56, 8), + (56, 12) => $expand!(56, 12), + (57, 4) => $expand!(57, 4), + (57, 8) => $expand!(57, 8), + (57, 12) => $expand!(57, 12), + (58, 4) => $expand!(58, 4), + (58, 8) => $expand!(58, 8), + (58, 12) => $expand!(58, 12), + (59, 4) => $expand!(59, 4), + (59, 8) => $expand!(59, 8), + (59, 12) => $expand!(59, 12), + (60, 4) => $expand!(60, 4), + (60, 8) => $expand!(60, 8), + (60, 12) => $expand!(60, 12), + (61, 4) => $expand!(61, 4), + (61, 8) => $expand!(61, 8), + (61, 12) => $expand!(61, 12), + (62, 4) => $expand!(62, 4), + (62, 8) => $expand!(62, 8), + (62, 12) => $expand!(62, 12), + (63, 4) => $expand!(63, 4), + (63, 8) => $expand!(63, 8), + (63, 12) => $expand!(63, 12), + (64, 4) => $expand!(64, 4), + (64, 8) => $expand!(64, 8), + (64, 12) => $expand!(64, 12), + (65, 4) => $expand!(65, 4), + (65, 8) => $expand!(65, 8), + (65, 12) => $expand!(65, 12), + (66, 4) => $expand!(66, 4), + (66, 8) => $expand!(66, 8), + (66, 12) => $expand!(66, 12), + (67, 4) => $expand!(67, 4), + (67, 8) => $expand!(67, 8), + (67, 12) => $expand!(67, 12), + (68, 4) => $expand!(68, 4), + (68, 8) => $expand!(68, 8), + (68, 12) => $expand!(68, 12), + (69, 4) => $expand!(69, 4), + (69, 8) => $expand!(69, 8), + (69, 12) => $expand!(69, 12), + (70, 4) => $expand!(70, 4), + (70, 8) => $expand!(70, 8), + (70, 12) => $expand!(70, 12), + (71, 4) => $expand!(71, 4), + (71, 8) => $expand!(71, 8), + (71, 12) => $expand!(71, 12), + (72, 4) => $expand!(72, 4), + (72, 8) => $expand!(72, 8), + (72, 12) => $expand!(72, 12), + (73, 4) => $expand!(73, 4), + (73, 8) => $expand!(73, 8), + (73, 12) => $expand!(73, 12), + (74, 4) => $expand!(74, 4), + (74, 8) => $expand!(74, 8), + (74, 12) => $expand!(74, 12), + (75, 4) => $expand!(75, 4), + (75, 8) => $expand!(75, 8), + (75, 12) => $expand!(75, 12), + (76, 4) => $expand!(76, 4), + (76, 8) => $expand!(76, 8), + (76, 12) => $expand!(76, 12), + (77, 4) => $expand!(77, 4), + (77, 8) => $expand!(77, 8), + (77, 12) => $expand!(77, 12), + (78, 4) => $expand!(78, 4), + (78, 8) => $expand!(78, 8), + (78, 12) => $expand!(78, 12), + (79, 4) => $expand!(79, 4), + (79, 8) => $expand!(79, 8), + (79, 12) => $expand!(79, 12), + (80, 4) => $expand!(80, 4), + (80, 8) => $expand!(80, 8), + (80, 12) => $expand!(80, 12), + (81, 4) => $expand!(81, 4), + (81, 8) => $expand!(81, 8), + (81, 12) => $expand!(81, 12), + (82, 4) => $expand!(82, 4), + (82, 8) => $expand!(82, 8), + (82, 12) => $expand!(82, 12), + (83, 4) => $expand!(83, 4), + (83, 8) => $expand!(83, 8), + (83, 12) => $expand!(83, 12), + (84, 4) => $expand!(84, 4), + (84, 8) => $expand!(84, 8), + (84, 12) => $expand!(84, 12), + (85, 4) => $expand!(85, 4), + (85, 8) => $expand!(85, 8), + (85, 12) => $expand!(85, 12), + (86, 4) => $expand!(86, 4), + (86, 8) => $expand!(86, 8), + (86, 12) => $expand!(86, 12), + (87, 4) => $expand!(87, 4), + (87, 8) => $expand!(87, 8), + (87, 12) => $expand!(87, 12), + (88, 4) => $expand!(88, 4), + (88, 8) => $expand!(88, 8), + (88, 12) => $expand!(88, 12), + (89, 4) => $expand!(89, 4), + (89, 8) => $expand!(89, 8), + (89, 12) => $expand!(89, 12), + (90, 4) => $expand!(90, 4), + (90, 8) => $expand!(90, 8), + (90, 12) => $expand!(90, 12), + (91, 4) => $expand!(91, 4), + (91, 8) => $expand!(91, 8), + (91, 12) => $expand!(91, 12), + (92, 4) => $expand!(92, 4), + (92, 8) => $expand!(92, 8), + (92, 12) => $expand!(92, 12), + (93, 4) => $expand!(93, 4), + (93, 8) => $expand!(93, 8), + (93, 12) => $expand!(93, 12), + (94, 4) => $expand!(94, 4), + (94, 8) => $expand!(94, 8), + (94, 12) => $expand!(94, 12), + (95, 4) => $expand!(95, 4), + (95, 8) => $expand!(95, 8), + (95, 12) => $expand!(95, 12), + (96, 4) => $expand!(96, 4), + (96, 8) => $expand!(96, 8), + (96, 12) => $expand!(96, 12), + (97, 4) => $expand!(97, 4), + (97, 8) => $expand!(97, 8), + (97, 12) => $expand!(97, 12), + (98, 4) => $expand!(98, 4), + (98, 8) => $expand!(98, 8), + (98, 12) => $expand!(98, 12), + (99, 4) => $expand!(99, 4), + (99, 8) => $expand!(99, 8), + (99, 12) => $expand!(99, 12), + (100, 4) => $expand!(100, 4), + (100, 8) => $expand!(100, 8), + (100, 12) => $expand!(100, 12), + (101, 4) => $expand!(101, 4), + (101, 8) => $expand!(101, 8), + (101, 12) => $expand!(101, 12), + (102, 4) => $expand!(102, 4), + (102, 8) => $expand!(102, 8), + (102, 12) => $expand!(102, 12), + (103, 4) => $expand!(103, 4), + (103, 8) => $expand!(103, 8), + (103, 12) => $expand!(103, 12), + (104, 4) => $expand!(104, 4), + (104, 8) => $expand!(104, 8), + (104, 12) => $expand!(104, 12), + (105, 4) => $expand!(105, 4), + (105, 8) => $expand!(105, 8), + (105, 12) => $expand!(105, 12), + (106, 4) => $expand!(106, 4), + (106, 8) => $expand!(106, 8), + (106, 12) => $expand!(106, 12), + (107, 4) => $expand!(107, 4), + (107, 8) => $expand!(107, 8), + (107, 12) => $expand!(107, 12), + (108, 4) => $expand!(108, 4), + (108, 8) => $expand!(108, 8), + (108, 12) => $expand!(108, 12), + (109, 4) => $expand!(109, 4), + (109, 8) => $expand!(109, 8), + (109, 12) => $expand!(109, 12), + (110, 4) => $expand!(110, 4), + (110, 8) => $expand!(110, 8), + (110, 12) => $expand!(110, 12), + (111, 4) => $expand!(111, 4), + (111, 8) => $expand!(111, 8), + (111, 12) => $expand!(111, 12), + (112, 4) => $expand!(112, 4), + (112, 8) => $expand!(112, 8), + (112, 12) => $expand!(112, 12), + (113, 4) => $expand!(113, 4), + (113, 8) => $expand!(113, 8), + (113, 12) => $expand!(113, 12), + (114, 4) => $expand!(114, 4), + (114, 8) => $expand!(114, 8), + (114, 12) => $expand!(114, 12), + (115, 4) => $expand!(115, 4), + (115, 8) => $expand!(115, 8), + (115, 12) => $expand!(115, 12), + (116, 4) => $expand!(116, 4), + (116, 8) => $expand!(116, 8), + (116, 12) => $expand!(116, 12), + (117, 4) => $expand!(117, 4), + (117, 8) => $expand!(117, 8), + (117, 12) => $expand!(117, 12), + (118, 4) => $expand!(118, 4), + (118, 8) => $expand!(118, 8), + (118, 12) => $expand!(118, 12), + (119, 4) => $expand!(119, 4), + (119, 8) => $expand!(119, 8), + (119, 12) => $expand!(119, 12), + (120, 4) => $expand!(120, 4), + (120, 8) => $expand!(120, 8), + (120, 12) => $expand!(120, 12), + (121, 4) => $expand!(121, 4), + (121, 8) => $expand!(121, 8), + (121, 12) => $expand!(121, 12), + (122, 4) => $expand!(122, 4), + (122, 8) => $expand!(122, 8), + (122, 12) => $expand!(122, 12), + (123, 4) => $expand!(123, 4), + (123, 8) => $expand!(123, 8), + (123, 12) => $expand!(123, 12), + (124, 4) => $expand!(124, 4), + (124, 8) => $expand!(124, 8), + (124, 12) => $expand!(124, 12), + (125, 4) => $expand!(125, 4), + (125, 8) => $expand!(125, 8), + (125, 12) => $expand!(125, 12), + (126, 4) => $expand!(126, 4), + (126, 8) => $expand!(126, 8), + (126, 12) => $expand!(126, 12), + (127, 4) => $expand!(127, 4), + (127, 8) => $expand!(127, 8), + (127, 12) => $expand!(127, 12), + (128, 4) => $expand!(128, 4), + (128, 8) => $expand!(128, 8), + (128, 12) => $expand!(128, 12), + (129, 4) => $expand!(129, 4), + (129, 8) => $expand!(129, 8), + (129, 12) => $expand!(129, 12), + (130, 4) => $expand!(130, 4), + (130, 8) => $expand!(130, 8), + (130, 12) => $expand!(130, 12), + (131, 4) => $expand!(131, 4), + (131, 8) => $expand!(131, 8), + (131, 12) => $expand!(131, 12), + (132, 4) => $expand!(132, 4), + (132, 8) => $expand!(132, 8), + (132, 12) => $expand!(132, 12), + (133, 4) => $expand!(133, 4), + (133, 8) => $expand!(133, 8), + (133, 12) => $expand!(133, 12), + (134, 4) => $expand!(134, 4), + (134, 8) => $expand!(134, 8), + (134, 12) => $expand!(134, 12), + (135, 4) => $expand!(135, 4), + (135, 8) => $expand!(135, 8), + (135, 12) => $expand!(135, 12), + (136, 4) => $expand!(136, 4), + (136, 8) => $expand!(136, 8), + (136, 12) => $expand!(136, 12), + (137, 4) => $expand!(137, 4), + (137, 8) => $expand!(137, 8), + (137, 12) => $expand!(137, 12), + (138, 4) => $expand!(138, 4), + (138, 8) => $expand!(138, 8), + (138, 12) => $expand!(138, 12), + (139, 4) => $expand!(139, 4), + (139, 8) => $expand!(139, 8), + (139, 12) => $expand!(139, 12), + (140, 4) => $expand!(140, 4), + (140, 8) => $expand!(140, 8), + (140, 12) => $expand!(140, 12), + (141, 4) => $expand!(141, 4), + (141, 8) => $expand!(141, 8), + (141, 12) => $expand!(141, 12), + (142, 4) => $expand!(142, 4), + (142, 8) => $expand!(142, 8), + (142, 12) => $expand!(142, 12), + (143, 4) => $expand!(143, 4), + (143, 8) => $expand!(143, 8), + (143, 12) => $expand!(143, 12), + (144, 4) => $expand!(144, 4), + (144, 8) => $expand!(144, 8), + (144, 12) => $expand!(144, 12), + (145, 4) => $expand!(145, 4), + (145, 8) => $expand!(145, 8), + (145, 12) => $expand!(145, 12), + (146, 4) => $expand!(146, 4), + (146, 8) => $expand!(146, 8), + (146, 12) => $expand!(146, 12), + (147, 4) => $expand!(147, 4), + (147, 8) => $expand!(147, 8), + (147, 12) => $expand!(147, 12), + (148, 4) => $expand!(148, 4), + (148, 8) => $expand!(148, 8), + (148, 12) => $expand!(148, 12), + (149, 4) => $expand!(149, 4), + (149, 8) => $expand!(149, 8), + (149, 12) => $expand!(149, 12), + (150, 4) => $expand!(150, 4), + (150, 8) => $expand!(150, 8), + (150, 12) => $expand!(150, 12), + (151, 4) => $expand!(151, 4), + (151, 8) => $expand!(151, 8), + (151, 12) => $expand!(151, 12), + (152, 4) => $expand!(152, 4), + (152, 8) => $expand!(152, 8), + (152, 12) => $expand!(152, 12), + (153, 4) => $expand!(153, 4), + (153, 8) => $expand!(153, 8), + (153, 12) => $expand!(153, 12), + (154, 4) => $expand!(154, 4), + (154, 8) => $expand!(154, 8), + (154, 12) => $expand!(154, 12), + (155, 4) => $expand!(155, 4), + (155, 8) => $expand!(155, 8), + (155, 12) => $expand!(155, 12), + (156, 4) => $expand!(156, 4), + (156, 8) => $expand!(156, 8), + (156, 12) => $expand!(156, 12), + (157, 4) => $expand!(157, 4), + (157, 8) => $expand!(157, 8), + (157, 12) => $expand!(157, 12), + (158, 4) => $expand!(158, 4), + (158, 8) => $expand!(158, 8), + (158, 12) => $expand!(158, 12), + (159, 4) => $expand!(159, 4), + (159, 8) => $expand!(159, 8), + (159, 12) => $expand!(159, 12), + (160, 4) => $expand!(160, 4), + (160, 8) => $expand!(160, 8), + (160, 12) => $expand!(160, 12), + (161, 4) => $expand!(161, 4), + (161, 8) => $expand!(161, 8), + (161, 12) => $expand!(161, 12), + (162, 4) => $expand!(162, 4), + (162, 8) => $expand!(162, 8), + (162, 12) => $expand!(162, 12), + (163, 4) => $expand!(163, 4), + (163, 8) => $expand!(163, 8), + (163, 12) => $expand!(163, 12), + (164, 4) => $expand!(164, 4), + (164, 8) => $expand!(164, 8), + (164, 12) => $expand!(164, 12), + (165, 4) => $expand!(165, 4), + (165, 8) => $expand!(165, 8), + (165, 12) => $expand!(165, 12), + (166, 4) => $expand!(166, 4), + (166, 8) => $expand!(166, 8), + (166, 12) => $expand!(166, 12), + (167, 4) => $expand!(167, 4), + (167, 8) => $expand!(167, 8), + (167, 12) => $expand!(167, 12), + (168, 4) => $expand!(168, 4), + (168, 8) => $expand!(168, 8), + (168, 12) => $expand!(168, 12), + (169, 4) => $expand!(169, 4), + (169, 8) => $expand!(169, 8), + (169, 12) => $expand!(169, 12), + (170, 4) => $expand!(170, 4), + (170, 8) => $expand!(170, 8), + (170, 12) => $expand!(170, 12), + (171, 4) => $expand!(171, 4), + (171, 8) => $expand!(171, 8), + (171, 12) => $expand!(171, 12), + (172, 4) => $expand!(172, 4), + (172, 8) => $expand!(172, 8), + (172, 12) => $expand!(172, 12), + (173, 4) => $expand!(173, 4), + (173, 8) => $expand!(173, 8), + (173, 12) => $expand!(173, 12), + (174, 4) => $expand!(174, 4), + (174, 8) => $expand!(174, 8), + (174, 12) => $expand!(174, 12), + (175, 4) => $expand!(175, 4), + (175, 8) => $expand!(175, 8), + (175, 12) => $expand!(175, 12), + (176, 4) => $expand!(176, 4), + (176, 8) => $expand!(176, 8), + (176, 12) => $expand!(176, 12), + (177, 4) => $expand!(177, 4), + (177, 8) => $expand!(177, 8), + (177, 12) => $expand!(177, 12), + (178, 4) => $expand!(178, 4), + (178, 8) => $expand!(178, 8), + (178, 12) => $expand!(178, 12), + (179, 4) => $expand!(179, 4), + (179, 8) => $expand!(179, 8), + (179, 12) => $expand!(179, 12), + (180, 4) => $expand!(180, 4), + (180, 8) => $expand!(180, 8), + (180, 12) => $expand!(180, 12), + (181, 4) => $expand!(181, 4), + (181, 8) => $expand!(181, 8), + (181, 12) => $expand!(181, 12), + (182, 4) => $expand!(182, 4), + (182, 8) => $expand!(182, 8), + (182, 12) => $expand!(182, 12), + (183, 4) => $expand!(183, 4), + (183, 8) => $expand!(183, 8), + (183, 12) => $expand!(183, 12), + (184, 4) => $expand!(184, 4), + (184, 8) => $expand!(184, 8), + (184, 12) => $expand!(184, 12), + (185, 4) => $expand!(185, 4), + (185, 8) => $expand!(185, 8), + (185, 12) => $expand!(185, 12), + (186, 4) => $expand!(186, 4), + (186, 8) => $expand!(186, 8), + (186, 12) => $expand!(186, 12), + (187, 4) => $expand!(187, 4), + (187, 8) => $expand!(187, 8), + (187, 12) => $expand!(187, 12), + (188, 4) => $expand!(188, 4), + (188, 8) => $expand!(188, 8), + (188, 12) => $expand!(188, 12), + (189, 4) => $expand!(189, 4), + (189, 8) => $expand!(189, 8), + (189, 12) => $expand!(189, 12), + (190, 4) => $expand!(190, 4), + (190, 8) => $expand!(190, 8), + (190, 12) => $expand!(190, 12), + (191, 4) => $expand!(191, 4), + (191, 8) => $expand!(191, 8), + (191, 12) => $expand!(191, 12), + (192, 4) => $expand!(192, 4), + (192, 8) => $expand!(192, 8), + (192, 12) => $expand!(192, 12), + (193, 4) => $expand!(193, 4), + (193, 8) => $expand!(193, 8), + (193, 12) => $expand!(193, 12), + (194, 4) => $expand!(194, 4), + (194, 8) => $expand!(194, 8), + (194, 12) => $expand!(194, 12), + (195, 4) => $expand!(195, 4), + (195, 8) => $expand!(195, 8), + (195, 12) => $expand!(195, 12), + (196, 4) => $expand!(196, 4), + (196, 8) => $expand!(196, 8), + (196, 12) => $expand!(196, 12), + (197, 4) => $expand!(197, 4), + (197, 8) => $expand!(197, 8), + (197, 12) => $expand!(197, 12), + (198, 4) => $expand!(198, 4), + (198, 8) => $expand!(198, 8), + (198, 12) => $expand!(198, 12), + (199, 4) => $expand!(199, 4), + (199, 8) => $expand!(199, 8), + (199, 12) => $expand!(199, 12), + (200, 4) => $expand!(200, 4), + (200, 8) => $expand!(200, 8), + (200, 12) => $expand!(200, 12), + (201, 4) => $expand!(201, 4), + (201, 8) => $expand!(201, 8), + (201, 12) => $expand!(201, 12), + (202, 4) => $expand!(202, 4), + (202, 8) => $expand!(202, 8), + (202, 12) => $expand!(202, 12), + (203, 4) => $expand!(203, 4), + (203, 8) => $expand!(203, 8), + (203, 12) => $expand!(203, 12), + (204, 4) => $expand!(204, 4), + (204, 8) => $expand!(204, 8), + (204, 12) => $expand!(204, 12), + (205, 4) => $expand!(205, 4), + (205, 8) => $expand!(205, 8), + (205, 12) => $expand!(205, 12), + (206, 4) => $expand!(206, 4), + (206, 8) => $expand!(206, 8), + (206, 12) => $expand!(206, 12), + (207, 4) => $expand!(207, 4), + (207, 8) => $expand!(207, 8), + (207, 12) => $expand!(207, 12), + (208, 4) => $expand!(208, 4), + (208, 8) => $expand!(208, 8), + (208, 12) => $expand!(208, 12), + (209, 4) => $expand!(209, 4), + (209, 8) => $expand!(209, 8), + (209, 12) => $expand!(209, 12), + (210, 4) => $expand!(210, 4), + (210, 8) => $expand!(210, 8), + (210, 12) => $expand!(210, 12), + (211, 4) => $expand!(211, 4), + (211, 8) => $expand!(211, 8), + (211, 12) => $expand!(211, 12), + (212, 4) => $expand!(212, 4), + (212, 8) => $expand!(212, 8), + (212, 12) => $expand!(212, 12), + (213, 4) => $expand!(213, 4), + (213, 8) => $expand!(213, 8), + (213, 12) => $expand!(213, 12), + (214, 4) => $expand!(214, 4), + (214, 8) => $expand!(214, 8), + (214, 12) => $expand!(214, 12), + (215, 4) => $expand!(215, 4), + (215, 8) => $expand!(215, 8), + (215, 12) => $expand!(215, 12), + (216, 4) => $expand!(216, 4), + (216, 8) => $expand!(216, 8), + (216, 12) => $expand!(216, 12), + (217, 4) => $expand!(217, 4), + (217, 8) => $expand!(217, 8), + (217, 12) => $expand!(217, 12), + (218, 4) => $expand!(218, 4), + (218, 8) => $expand!(218, 8), + (218, 12) => $expand!(218, 12), + (219, 4) => $expand!(219, 4), + (219, 8) => $expand!(219, 8), + (219, 12) => $expand!(219, 12), + (220, 4) => $expand!(220, 4), + (220, 8) => $expand!(220, 8), + (220, 12) => $expand!(220, 12), + (221, 4) => $expand!(221, 4), + (221, 8) => $expand!(221, 8), + (221, 12) => $expand!(221, 12), + (222, 4) => $expand!(222, 4), + (222, 8) => $expand!(222, 8), + (222, 12) => $expand!(222, 12), + (223, 4) => $expand!(223, 4), + (223, 8) => $expand!(223, 8), + (223, 12) => $expand!(223, 12), + (224, 4) => $expand!(224, 4), + (224, 8) => $expand!(224, 8), + (224, 12) => $expand!(224, 12), + (225, 4) => $expand!(225, 4), + (225, 8) => $expand!(225, 8), + (225, 12) => $expand!(225, 12), + (226, 4) => $expand!(226, 4), + (226, 8) => $expand!(226, 8), + (226, 12) => $expand!(226, 12), + (227, 4) => $expand!(227, 4), + (227, 8) => $expand!(227, 8), + (227, 12) => $expand!(227, 12), + (228, 4) => $expand!(228, 4), + (228, 8) => $expand!(228, 8), + (228, 12) => $expand!(228, 12), + (229, 4) => $expand!(229, 4), + (229, 8) => $expand!(229, 8), + (229, 12) => $expand!(229, 12), + (230, 4) => $expand!(230, 4), + (230, 8) => $expand!(230, 8), + (230, 12) => $expand!(230, 12), + (231, 4) => $expand!(231, 4), + (231, 8) => $expand!(231, 8), + (231, 12) => $expand!(231, 12), + (232, 4) => $expand!(232, 4), + (232, 8) => $expand!(232, 8), + (232, 12) => $expand!(232, 12), + (233, 4) => $expand!(233, 4), + (233, 8) => $expand!(233, 8), + (233, 12) => $expand!(233, 12), + (234, 4) => $expand!(234, 4), + (234, 8) => $expand!(234, 8), + (234, 12) => $expand!(234, 12), + (235, 4) => $expand!(235, 4), + (235, 8) => $expand!(235, 8), + (235, 12) => $expand!(235, 12), + (236, 4) => $expand!(236, 4), + (236, 8) => $expand!(236, 8), + (236, 12) => $expand!(236, 12), + (237, 4) => $expand!(237, 4), + (237, 8) => $expand!(237, 8), + (237, 12) => $expand!(237, 12), + (238, 4) => $expand!(238, 4), + (238, 8) => $expand!(238, 8), + (238, 12) => $expand!(238, 12), + (239, 4) => $expand!(239, 4), + (239, 8) => $expand!(239, 8), + (239, 12) => $expand!(239, 12), + (240, 4) => $expand!(240, 4), + (240, 8) => $expand!(240, 8), + (240, 12) => $expand!(240, 12), + (241, 4) => $expand!(241, 4), + (241, 8) => $expand!(241, 8), + (241, 12) => $expand!(241, 12), + (242, 4) => $expand!(242, 4), + (242, 8) => $expand!(242, 8), + (242, 12) => $expand!(242, 12), + (243, 4) => $expand!(243, 4), + (243, 8) => $expand!(243, 8), + (243, 12) => $expand!(243, 12), + (244, 4) => $expand!(244, 4), + (244, 8) => $expand!(244, 8), + (244, 12) => $expand!(244, 12), + (245, 4) => $expand!(245, 4), + (245, 8) => $expand!(245, 8), + (245, 12) => $expand!(245, 12), + (246, 4) => $expand!(246, 4), + (246, 8) => $expand!(246, 8), + (246, 12) => $expand!(246, 12), + (247, 4) => $expand!(247, 4), + (247, 8) => $expand!(247, 8), + (247, 12) => $expand!(247, 12), + (248, 4) => $expand!(248, 4), + (248, 8) => $expand!(248, 8), + (248, 12) => $expand!(248, 12), + (249, 4) => $expand!(249, 4), + (249, 8) => $expand!(249, 8), + (249, 12) => $expand!(249, 12), + (250, 4) => $expand!(250, 4), + (250, 8) => $expand!(250, 8), + (250, 12) => $expand!(250, 12), + (251, 4) => $expand!(251, 4), + (251, 8) => $expand!(251, 8), + (251, 12) => $expand!(251, 12), + (252, 4) => $expand!(252, 4), + (252, 8) => $expand!(252, 8), + (252, 12) => $expand!(252, 12), + (253, 4) => $expand!(253, 4), + (253, 8) => $expand!(253, 8), + (253, 12) => $expand!(253, 12), + (254, 4) => $expand!(254, 4), + (254, 8) => $expand!(254, 8), + (254, 12) => $expand!(254, 12), + (255, 4) => $expand!(255, 4), + (255, 8) => $expand!(255, 8), + (255, 12) => $expand!(255, 12), + (_, _) => panic!("Invalid sae value"), + } + }; +} + #[cfg(test)] macro_rules! assert_approx_eq { ($a:expr, $b:expr, $eps:expr) => {{ diff --git a/library/stdarch/crates/core_arch/src/x86/mod.rs b/library/stdarch/crates/core_arch/src/x86/mod.rs index a649cf3e2d..271707ecef 100644 --- a/library/stdarch/crates/core_arch/src/x86/mod.rs +++ b/library/stdarch/crates/core_arch/src/x86/mod.rs @@ -298,6 +298,14 @@ types! { pub struct __m512d(f64, f64, f64, f64, f64, f64, f64, f64); } +/// The `__mmask64` type used in AVX-512 intrinsics, a 64-bit integer +#[allow(non_camel_case_types)] +pub type __mmask64 = u64; + +/// The `__mmask32` type used in AVX-512 intrinsics, a 32-bit integer +#[allow(non_camel_case_types)] +pub type __mmask32 = u32; + /// The `__mmask16` type used in AVX-512 intrinsics, a 16-bit integer #[allow(non_camel_case_types)] pub type __mmask16 = u16; @@ -434,7 +442,7 @@ impl m256iExt for __m256i { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m128Ext: Sized { fn as_m128(self) -> __m128; @@ -451,6 +459,24 @@ impl m128Ext for __m128 { } } +#[allow(non_camel_case_types)] +#[unstable(feature = "stdsimd_internal", issue = "none")] +pub(crate) trait m128dExt: Sized { + fn as_m128d(self) -> __m128d; + + #[inline] + fn as_f64x2(self) -> crate::core_arch::simd::f64x2 { + unsafe { transmute(self.as_m128d()) } + } +} + +impl m128dExt for __m128d { + #[inline] + fn as_m128d(self) -> Self { + self + } +} + #[allow(non_camel_case_types)] #[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m256Ext: Sized { @@ -474,6 +500,26 @@ impl m256Ext for __m256 { pub(crate) trait m512iExt: Sized { fn as_m512i(self) -> __m512i; + #[inline] + fn as_u8x64(self) -> crate::core_arch::simd::u8x64 { + unsafe { transmute(self.as_m512i()) } + } + + #[inline] + fn as_i8x64(self) -> crate::core_arch::simd::i8x64 { + unsafe { transmute(self.as_m512i()) } + } + + #[inline] + fn as_u16x32(self) -> crate::core_arch::simd::u16x32 { + unsafe { transmute(self.as_m512i()) } + } + + #[inline] + fn as_i16x32(self) -> crate::core_arch::simd::i16x32 { + unsafe { transmute(self.as_m512i()) } + } + #[inline] fn as_u32x16(self) -> crate::core_arch::simd::u32x16 { unsafe { transmute(self.as_m512i()) } @@ -620,9 +666,38 @@ pub unsafe fn ud2() -> ! { mod avx512f; pub use self::avx512f::*; +mod avx512bw; +pub use self::avx512bw::*; + +mod avx512cd; +pub use self::avx512cd::*; + mod avx512ifma; pub use self::avx512ifma::*; +#[cfg(not(bootstrap))] +mod avx512bitalg; +#[cfg(not(bootstrap))] +pub use self::avx512bitalg::*; + +#[cfg(not(bootstrap))] +mod avx512gfni; +#[cfg(not(bootstrap))] +pub use self::avx512gfni::*; + +mod avx512vpopcntdq; +pub use self::avx512vpopcntdq::*; + +#[cfg(not(bootstrap))] +mod avx512vaes; +#[cfg(not(bootstrap))] +pub use self::avx512vaes::*; + +#[cfg(not(bootstrap))] +mod avx512vpclmulqdq; +#[cfg(not(bootstrap))] +pub use self::avx512vpclmulqdq::*; + mod bt; pub use self::bt::*; diff --git a/library/stdarch/crates/core_arch/src/x86/rtm.rs b/library/stdarch/crates/core_arch/src/x86/rtm.rs index 1e532b4efe..7cb1cc09bd 100644 --- a/library/stdarch/crates/core_arch/src/x86/rtm.rs +++ b/library/stdarch/crates/core_arch/src/x86/rtm.rs @@ -20,9 +20,9 @@ extern "C" { #[link_name = "llvm.x86.xbegin"] fn x86_xbegin() -> i32; #[link_name = "llvm.x86.xend"] - fn x86_xend() -> (); + fn x86_xend(); #[link_name = "llvm.x86.xabort"] - fn x86_xabort(imm8: i8) -> (); + fn x86_xabort(imm8: i8); #[link_name = "llvm.x86.xtest"] fn x86_xtest() -> i32; } diff --git a/library/stdarch/crates/core_arch/src/x86/sse.rs b/library/stdarch/crates/core_arch/src/x86/sse.rs index ba3efae3c9..f52ece769d 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse.rs @@ -957,9 +957,15 @@ pub unsafe fn _mm_set_ps(a: f32, b: f32, c: f32, d: f32) -> __m128 { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_ps) #[inline] #[target_feature(enable = "sse")] -#[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(unpcklps))] -// On a 32-bit architecture it just copies the operands from the stack. -#[cfg_attr(all(test, target_arch = "x86"), assert_instr(movaps))] +#[cfg_attr( + all(test, any(target_os = "windows", target_arch = "x86_64")), + assert_instr(unpcklps) +)] +// On a 32-bit architecture on non-Windows it just copies the operands from the stack. +#[cfg_attr( + all(test, all(not(target_os = "windows"), target_arch = "x86")), + assert_instr(movaps) +)] #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _mm_setr_ps(a: f32, b: f32, c: f32, d: f32) -> __m128 { __m128(a, b, c, d) @@ -3100,8 +3106,8 @@ mod tests { let mut p = vals.as_mut_ptr(); if (p as usize) & 0xf != 0 { - ofs = (16 - (p as usize) & 0xf) >> 2; - p = p.offset(ofs as isize); + ofs = ((16 - (p as usize)) & 0xf) >> 2; + p = p.add(ofs); } _mm_store1_ps(p, *black_box(&a)); @@ -3126,8 +3132,8 @@ mod tests { // Align p to 16-byte boundary if (p as usize) & 0xf != 0 { - ofs = (16 - (p as usize) & 0xf) >> 2; - p = p.offset(ofs as isize); + ofs = ((16 - (p as usize)) & 0xf) >> 2; + p = p.add(ofs); } _mm_store_ps(p, *black_box(&a)); @@ -3152,8 +3158,8 @@ mod tests { // Align p to 16-byte boundary if (p as usize) & 0xf != 0 { - ofs = (16 - (p as usize) & 0xf) >> 2; - p = p.offset(ofs as isize); + ofs = ((16 - (p as usize)) & 0xf) >> 2; + p = p.add(ofs); } _mm_storer_ps(p, *black_box(&a)); diff --git a/library/stdarch/crates/core_arch/src/x86/sse2.rs b/library/stdarch/crates/core_arch/src/x86/sse2.rs index b6c19cdef4..947b196f26 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse2.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse2.rs @@ -2812,8 +2812,14 @@ pub unsafe fn _mm_loadu_pd(mem_addr: *const f64) -> __m128d { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pd) #[inline] #[target_feature(enable = "sse2")] -#[cfg_attr(all(test, not(target_os = "windows")), assert_instr(shufps, imm8 = 1))] -#[cfg_attr(all(test, target_os = "windows"), assert_instr(shufpd, imm8 = 1))] +#[cfg_attr( + all(test, any(not(target_os = "windows"), target_arch = "x86")), + assert_instr(shufps, imm8 = 1) +)] +#[cfg_attr( + all(test, all(target_os = "windows", target_arch = "x86_64")), + assert_instr(shufpd, imm8 = 1) +)] #[rustc_args_required_const(2)] #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _mm_shuffle_pd(a: __m128d, b: __m128d, imm8: i32) -> __m128d { @@ -2832,8 +2838,14 @@ pub unsafe fn _mm_shuffle_pd(a: __m128d, b: __m128d, imm8: i32) -> __m128d { /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_sd) #[inline] #[target_feature(enable = "sse2")] -#[cfg_attr(all(test, not(target_os = "windows")), assert_instr(movsd))] -#[cfg_attr(all(test, target_os = "windows"), assert_instr(movlps))] +#[cfg_attr( + all(test, any(not(target_os = "windows"), target_arch = "x86")), + assert_instr(movsd) +)] +#[cfg_attr( + all(test, all(target_os = "windows", target_arch = "x86_64")), + assert_instr(movlps) +)] #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _mm_move_sd(a: __m128d, b: __m128d) -> __m128d { _mm_setr_pd(simd_extract(b, 0), simd_extract(a, 1)) diff --git a/library/stdarch/crates/core_arch/src/x86/sse41.rs b/library/stdarch/crates/core_arch/src/x86/sse41.rs index 4e1a9b373e..70c22dfeb6 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse41.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse41.rs @@ -178,7 +178,7 @@ pub unsafe fn _mm_extract_ps(a: __m128, imm8: i32) -> i32 { /// Extracts an 8-bit integer from `a`, selected with `imm8`. Returns a 32-bit /// integer containing the zero-extended integer data. /// -/// See [LLVM commit D20468][https://reviews.llvm.org/D20468]. +/// See [LLVM commit D20468](https://reviews.llvm.org/D20468). /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_epi8) #[inline] @@ -919,7 +919,7 @@ pub unsafe fn _mm_round_ss(a: __m128, b: __m128, rounding: i32) -> __m128 { /// index /// in its second position; all other elements are set to zero. /// -/// This intrinsic corresponds to the VPHMINPOSUW / PHMINPOSUW +/// This intrinsic corresponds to the `VPHMINPOSUW` / `PHMINPOSUW` /// instruction. /// /// Arguments: diff --git a/library/stdarch/crates/core_arch/src/x86/test.rs b/library/stdarch/crates/core_arch/src/x86/test.rs index a3ca0e0820..9014d66fd0 100644 --- a/library/stdarch/crates/core_arch/src/x86/test.rs +++ b/library/stdarch/crates/core_arch/src/x86/test.rs @@ -1,14 +1,11 @@ //! Utilities used in testing the x86 intrinsics use crate::core_arch::x86::*; +use std::mem::transmute; #[target_feature(enable = "sse2")] pub unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { - union A { - a: __m128i, - b: [u64; 2], - } - assert_eq!(A { a }.b, A { a: b }.b) + assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b)) } #[target_feature(enable = "sse2")] @@ -20,11 +17,7 @@ pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { #[target_feature(enable = "sse2")] pub unsafe fn get_m128d(a: __m128d, idx: usize) -> f64 { - union A { - a: __m128d, - b: [f64; 2], - }; - A { a }.b[idx] + transmute::<_, [f64; 2]>(a)[idx] } #[target_feature(enable = "sse")] @@ -37,11 +30,7 @@ pub unsafe fn assert_eq_m128(a: __m128, b: __m128) { #[target_feature(enable = "sse")] pub unsafe fn get_m128(a: __m128, idx: usize) -> f32 { - union A { - a: __m128, - b: [f32; 4], - }; - A { a }.b[idx] + transmute::<_, [f32; 4]>(a)[idx] } // not actually an intrinsic but useful in various tests as we proted from @@ -53,11 +42,7 @@ pub unsafe fn _mm_setr_epi64x(a: i64, b: i64) -> __m128i { #[target_feature(enable = "avx")] pub unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { - union A { - a: __m256i, - b: [u64; 4], - } - assert_eq!(A { a }.b, A { a: b }.b) + assert_eq!(transmute::<_, [u64; 4]>(a), transmute::<_, [u64; 4]>(b)) } #[target_feature(enable = "avx")] @@ -70,11 +55,7 @@ pub unsafe fn assert_eq_m256d(a: __m256d, b: __m256d) { #[target_feature(enable = "avx")] pub unsafe fn get_m256d(a: __m256d, idx: usize) -> f64 { - union A { - a: __m256d, - b: [f64; 4], - }; - A { a }.b[idx] + transmute::<_, [f64; 4]>(a)[idx] } #[target_feature(enable = "avx")] @@ -87,11 +68,22 @@ pub unsafe fn assert_eq_m256(a: __m256, b: __m256) { #[target_feature(enable = "avx")] pub unsafe fn get_m256(a: __m256, idx: usize) -> f32 { - union A { - a: __m256, - b: [f32; 8], - }; - A { a }.b[idx] + transmute::<_, [f32; 8]>(a)[idx] +} + +#[target_feature(enable = "avx512f")] +pub unsafe fn get_m512(a: __m512, idx: usize) -> f32 { + transmute::<_, [f32; 16]>(a)[idx] +} + +#[target_feature(enable = "avx512f")] +pub unsafe fn get_m512d(a: __m512d, idx: usize) -> f64 { + transmute::<_, [f64; 8]>(a)[idx] +} + +#[target_feature(enable = "avx512f")] +pub unsafe fn get_m512i(a: __m512i, idx: usize) -> i64 { + transmute::<_, [i64; 8]>(a)[idx] } // These intrinsics doesn't exist on x86 b/c it requires a 64-bit register, @@ -101,6 +93,7 @@ mod x86_polyfill { use crate::core_arch::x86::*; pub unsafe fn _mm_insert_epi64(a: __m128i, val: i64, idx: i32) -> __m128i { + #[repr(C)] union A { a: __m128i, b: [i64; 2], @@ -112,6 +105,7 @@ mod x86_polyfill { #[target_feature(enable = "avx2")] pub unsafe fn _mm256_insert_epi64(a: __m256i, val: i64, idx: i32) -> __m256i { + #[repr(C)] union A { a: __m256i, b: [i64; 4], @@ -128,11 +122,7 @@ mod x86_polyfill { pub use self::x86_polyfill::*; pub unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) { - union A { - a: __m512i, - b: [i32; 16], - } - assert_eq!(A { a }.b, A { a: b }.b) + assert_eq!(transmute::<_, [i32; 16]>(a), transmute::<_, [i32; 16]>(b)) } pub unsafe fn assert_eq_m512(a: __m512, b: __m512) { diff --git a/library/stdarch/crates/core_arch/src/x86/xsave.rs b/library/stdarch/crates/core_arch/src/x86/xsave.rs index 0076b1c9c4..5e2148840b 100644 --- a/library/stdarch/crates/core_arch/src/x86/xsave.rs +++ b/library/stdarch/crates/core_arch/src/x86/xsave.rs @@ -7,19 +7,21 @@ use stdarch_test::assert_instr; #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.xsave"] - fn xsave(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsave(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xrstor"] - fn xrstor(p: *const u8, hi: u32, lo: u32) -> (); + fn xrstor(p: *const u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xsetbv"] - fn xsetbv(v: u32, hi: u32, lo: u32) -> (); + fn xsetbv(v: u32, hi: u32, lo: u32); + #[link_name = "llvm.x86.xgetbv"] + fn xgetbv(v: u32) -> i64; #[link_name = "llvm.x86.xsaveopt"] - fn xsaveopt(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsaveopt(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xsavec"] - fn xsavec(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsavec(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xsaves"] - fn xsaves(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsaves(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xrstors"] - fn xrstors(p: *const u8, hi: u32, lo: u32) -> (); + fn xrstors(p: *const u8, hi: u32, lo: u32); } /// Performs a full or partial save of the enabled processor states to memory at @@ -85,10 +87,7 @@ pub unsafe fn _xsetbv(a: u32, val: u64) { #[cfg_attr(test, assert_instr(xgetbv))] #[stable(feature = "simd_x86", since = "1.27.0")] pub unsafe fn _xgetbv(xcr_no: u32) -> u64 { - let eax: u32; - let edx: u32; - llvm_asm!("xgetbv" : "={eax}"(eax), "={edx}"(edx) : "{ecx}"(xcr_no)); - ((edx as u64) << 32) | (eax as u64) + xgetbv(xcr_no) as u64 } /// Performs a full or partial save of the enabled processor states to memory at diff --git a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs index 54291877a0..f216a47f49 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs @@ -1,53 +1,17 @@ -use crate::{ - core_arch::{simd::*, x86::*}, - mem::transmute, -}; - -/// Sets packed 64-bit integers in `dst` with the supplied values. -/// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_epi64) -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_set_epi64( - e0: i64, - e1: i64, - e2: i64, - e3: i64, - e4: i64, - e5: i64, - e6: i64, - e7: i64, -) -> __m512i { - _mm512_setr_epi64(e7, e6, e5, e4, e3, e2, e1, e0) -} - -/// Sets packed 64-bit integers in `dst` with the supplied values in -/// reverse order. -/// -/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_epi64) -#[inline] -#[target_feature(enable = "avx512f")] -pub unsafe fn _mm512_setr_epi64( - e0: i64, - e1: i64, - e2: i64, - e3: i64, - e4: i64, - e5: i64, - e6: i64, - e7: i64, -) -> __m512i { - let r = i64x8::new(e0, e1, e2, e3, e4, e5, e6, e7); - transmute(r) -} +//use crate::{ +// +// core_arch::{simd::*, simd_llvm::*, x86::*}, +// mem::transmute, +//}; #[cfg(test)] mod tests { - use std; + use stdarch_test::simd_test; use crate::core_arch::x86::*; use crate::core_arch::x86_64::*; + use crate::hint::black_box; #[simd_test(enable = "avx512f")] unsafe fn test_mm512_abs_epi64() { @@ -105,6 +69,44 @@ mod tests { assert_eq_m512i(r, e); } + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mov_epi64() { + let src = _mm512_set1_epi64(1); + let a = _mm512_set1_epi64(2); + let r = _mm512_mask_mov_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_mov_epi64(src, 0b11111111, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mov_epi64() { + let a = _mm512_set1_epi64(2); + let r = _mm512_maskz_mov_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mov_epi64(0b11111111, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mov_pd() { + let src = _mm512_set1_pd(1.); + let a = _mm512_set1_pd(2.); + let r = _mm512_mask_mov_pd(src, 0, a); + assert_eq_m512d(r, src); + let r = _mm512_mask_mov_pd(src, 0b11111111, a); + assert_eq_m512d(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mov_pd() { + let a = _mm512_set1_pd(2.); + let r = _mm512_maskz_mov_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_mov_pd(0b11111111, a); + assert_eq_m512d(r, a); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_mask_add_epi64() { let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); @@ -1032,6 +1034,130 @@ mod tests { assert_eq_m512d(r, e); } + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_roundscale_pd() { + let a = _mm512_set1_pd(1.1); + let r = _mm512_roundscale_pd(a, 0); + let e = _mm512_set1_pd(1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_roundscale_pd() { + let a = _mm512_set1_pd(1.1); + let r = _mm512_mask_roundscale_pd(a, 0, a, 0); + let e = _mm512_set1_pd(1.1); + assert_eq_m512d(r, e); + let r = _mm512_mask_roundscale_pd(a, 0b11111111, a, 0); + let e = _mm512_set1_pd(1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_roundscale_pd() { + let a = _mm512_set1_pd(1.1); + let r = _mm512_maskz_roundscale_pd(0, a, 0); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_roundscale_pd(0b11111111, a, 0); + let e = _mm512_set1_pd(1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_scalef_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_scalef_pd(a, b); + let e = _mm512_set1_pd(8.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_scalef_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_mask_scalef_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_scalef_pd(a, 0b11110000, a, b); + let e = _mm512_set_pd(8., 8., 8., 8., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_scalef_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_maskz_scalef_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_scalef_pd(0b11110000, a, b); + let e = _mm512_set_pd(8., 8., 8., 8., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fixupimm_pd() { + let a = _mm512_set1_pd(f64::NAN); + let b = _mm512_set1_pd(f64::MAX); + let c = _mm512_set1_epi64(i32::MAX as i64); + let r = _mm512_fixupimm_pd(a, b, c, 5); + let e = _mm512_set1_pd(0.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fixupimm_pd() { + let a = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, 1., 1., 1., 1.); + let b = _mm512_set1_pd(f64::MAX); + let c = _mm512_set1_epi64(i32::MAX as i64); + let r = _mm512_mask_fixupimm_pd(a, 0b11110000, b, c, 5); + let e = _mm512_set_pd(0., 0., 0., 0., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fixupimm_pd() { + let a = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, 1., 1., 1., 1.); + let b = _mm512_set1_pd(f64::MAX); + let c = _mm512_set1_epi64(i32::MAX as i64); + let r = _mm512_maskz_fixupimm_pd(0b11110000, a, b, c, 5); + let e = _mm512_set_pd(0., 0., 0., 0., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_ternarylogic_epi64() { + let a = _mm512_set1_epi64(1 << 2); + let b = _mm512_set1_epi64(1 << 1); + let c = _mm512_set1_epi64(1 << 0); + let r = _mm512_ternarylogic_epi64(a, b, c, 8); + let e = _mm512_set1_epi64(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_ternarylogic_epi64() { + let src = _mm512_set1_epi64(1 << 2); + let a = _mm512_set1_epi64(1 << 1); + let b = _mm512_set1_epi64(1 << 0); + let r = _mm512_mask_ternarylogic_epi64(src, 0, a, b, 8); + assert_eq_m512i(r, src); + let r = _mm512_mask_ternarylogic_epi64(src, 0b11111111, a, b, 8); + let e = _mm512_set1_epi64(0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_ternarylogic_epi64() { + let a = _mm512_set1_epi64(1 << 2); + let b = _mm512_set1_epi64(1 << 1); + let c = _mm512_set1_epi64(1 << 0); + let r = _mm512_maskz_ternarylogic_epi64(0, a, b, c, 9); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_ternarylogic_epi64(0b11111111, a, b, c, 8); + let e = _mm512_set1_epi64(0); + assert_eq_m512i(r, e); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_getmant_pd() { let a = _mm512_set1_pd(10.); @@ -1090,204 +1216,827 @@ mod tests { } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvtt_roundpd_epi32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_cvtt_roundpd_epi32(a, _MM_FROUND_NO_EXC); - let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); - assert_eq_m256i(r, e); + unsafe fn test_mm512_cvtpslo_pd() { + let v2 = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 100., 100., 100., 100., 100., 100., 100., 100., + ); + let r = _mm512_cvtpslo_pd(v2); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvtt_roundpd_epi32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let src = _mm256_set1_epi32(0); - let r = _mm512_mask_cvtt_roundpd_epi32(src, 0, a, _MM_FROUND_NO_EXC); - assert_eq_m256i(r, src); - let r = _mm512_mask_cvtt_roundpd_epi32(src, 0b00001111, a, _MM_FROUND_NO_EXC); - let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); - assert_eq_m256i(r, e); + unsafe fn test_mm512_mask_cvtpslo_pd() { + let v2 = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 100., 100., 100., 100., 100., 100., 100., 100., + ); + let src = _mm512_set1_pd(0.); + let r = _mm512_mask_cvtpslo_pd(src, 0, v2); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvtpslo_pd(src, 0b00001111, v2); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvtt_roundpd_epi32() { + unsafe fn test_mm512_cvtpd_ps() { let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_maskz_cvtt_roundpd_epi32(0, a, _MM_FROUND_NO_EXC); - assert_eq_m256i(r, _mm256_setzero_si256()); - let r = _mm512_maskz_cvtt_roundpd_epi32(0b00001111, a, _MM_FROUND_NO_EXC); - let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); - assert_eq_m256i(r, e); + let r = _mm512_cvtpd_ps(a); + let e = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + assert_eq_m256(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvtt_roundpd_epu32() { + unsafe fn test_mm512_mask_cvtpd_ps() { let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_cvtt_roundpd_epu32(a, _MM_FROUND_NO_EXC); - let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); - assert_eq_m256i(r, e); + let src = _mm256_set1_ps(0.); + let r = _mm512_mask_cvtpd_ps(src, 0, a); + assert_eq_m256(r, src); + let r = _mm512_mask_cvtpd_ps(src, 0b00001111, a); + let e = _mm256_setr_ps(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m256(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvtt_roundpd_epu32() { + unsafe fn test_mm512_maskz_cvtpd_ps() { let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let src = _mm256_set1_epi32(0); - let r = _mm512_mask_cvtt_roundpd_epu32(src, 0, a, _MM_FROUND_NO_EXC); - assert_eq_m256i(r, src); - let r = _mm512_mask_cvtt_roundpd_epu32(src, 0b00001111, a, _MM_FROUND_NO_EXC); - let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); - assert_eq_m256i(r, e); + let r = _mm512_maskz_cvtpd_ps(0, a); + assert_eq_m256(r, _mm256_setzero_ps()); + let r = _mm512_maskz_cvtpd_ps(0b00001111, a); + let e = _mm256_setr_ps(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m256(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvtt_roundpd_epu32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_maskz_cvtt_roundpd_epu32(0, a, _MM_FROUND_NO_EXC); - assert_eq_m256i(r, _mm256_setzero_si256()); - let r = _mm512_maskz_cvtt_roundpd_epu32(0b00001111, a, _MM_FROUND_NO_EXC); - let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); - assert_eq_m256i(r, e); + unsafe fn test_mm512_cvtpd_pslo() { + let v2 = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtpd_pslo(v2); + let e = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvttpd_epi32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_cvttpd_epi32(a); - let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); - assert_eq_m256i(r, e); + unsafe fn test_mm512_mask_cvtpd_pslo() { + let v2 = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm512_set1_ps(0.); + let r = _mm512_mask_cvtpd_pslo(src, 0, v2); + assert_eq_m512(r, src); + let r = _mm512_mask_cvtpd_pslo(src, 0b00001111, v2); + let e = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvttpd_epi32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let src = _mm256_set1_epi32(0); - let r = _mm512_mask_cvttpd_epi32(src, 0, a); - assert_eq_m256i(r, src); - let r = _mm512_mask_cvttpd_epi32(src, 0b00001111, a); - let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); - assert_eq_m256i(r, e); + unsafe fn test_mm512_cvtepi8_epi64() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi8_epi64(a); + let e = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvttpd_epi32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_maskz_cvttpd_epi32(0, a); - assert_eq_m256i(r, _mm256_setzero_si256()); - let r = _mm512_maskz_cvttpd_epi32(0b00001111, a); - let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); - assert_eq_m256i(r, e); + unsafe fn test_mm512_mask_cvtepi8_epi64() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi64(-1); + let r = _mm512_mask_cvtepi8_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepi8_epi64(src, 0b00001111, a); + let e = _mm512_set_epi64(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_cvttpd_epu32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_cvttpd_epu32(a); - let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); - assert_eq_m256i(r, e); + unsafe fn test_mm512_maskz_cvtepi8_epi64() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi8_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepi8_epi64(0b00001111, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_cvttpd_epu32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let src = _mm256_set1_epi32(0); - let r = _mm512_mask_cvttpd_epu32(src, 0, a); - assert_eq_m256i(r, src); - let r = _mm512_mask_cvttpd_epu32(src, 0b00001111, a); - let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); - assert_eq_m256i(r, e); + unsafe fn test_mm512_cvtepu8_epi64() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu8_epi64(a); + let e = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_cvttpd_epu32() { - let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); - let r = _mm512_maskz_cvttpd_epu32(0, a); - assert_eq_m256i(r, _mm256_setzero_si256()); - let r = _mm512_maskz_cvttpd_epu32(0b00001111, a); - let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); - assert_eq_m256i(r, e); + unsafe fn test_mm512_mask_cvtepu8_epi64() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi64(-1); + let r = _mm512_mask_cvtepu8_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepu8_epi64(src, 0b00001111, a); + let e = _mm512_set_epi64(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_add_round_pd() { - let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); - let b = _mm512_set1_pd(-1.); - let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); - assert_eq_m512d(r, e); - let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); - assert_eq_m512d(r, e); + unsafe fn test_mm512_maskz_cvtepu8_epi64() { + let a = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepu8_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepu8_epi64(0b00001111, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_add_round_pd() { - let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); - let b = _mm512_set1_pd(-1.); - let r = _mm512_mask_add_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512d(r, a); - let r = _mm512_mask_add_round_pd( - a, - 0b11110000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); - assert_eq_m512d(r, e); + unsafe fn test_mm512_cvtepi16_epi64() { + let a = _mm_set_epi16(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi16_epi64(a); + let e = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_add_round_pd() { - let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); - let b = _mm512_set1_pd(-1.); - let r = _mm512_maskz_add_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512d(r, _mm512_setzero_pd()); - let r = _mm512_maskz_add_round_pd( - 0b11110000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_pd(0., 0., 0., 0., 11., 12.5, 13., -1.0); - assert_eq_m512d(r, e); + unsafe fn test_mm512_mask_cvtepi16_epi64() { + let a = _mm_set_epi16(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi64(-1); + let r = _mm512_mask_cvtepi16_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepi16_epi64(src, 0b00001111, a); + let e = _mm512_set_epi64(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_sub_round_pd() { - let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); - let b = _mm512_set1_pd(1.); - let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); - assert_eq_m512d(r, e); - let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); - assert_eq_m512d(r, e); + unsafe fn test_mm512_maskz_cvtepi16_epi64() { + let a = _mm_set_epi16(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi16_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepi16_epi64(0b00001111, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_mask_sub_round_pd() { - let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); - let b = _mm512_set1_pd(1.); - let r = _mm512_mask_sub_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512d(r, a); - let r = _mm512_mask_sub_round_pd( - a, - 0b11110000, - a, - b, - _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, - ); - let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); - assert_eq_m512d(r, e); + unsafe fn test_mm512_cvtepu16_epi64() { + let a = _mm_set_epi16(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu16_epi64(a); + let e = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_maskz_sub_round_pd() { - let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); - let b = _mm512_set1_pd(1.); - let r = _mm512_maskz_sub_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - assert_eq_m512d(r, _mm512_setzero_pd()); - let r = _mm512_maskz_sub_round_pd( - 0b11110000, - a, + unsafe fn test_mm512_mask_cvtepu16_epi64() { + let a = _mm_set_epi16(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi64(-1); + let r = _mm512_mask_cvtepu16_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepu16_epi64(src, 0b00001111, a); + let e = _mm512_set_epi64(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepu16_epi64() { + let a = _mm_set_epi16(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepu16_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepu16_epi64(0b00001111, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi32_epi64() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi32_epi64(a); + let e = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi32_epi64() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi64(-1); + let r = _mm512_mask_cvtepi32_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepi32_epi64(src, 0b00001111, a); + let e = _mm512_set_epi64(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi32_epi64() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi32_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepi32_epi64(0b00001111, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepu32_epi64() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu32_epi64(a); + let e = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepu32_epi64() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_epi64(-1); + let r = _mm512_mask_cvtepu32_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtepu32_epi64(src, 0b00001111, a); + let e = _mm512_set_epi64(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepu32_epi64() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepu32_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtepu32_epi64(0b00001111, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi32_pd() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi32_pd(a); + let e = _mm512_set_pd(8., 9., 10., 11., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi32_pd() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_pd(-1.); + let r = _mm512_mask_cvtepi32_pd(src, 0, a); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvtepi32_pd(src, 0b00001111, a); + let e = _mm512_set_pd(-1., -1., -1., -1., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi32_pd() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi32_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_cvtepi32_pd(0b00001111, a); + let e = _mm512_set_pd(0., 0., 0., 0., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepu32_pd() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu32_pd(a); + let e = _mm512_set_pd(8., 9., 10., 11., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepu32_pd() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_pd(-1.); + let r = _mm512_mask_cvtepu32_pd(src, 0, a); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvtepu32_pd(src, 0b00001111, a); + let e = _mm512_set_pd(-1., -1., -1., -1., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepu32_pd() { + let a = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepu32_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_cvtepu32_pd(0b00001111, a); + let e = _mm512_set_pd(0., 0., 0., 0., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi32lo_pd() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi32lo_pd(a); + let e = _mm512_set_pd(8., 9., 10., 11., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi32lo_pd() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_pd(-1.); + let r = _mm512_mask_cvtepi32lo_pd(src, 0, a); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvtepi32lo_pd(src, 0b00001111, a); + let e = _mm512_set_pd(-1., -1., -1., -1., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepu32lo_pd() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepu32lo_pd(a); + let e = _mm512_set_pd(8., 9., 10., 11., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepu32lo_pd() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm512_set1_pd(-1.); + let r = _mm512_mask_cvtepu32lo_pd(src, 0, a); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvtepu32lo_pd(src, 0b00001111, a); + let e = _mm512_set_pd(-1., -1., -1., -1., 12., 13., 14., 15.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi64_epi32() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi64_epi32(a); + let e = _mm256_set_epi32(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi64_epi32() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm256_set1_epi32(-1); + let r = _mm512_mask_cvtepi64_epi32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtepi64_epi32(src, 0b00001111, a); + let e = _mm256_set_epi32(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi64_epi32() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi64_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtepi64_epi32(0b00001111, a); + let e = _mm256_set_epi32(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi64_epi16() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi64_epi16(a); + let e = _mm_set_epi16(8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi64_epi16() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm_set1_epi16(-1); + let r = _mm512_mask_cvtepi64_epi16(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtepi64_epi16(src, 0b00001111, a); + let e = _mm_set_epi16(-1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi64_epi16() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi64_epi16(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtepi64_epi16(0b00001111, a); + let e = _mm_set_epi16(0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtepi64_epi8() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_cvtepi64_epi8(a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtepi64_epi8() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let src = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + let r = _mm512_mask_cvtepi64_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtepi64_epi8(src, 0b00001111, a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtepi64_epi8() { + let a = _mm512_set_epi64(8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_cvtepi64_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtepi64_epi8(0b00001111, a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 14, 15); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtsepi64_epi32() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let r = _mm512_cvtsepi64_epi32(a); + let e = _mm256_set_epi32(0, 1, 2, 3, 4, 5, i32::MIN, i32::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtsepi64_epi32() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let src = _mm256_set1_epi32(-1); + let r = _mm512_mask_cvtsepi64_epi32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtsepi64_epi32(src, 0b00001111, a); + let e = _mm256_set_epi32(-1, -1, -1, -1, 4, 5, i32::MIN, i32::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtsepi64_epi32() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let r = _mm512_maskz_cvtsepi64_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtsepi64_epi32(0b00001111, a); + let e = _mm256_set_epi32(0, 0, 0, 0, 4, 5, i32::MIN, i32::MAX); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtsepi64_epi16() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let r = _mm512_cvtsepi64_epi16(a); + let e = _mm_set_epi16(0, 1, 2, 3, 4, 5, i16::MIN, i16::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtsepi64_epi16() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let src = _mm_set1_epi16(-1); + let r = _mm512_mask_cvtsepi64_epi16(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtsepi64_epi16(src, 0b00001111, a); + let e = _mm_set_epi16(-1, -1, -1, -1, 4, 5, i16::MIN, i16::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtsepi64_epi16() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let r = _mm512_maskz_cvtsepi64_epi16(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtsepi64_epi16(0b00001111, a); + let e = _mm_set_epi16(0, 0, 0, 0, 4, 5, i16::MIN, i16::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtsepi64_epi8() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let r = _mm512_cvtsepi64_epi8(a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, i8::MIN, i8::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtsepi64_epi8() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let src = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + let r = _mm512_mask_cvtsepi64_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtsepi64_epi8(src, 0b00001111, a); + let e = _mm_set_epi8( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + -1, + -1, + -1, + -1, + 4, + 5, + i8::MIN, + i8::MAX, + ); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtsepi64_epi8() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MAX); + let r = _mm512_maskz_cvtsepi64_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtsepi64_epi8(0b00001111, a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, i8::MIN, i8::MAX); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtusepi64_epi32() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let r = _mm512_cvtusepi64_epi32(a); + let e = _mm256_set_epi32(0, 1, 2, 3, 4, 5, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtusepi64_epi32() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let src = _mm256_set1_epi32(-1); + let r = _mm512_mask_cvtusepi64_epi32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtusepi64_epi32(src, 0b00001111, a); + let e = _mm256_set_epi32(-1, -1, -1, -1, 4, 5, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtusepi64_epi32() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let r = _mm512_maskz_cvtusepi64_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtusepi64_epi32(0b00001111, a); + let e = _mm256_set_epi32(0, 0, 0, 0, 4, 5, -1, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtusepi64_epi16() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let r = _mm512_cvtusepi64_epi16(a); + let e = _mm_set_epi16(0, 1, 2, 3, 4, 5, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtusepi64_epi16() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let src = _mm_set1_epi16(-1); + let r = _mm512_mask_cvtusepi64_epi16(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtusepi64_epi16(src, 0b00001111, a); + let e = _mm_set_epi16(-1, -1, -1, -1, 4, 5, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtusepi64_epi16() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let r = _mm512_maskz_cvtusepi64_epi16(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtusepi64_epi16(0b00001111, a); + let e = _mm_set_epi16(0, 0, 0, 0, 4, 5, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtusepi64_epi8() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let r = _mm512_cvtusepi64_epi8(a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtusepi64_epi8() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let src = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1); + let r = _mm512_mask_cvtusepi64_epi8(src, 0, a); + assert_eq_m128i(r, src); + let r = _mm512_mask_cvtusepi64_epi8(src, 0b00001111, a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 4, 5, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtusepi64_epi8() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, i64::MIN, i64::MIN); + let r = _mm512_maskz_cvtusepi64_epi8(0, a); + assert_eq_m128i(r, _mm_setzero_si128()); + let r = _mm512_maskz_cvtusepi64_epi8(0b00001111, a); + let e = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, -1, -1); + assert_eq_m128i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtt_roundpd_epi32(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvtt_roundpd_epi32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtt_roundpd_epi32(src, 0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtt_roundpd_epi32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtt_roundpd_epi32(0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtt_roundpd_epu32(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvtt_roundpd_epu32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtt_roundpd_epu32(src, 0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtt_roundpd_epu32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtt_roundpd_epu32(0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvttpd_epi32(a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvttpd_epi32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvttpd_epi32(src, 0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvttpd_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvttpd_epi32(0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvttpd_epu32(a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvttpd_epu32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvttpd_epu32(src, 0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvttpd_epu32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvttpd_epu32(0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_mask_add_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_add_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_maskz_add_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_add_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(0., 0., 0., 0., 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_mask_sub_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_sub_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_maskz_sub_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sub_round_pd( + 0b11110000, + a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, ); @@ -1375,7 +2124,7 @@ mod tests { let e = _mm512_set1_pd(0.3333333333333333); assert_eq_m512d(r, e); let r = _mm512_div_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); - let e = _mm512_set1_pd(0.33333333333333334); + let e = _mm512_set1_pd(0.3333333333333333); assert_eq_m512d(r, e); } @@ -2100,6 +2849,109 @@ mod tests { assert_eq_m512d(r, e); } + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_roundscale_round_pd() { + let a = _mm512_set1_pd(1.1); + let r = _mm512_roundscale_round_pd(a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_pd(1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_roundscale_round_pd() { + let a = _mm512_set1_pd(1.1); + let r = _mm512_mask_roundscale_round_pd(a, 0, a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_pd(1.1); + assert_eq_m512d(r, e); + let r = _mm512_mask_roundscale_round_pd(a, 0b11111111, a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_pd(1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_roundscale_round_pd() { + let a = _mm512_set1_pd(1.1); + let r = _mm512_maskz_roundscale_round_pd(0, a, 0, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_roundscale_round_pd(0b11111111, a, 0, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_pd(1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_scalef_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_scalef_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(8.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_scalef_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = + _mm512_mask_scalef_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_scalef_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_set_pd(8., 8., 8., 8., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_scalef_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = + _mm512_maskz_scalef_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_scalef_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_set_pd(8., 8., 8., 8., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fixupimm_round_pd() { + let a = _mm512_set1_pd(f64::NAN); + let b = _mm512_set1_pd(f64::MAX); + let c = _mm512_set1_epi64(i32::MAX as i64); + let r = _mm512_fixupimm_round_pd(a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_pd(0.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fixupimm_round_pd() { + let a = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, 1., 1., 1., 1.); + let b = _mm512_set1_pd(f64::MAX); + let c = _mm512_set1_epi64(i32::MAX as i64); + let r = _mm512_mask_fixupimm_round_pd(a, 0b11110000, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set_pd(0., 0., 0., 0., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fixupimm_round_pd() { + let a = _mm512_set_pd(f64::NAN, f64::NAN, f64::NAN, f64::NAN, 1., 1., 1., 1.); + let b = _mm512_set1_pd(f64::MAX); + let c = _mm512_set1_epi64(i32::MAX as i64); + let r = _mm512_maskz_fixupimm_round_pd(0b11110000, a, b, c, 5, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set_pd(0., 0., 0., 0., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_getmant_round_pd() { let a = _mm512_set1_pd(10.); @@ -2188,20 +3040,129 @@ mod tests { assert_eq_m512d(r, e); } + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundpd_ps() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvt_roundpd_ps(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + assert_eq_m256(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundpd_ps() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_ps(0.); + let r = _mm512_mask_cvt_roundpd_ps(src, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m256(r, src); + let r = _mm512_mask_cvt_roundpd_ps(src, 0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_ps(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m256(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundpd_ps() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvt_roundpd_ps(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m256(r, _mm256_setzero_ps()); + let r = _mm512_maskz_cvt_roundpd_ps(0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_ps(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m256(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvt_roundpd_epi32(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvt_roundpd_epi32(src, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvt_roundpd_epi32(src, 0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_epi32(0, -2, 2, -4, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvt_roundpd_epi32(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvt_roundpd_epi32(0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_epi32(0, -2, 2, -4, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvt_roundpd_epu32(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvt_roundpd_epu32(src, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvt_roundpd_epu32(src, 0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvt_roundpd_epu32(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvt_roundpd_epu32(0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_setzero_pd() { assert_eq_m512d(_mm512_setzero_pd(), _mm512_set1_pd(0.)); } + unsafe fn test_mm512_set1_epi64() { + let r = _mm512_set_epi64(2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, _mm512_set1_epi64(2)); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_set1_pd() { let expected = _mm512_set_pd(2., 2., 2., 2., 2., 2., 2., 2.); assert_eq_m512d(expected, _mm512_set1_pd(2.)); } - unsafe fn test_mm512_set1_epi64() { - let r = _mm512_set_epi64(2, 2, 2, 2, 2, 2, 2, 2); - assert_eq_m512i(r, _mm512_set1_epi64(2)); + unsafe fn test_mm512_set4_epi64() { + let r = _mm512_set_epi64(4, 3, 2, 1, 4, 3, 2, 1); + assert_eq_m512i(r, _mm512_set4_epi64(4, 3, 2, 1)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_set4_pd() { + let r = _mm512_set_pd(4., 3., 2., 1., 4., 3., 2., 1.); + assert_eq_m512d(r, _mm512_set4_pd(4., 3., 2., 1.)); + } + + unsafe fn test_mm512_setr4_epi64() { + let r = _mm512_set_epi64(4, 3, 2, 1, 4, 3, 2, 1); + assert_eq_m512i(r, _mm512_setr4_epi64(1, 2, 3, 4)); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_setr4_pd() { + let r = _mm512_set_pd(4., 3., 2., 1., 4., 3., 2., 1.); + assert_eq_m512d(r, _mm512_setr4_pd(1., 2., 3., 4.)); } #[simd_test(enable = "avx512f")] @@ -4341,18 +5302,34 @@ mod tests { } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castpd128_pd512() { + unsafe fn test_mm512_castpd128_pd512() { + let a = _mm_setr_pd(17., 18.); + let r = _mm512_castpd128_pd512(a); + let e = _mm512_setr_pd(17., 18., -1., -1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_castpd256_pd512() { + let a = _mm256_setr_pd(17., 18., 19., 20.); + let r = _mm512_castpd256_pd512(a); + let e = _mm512_setr_pd(17., 18., 19., 20., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_zextpd128_pd512() { let a = _mm_setr_pd(17., 18.); - let r = _mm512_castpd128_pd512(a); - let e = _mm512_setr_pd(17., 18., -1., -1., -1., -1., -1., -1.); + let r = _mm512_zextpd128_pd512(a); + let e = _mm512_setr_pd(17., 18., 0., 0., 0., 0., 0., 0.); assert_eq_m512d(r, e); } #[simd_test(enable = "avx512f")] - unsafe fn test_mm512_castpd256_pd512() { + unsafe fn test_mm512_zextpd256_pd512() { let a = _mm256_setr_pd(17., 18., 19., 20.); - let r = _mm512_castpd256_pd512(a); - let e = _mm512_setr_pd(17., 18., 19., 20., -1., -1., -1., -1.); + let r = _mm512_zextpd256_pd512(a); + let e = _mm512_setr_pd(17., 18., 19., 20., 0., 0., 0., 0.); assert_eq_m512d(r, e); } @@ -4410,6 +5387,22 @@ mod tests { assert_eq_m512i(r, e); } + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_zextsi128_si512() { + let a = _mm_setr_epi64x(17, 18); + let r = _mm512_zextsi128_si512(a); + let e = _mm512_setr_epi64(17, 18, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_zextsi256_si512() { + let a = _mm256_setr_epi64x(17, 18, 19, 20); + let r = _mm512_zextsi256_si512(a); + let e = _mm512_setr_epi64(17, 18, 19, 20, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_castsi512_si128() { let a = _mm512_setr_epi64(17, 18, -1, -1, -1, -1, -1, -1); @@ -4702,6 +5695,41 @@ mod tests { assert_eq_m512d(r, e); } + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_alignr_epi64() { + let a = _mm512_set_epi64(8, 7, 6, 5, 4, 3, 2, 1); + let b = _mm512_set_epi64(16, 15, 14, 13, 12, 11, 10, 9); + let r = _mm512_alignr_epi64(a, b, 0); + assert_eq_m512i(r, b); + let r = _mm512_alignr_epi64(a, b, 8); + assert_eq_m512i(r, b); + let r = _mm512_alignr_epi64(a, b, 1); + let e = _mm512_set_epi64(1, 16, 15, 14, 13, 12, 11, 10); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_alignr_epi64() { + let a = _mm512_set_epi64(8, 7, 6, 5, 4, 3, 2, 1); + let b = _mm512_set_epi64(16, 15, 14, 13, 12, 11, 10, 9); + let r = _mm512_mask_alignr_epi64(a, 0, a, b, 1); + assert_eq_m512i(r, a); + let r = _mm512_mask_alignr_epi64(a, 0b11111111, a, b, 1); + let e = _mm512_set_epi64(1, 16, 15, 14, 13, 12, 11, 10); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_alignr_epi64() { + let a = _mm512_set_epi64(8, 7, 6, 5, 4, 3, 2, 1); + let b = _mm512_set_epi64(16, 15, 14, 13, 12, 11, 10, 9); + let r = _mm512_maskz_alignr_epi64(0, a, b, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_alignr_epi64(0b00001111, a, b, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 13, 12, 11, 10); + assert_eq_m512i(r, e); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_and_epi64() { let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); @@ -4911,4 +5939,452 @@ mod tests { let e = _mm512_set1_epi64(1 << 3 | 1 << 4); assert_eq_m512i(r, e); } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_add_epi64() { + let a = _mm512_set1_epi64(1); + let e: i64 = _mm512_reduce_add_epi64(a); + assert_eq!(8, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_add_epi64() { + let a = _mm512_set1_epi64(1); + let e: i64 = _mm512_mask_reduce_add_epi64(0b11110000, a); + assert_eq!(4, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_add_pd() { + let a = _mm512_set1_pd(1.); + let e: f64 = _mm512_reduce_add_pd(a); + assert_eq!(8., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_add_pd() { + let a = _mm512_set1_pd(1.); + let e: f64 = _mm512_mask_reduce_add_pd(0b11110000, a); + assert_eq!(4., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_mul_epi64() { + let a = _mm512_set1_epi64(2); + let e: i64 = _mm512_reduce_mul_epi64(a); + assert_eq!(256, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_mul_epi64() { + let a = _mm512_set1_epi64(2); + let e: i64 = _mm512_mask_reduce_mul_epi64(0b11110000, a); + assert_eq!(16, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_mul_pd() { + let a = _mm512_set1_pd(2.); + let e: f64 = _mm512_reduce_mul_pd(a); + assert_eq!(256., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_mul_pd() { + let a = _mm512_set1_pd(2.); + let e: f64 = _mm512_mask_reduce_mul_pd(0b11110000, a); + assert_eq!(16., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_max_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: i64 = _mm512_reduce_max_epi64(a); + assert_eq!(7, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_max_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: i64 = _mm512_mask_reduce_max_epi64(0b11110000, a); + assert_eq!(3, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_max_epu64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: u64 = _mm512_reduce_max_epu64(a); + assert_eq!(7, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_max_epu64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: u64 = _mm512_mask_reduce_max_epu64(0b11110000, a); + assert_eq!(3, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_max_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let e: f64 = _mm512_reduce_max_pd(a); + assert_eq!(7., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_max_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let e: f64 = _mm512_mask_reduce_max_pd(0b11110000, a); + assert_eq!(3., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_min_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: i64 = _mm512_reduce_min_epi64(a); + assert_eq!(0, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_min_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: i64 = _mm512_mask_reduce_min_epi64(0b11110000, a); + assert_eq!(0, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_min_epu64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: u64 = _mm512_reduce_min_epu64(a); + assert_eq!(0, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_min_epu64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let e: u64 = _mm512_mask_reduce_min_epu64(0b11110000, a); + assert_eq!(0, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_min_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let e: f64 = _mm512_reduce_min_pd(a); + assert_eq!(0., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_min_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let e: f64 = _mm512_mask_reduce_min_pd(0b11110000, a); + assert_eq!(0., e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_and_epi64() { + let a = _mm512_set_epi64(1, 1, 1, 1, 2, 2, 2, 2); + let e: i64 = _mm512_reduce_and_epi64(a); + assert_eq!(0, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_and_epi64() { + let a = _mm512_set_epi64(1, 1, 1, 1, 2, 2, 2, 2); + let e: i64 = _mm512_mask_reduce_and_epi64(0b11110000, a); + assert_eq!(1, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_reduce_or_epi64() { + let a = _mm512_set_epi64(1, 1, 1, 1, 2, 2, 2, 2); + let e: i64 = _mm512_reduce_or_epi64(a); + assert_eq!(3, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_reduce_or_epi64() { + let a = _mm512_set_epi64(1, 1, 1, 1, 2, 2, 2, 2); + let e: i64 = _mm512_mask_reduce_or_epi64(0b11110000, a); + assert_eq!(1, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_extractf64x4_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_extractf64x4_pd(a, 0x1); + let e = _mm256_setr_pd(5., 6., 7., 8.); + assert_eq_m256d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_extractf64x4_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let src = _mm256_set1_pd(100.); + let r = _mm512_mask_extractf64x4_pd(src, 0, a, 0x1); + assert_eq_m256d(r, src); + let r = _mm512_mask_extractf64x4_pd(src, 0b11111111, a, 0x1); + let e = _mm256_setr_pd(5., 6., 7., 8.); + assert_eq_m256d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_extractf64x4_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_maskz_extractf64x4_pd(0, a, 0x1); + assert_eq_m256d(r, _mm256_setzero_pd()); + let r = _mm512_maskz_extractf64x4_pd(0b00000001, a, 0x1); + let e = _mm256_setr_pd(5., 0., 0., 0.); + assert_eq_m256d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_extracti64x4_epi64() { + let a = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); + let r = _mm512_extracti64x4_epi64(a, 0x1); + let e = _mm256_setr_epi64x(5, 6, 7, 8); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_extracti64x4_epi64() { + let a = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); + let src = _mm256_set1_epi64x(100); + let r = _mm512_mask_extracti64x4_epi64(src, 0, a, 0x1); + assert_eq_m256i(r, src); + let r = _mm512_mask_extracti64x4_epi64(src, 0b11111111, a, 0x1); + let e = _mm256_setr_epi64x(5, 6, 7, 8); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_extracti64x4_epi64() { + let a = _mm512_setr_epi64(1, 2, 3, 4, 5, 6, 7, 8); + let r = _mm512_maskz_extracti64x4_epi64(0, a, 0x1); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_extracti64x4_epi64(0b00000001, a, 0x1); + let e = _mm256_setr_epi64x(5, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_compress_epi64() { + let src = _mm512_set1_epi64(200); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_compress_epi64(src, 0b01010101, a); + let e = _mm512_set_epi64(200, 200, 200, 200, 1, 3, 5, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_compress_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_compress_epi64(0b01010101, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 1, 3, 5, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_compress_pd() { + let src = _mm512_set1_pd(200.); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_compress_pd(src, 0b01010101, a); + let e = _mm512_set_pd(200., 200., 200., 200., 1., 3., 5., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_compress_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_compress_pd(0b01010101, a); + let e = _mm512_set_pd(0., 0., 0., 0., 1., 3., 5., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_expand_epi64() { + let src = _mm512_set1_epi64(200); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_expand_epi64(src, 0b01010101, a); + let e = _mm512_set_epi64(200, 4, 200, 5, 200, 6, 200, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_expand_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_expand_epi64(0b01010101, a); + let e = _mm512_set_epi64(0, 4, 0, 5, 0, 6, 0, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_expand_pd() { + let src = _mm512_set1_pd(200.); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_expand_pd(src, 0b01010101, a); + let e = _mm512_set_pd(200., 4., 200., 5., 200., 6., 200., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_expand_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_expand_pd(0b01010101, a); + let e = _mm512_set_pd(0., 4., 0., 5., 0., 6., 0., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_loadu_epi64() { + let a = &[4, 3, 2, 5, -8, -9, -64, -50]; + let p = a.as_ptr(); + let r = _mm512_loadu_epi64(black_box(p)); + let e = _mm512_setr_epi64(4, 3, 2, 5, -8, -9, -64, -50); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_storeu_epi64() { + let a = _mm512_set1_epi64(9); + let mut r = _mm512_set1_epi64(0); + _mm512_storeu_epi64(&mut r as *mut _ as *mut i64, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_load_epi64() { + #[repr(align(64))] + struct Align { + data: [i64; 8], // 64 bytes + } + let a = Align { + data: [4, 3, 2, 5, -8, -9, -64, -50], + }; + let p = (a.data).as_ptr(); + let r = _mm512_load_epi64(black_box(p)); + let e = _mm512_setr_epi64(4, 3, 2, 5, -8, -9, -64, -50); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_store_epi64() { + let a = _mm512_set1_epi64(9); + let mut r = _mm512_set1_epi64(0); + _mm512_store_epi64(&mut r as *mut _ as *mut i64, a); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_load_pd() { + #[repr(align(64))] + struct Align { + data: [f64; 8], // 64 bytes + } + let a = Align { + data: [4., 3., 2., 5., -8., -9., -64., -50.], + }; + let p = (a.data).as_ptr(); + let r = _mm512_load_pd(black_box(p)); + let e = _mm512_setr_pd(4., 3., 2., 5., -8., -9., -64., -50.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_store_pd() { + let a = _mm512_set1_pd(9.); + let mut r = _mm512_undefined_pd(); + _mm512_store_pd(&mut r as *mut _ as *mut f64, a); + assert_eq_m512d(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_test_epi64_mask() { + let a = _mm512_set1_epi64(1 << 0); + let b = _mm512_set1_epi64(1 << 0 | 1 << 1); + let r = _mm512_test_epi64_mask(a, b); + let e: __mmask8 = 0b11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_test_epi64_mask() { + let a = _mm512_set1_epi64(1 << 0); + let b = _mm512_set1_epi64(1 << 0 | 1 << 1); + let r = _mm512_mask_test_epi64_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_test_epi64_mask(0b11111111, a, b); + let e: __mmask8 = 0b11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_testn_epi64_mask() { + let a = _mm512_set1_epi64(1 << 0); + let b = _mm512_set1_epi64(1 << 0 | 1 << 1); + let r = _mm512_testn_epi64_mask(a, b); + let e: __mmask8 = 0b00000000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_testn_epi64_mask() { + let a = _mm512_set1_epi64(1 << 0); + let b = _mm512_set1_epi64(1 << 1); + let r = _mm512_mask_testn_epi64_mask(0, a, b); + assert_eq!(r, 0); + let r = _mm512_mask_testn_epi64_mask(0b11111111, a, b); + let e: __mmask8 = 0b11111111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_stream_pd() { + #[repr(align(64))] + struct Memory { + pub data: [f64; 8], + } + let a = _mm512_set1_pd(7.0); + let mut mem = Memory { data: [-1.0; 8] }; + + _mm512_stream_pd(&mut mem.data[0] as *mut f64, a); + for i in 0..8 { + assert_eq!(mem.data[i], get_m512d(a, i)); + } + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_stream_si512() { + #[repr(align(64))] + struct Memory { + pub data: [i64; 8], + } + let a = _mm512_set1_epi64(7); + let mut mem = Memory { data: [-1; 8] }; + + _mm512_stream_si512(&mut mem.data[0] as *mut i64, a); + for i in 0..8 { + assert_eq!(mem.data[i], get_m512i(a, i)); + } + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_set1_epi64() { + let src = _mm512_set1_epi64(2); + let a: i64 = 11; + let r = _mm512_mask_set1_epi64(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_set1_epi64(src, 0b11111111, a); + let e = _mm512_set1_epi64(11); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_set1_epi64() { + let a: i64 = 11; + let r = _mm512_maskz_set1_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_set1_epi64(0b11111111, a); + let e = _mm512_set1_epi64(11); + assert_eq_m512i(r, e); + } } diff --git a/library/stdarch/crates/core_arch/src/x86_64/fxsr.rs b/library/stdarch/crates/core_arch/src/x86_64/fxsr.rs index 0b26fb6d04..ef7e311cfc 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/fxsr.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/fxsr.rs @@ -6,9 +6,9 @@ use stdarch_test::assert_instr; #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.fxsave64"] - fn fxsave64(p: *mut u8) -> (); + fn fxsave64(p: *mut u8); #[link_name = "llvm.x86.fxrstor64"] - fn fxrstor64(p: *const u8) -> (); + fn fxrstor64(p: *const u8); } /// Saves the `x87` FPU, `MMX` technology, `XMM`, and `MXCSR` registers to the diff --git a/library/stdarch/crates/core_arch/src/x86_64/xsave.rs b/library/stdarch/crates/core_arch/src/x86_64/xsave.rs index 8296695058..215e5a541e 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/xsave.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/xsave.rs @@ -8,17 +8,17 @@ use stdarch_test::assert_instr; #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.xsave64"] - fn xsave64(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsave64(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xrstor64"] - fn xrstor64(p: *const u8, hi: u32, lo: u32) -> (); + fn xrstor64(p: *const u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xsaveopt64"] - fn xsaveopt64(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsaveopt64(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xsavec64"] - fn xsavec64(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsavec64(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xsaves64"] - fn xsaves64(p: *mut u8, hi: u32, lo: u32) -> (); + fn xsaves64(p: *mut u8, hi: u32, lo: u32); #[link_name = "llvm.x86.xrstors64"] - fn xrstors64(p: *const u8, hi: u32, lo: u32) -> (); + fn xrstors64(p: *const u8, hi: u32, lo: u32); } /// Performs a full or partial save of the enabled processor states to memory at diff --git a/library/stdarch/crates/core_arch/tests/cpu-detection.rs b/library/stdarch/crates/core_arch/tests/cpu-detection.rs index e17050d8ca..61f5f09053 100644 --- a/library/stdarch/crates/core_arch/tests/cpu-detection.rs +++ b/library/stdarch/crates/core_arch/tests/cpu-detection.rs @@ -1,5 +1,5 @@ #![feature(stdsimd)] -#![allow(clippy::option_unwrap_used, clippy::print_stdout, clippy::use_debug)] +#![allow(clippy::unwrap_used, clippy::print_stdout, clippy::use_debug)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[macro_use] diff --git a/library/stdarch/crates/std_detect/tests/cpu-detection.rs b/library/stdarch/crates/std_detect/tests/cpu-detection.rs index a95b1e7393..8f29ea45cd 100644 --- a/library/stdarch/crates/std_detect/tests/cpu-detection.rs +++ b/library/stdarch/crates/std_detect/tests/cpu-detection.rs @@ -1,5 +1,5 @@ #![feature(stdsimd)] -#![allow(clippy::option_unwrap_used, clippy::use_debug, clippy::print_stdout)] +#![allow(clippy::unwrap_used, clippy::use_debug, clippy::print_stdout)] #![cfg(any( target_arch = "arm", target_arch = "aarch64", diff --git a/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs b/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs index e950523d0e..cd597af73c 100644 --- a/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs +++ b/library/stdarch/crates/std_detect/tests/macro_trailing_commas.rs @@ -1,5 +1,5 @@ #![feature(stdsimd)] -#![allow(clippy::option_unwrap_used, clippy::use_debug, clippy::print_stdout)] +#![allow(clippy::unwrap_used, clippy::use_debug, clippy::print_stdout)] #[cfg(any( target_arch = "arm", diff --git a/library/stdarch/crates/stdarch-gen/neon.spec b/library/stdarch/crates/stdarch-gen/neon.spec index 0343a7232e..5c705c15db 100644 --- a/library/stdarch/crates/stdarch-gen/neon.spec +++ b/library/stdarch/crates/stdarch-gen/neon.spec @@ -1,6 +1,6 @@ // ARM Neon intrinsic specification. -// -// This file contains the specification for a number of +// +// This file contains the specification for a number of // intrinsics that allows us to generate them along with // their test cases. // @@ -31,7 +31,7 @@ // This is used to generate both aarch64 specific and // shared intrinics by first only specifying th aarch64 // variant then the arm variant. -// +// // arm - The arm v7 intrinics used to checked for arm code // generation. All neon functions available in arm are // also available in aarch64. If no aarch64 intrinic was @@ -60,7 +60,7 @@ // The special values 'TRUE' and 'FALSE' can be used to // represent the corect NEON representation of true or // false values. It too gets scaled to the type. -// +// // Validate needs to be called before generate as it sets // up the rules for validation that get generated for each // type. @@ -168,7 +168,7 @@ generate uint*_t /// Floating-point compare greater than name = vcgt fn = simd_gt -a = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 +a = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 b = 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8 validate TRUE, TRUE, TRUE, TRUE, TRUE, TRUE @@ -212,7 +212,7 @@ generate uint*_t name = vclt fn = simd_lt a = 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8 -b = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 +b = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 validate TRUE, TRUE, TRUE, TRUE, TRUE, TRUE aarch64 = fcmgt @@ -256,7 +256,7 @@ generate uint*_t name = vcle fn = simd_le a = 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8 -b = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 +b = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 validate TRUE, TRUE, TRUE, TRUE, TRUE, TRUE aarch64 = fcmge generate float64x1_t:uint64x1_t, float64x2_t:uint64x2_t @@ -298,7 +298,7 @@ generate uint*_t /// Floating-point compare greater than or equal name = vcge fn = simd_ge -a = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 +a = 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9 b = 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8 validate TRUE, TRUE, TRUE, TRUE, TRUE, TRUE @@ -383,25 +383,6 @@ link-arm = vqadds._EXT_ link-aarch64 = sqadd._EXT_ generate int*_t -// requires 1st and second argument to be different, this not implemented yet -// /// Signed saturating accumulate of unsigned value -// -// name = vuqadd -// a = 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 -// b = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 -// e = 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 - -// it seems like we don't have those in rustland :( -// aarch64 = suqadd -// link-aarch64 = usqadd._EXT_ -// generate int64x*_t - -/ arm = suqadd -// link-arm = vuqadds._EXT_ -// link-aarch64 = suqadd._EXT_ -// generate int*_t - - /// Multiply name = vmul a = 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 @@ -467,3 +448,71 @@ aarch64 = shsub link-arm = vhsubs._EXT_ link-aarch64 = shsub._EXT_ generate int*_t + +/// Maximum (vector) +name = vmax +a = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 +b = 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 +validate 16, 15, 14, 13, 12, 11, 10, 9, 9, 10, 11, 12, 13, 14, 15, 16 + +arm = vmax +aarch64 = smax +link-arm = vmaxs._EXT_ +link-aarch64 = smax._EXT_ +generate int*_t + +arm = vmax +aarch64 = umax +link-arm = vmaxu._EXT_ +link-aarch64 = umax._EXT_ +generate uint*_t + +/// Maximum (vector) +name = vmax +a = 1.0, -2.0, 3.0, -4.0 +b = 0.0, 3.0, 2.0, 8.0 +validate 1.0, 3.0, 3.0, 8.0 + +aarch64 = fmax +link-aarch64 = fmax._EXT_ +generate float64x*_t + +arm = vmax +aarch64 = fmax +link-arm = vmaxs._EXT_ +link-aarch64 = fmax._EXT_ +generate float*_t + +/// Minimum (vector) +name = vmin +a = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 +b = 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 +validate 1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1 + +arm = vmin +aarch64 = smin +link-arm = vmins._EXT_ +link-aarch64 = smin._EXT_ +generate int*_t + +arm = vmin +aarch64 = umin +link-arm = vminu._EXT_ +link-aarch64 = umin._EXT_ +generate uint*_t + +/// Minimum (vector) +name = vmin +a = 1.0, -2.0, 3.0, -4.0 +b = 0.0, 3.0, 2.0, 8.0 +validate 0.0, -2.0, 2.0, -4.0 + +aarch64 = fmin +link-aarch64 = fmin._EXT_ +generate float64x*_t + +arm = vmin +aarch64 = fmin +link-arm = vmins._EXT_ +link-aarch64 = fmin._EXT_ +generate float*_t diff --git a/library/stdarch/crates/stdarch-gen/src/main.rs b/library/stdarch/crates/stdarch-gen/src/main.rs index 8a9d9f25c0..6e341c00dd 100644 --- a/library/stdarch/crates/stdarch-gen/src/main.rs +++ b/library/stdarch/crates/stdarch-gen/src/main.rs @@ -318,13 +318,12 @@ fn gen_aarch64( let ext = type_to_ext(in_t); format!( - r#" - #[allow(improper_ctypes)] + r#"#[allow(improper_ctypes)] extern "C" {{ #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.{}")] fn {}(a: {}, a: {}) -> {}; }} -"#, + "#, link_aarch64.replace("_EXT_", ext), current_fn, in_t, @@ -476,7 +475,7 @@ pub unsafe fn {}(a: {}, b: {}) -> {} {{ } fn expand_intrinsic(intr: &str, t: &str) -> String { - if intr.ends_with(".") { + if intr.ends_with('.') { let ext = match t { "int8x8_t" => "i8", "int8x16_t" => "i8", diff --git a/library/stdarch/crates/stdarch-test/src/disassembly.rs b/library/stdarch/crates/stdarch-test/src/disassembly.rs index d82b07d0a8..38ebce75f7 100644 --- a/library/stdarch/crates/stdarch-test/src/disassembly.rs +++ b/library/stdarch/crates/stdarch-test/src/disassembly.rs @@ -32,62 +32,72 @@ fn normalize(mut symbol: &str) -> String { while symbol.starts_with('_') { symbol.remove(0); } + // Windows/x86 has a suffix such as @@4. + if let Some(idx) = symbol.find("@@") { + symbol = (&symbol[..idx]).to_string(); + } symbol } pub(crate) fn disassemble_myself() -> HashSet { let me = env::current_exe().expect("failed to get current exe"); - let disassembly = - if cfg!(target_arch = "x86_64") && cfg!(target_os = "windows") && cfg!(target_env = "msvc") - { - let mut cmd = cc::windows_registry::find("x86_64-pc-windows-msvc", "dumpbin.exe") - .expect("failed to find `dumpbin` tool"); - let output = cmd - .arg("/DISASM") - .arg(&me) - .output() - .expect("failed to execute dumpbin"); - println!( - "{}\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) - ); - assert!(output.status.success()); - // Windows does not return valid UTF-8 output: - String::from_utf8_lossy(Vec::leak(output.stdout)) - } else if cfg!(target_os = "windows") { - panic!("disassembly unimplemented") - } else if cfg!(target_os = "macos") { - let output = Command::new("otool") - .arg("-vt") - .arg(&me) - .output() - .expect("failed to execute otool"); - println!( - "{}\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) - ); - assert!(output.status.success()); - - String::from_utf8_lossy(Vec::leak(output.stdout)) + let disassembly = if cfg!(target_os = "windows") && cfg!(target_env = "msvc") { + let target = if cfg!(target_arch = "x86_64") { + "x86_64-pc-windows-msvc" + } else if cfg!(target_arch = "x86") { + "i686-pc-windows-msvc" } else { - let objdump = env::var("OBJDUMP").unwrap_or_else(|_| "objdump".to_string()); - let output = Command::new(objdump.clone()) - .arg("--disassemble") - .arg(&me) - .output() - .unwrap_or_else(|_| panic!("failed to execute objdump. OBJDUMP={}", objdump)); - println!( - "{}\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) - ); - assert!(output.status.success()); - - String::from_utf8_lossy(Vec::leak(output.stdout)) + panic!("disassembly unimplemented") }; + let mut cmd = cc::windows_registry::find(target, "dumpbin.exe") + .expect("failed to find `dumpbin` tool"); + let output = cmd + .arg("/DISASM") + .arg(&me) + .output() + .expect("failed to execute dumpbin"); + println!( + "{}\n{}", + output.status, + String::from_utf8_lossy(&output.stderr) + ); + assert!(output.status.success()); + // Windows does not return valid UTF-8 output: + String::from_utf8_lossy(Vec::leak(output.stdout)) + } else if cfg!(target_os = "windows") { + panic!("disassembly unimplemented") + } else if cfg!(target_os = "macos") { + let output = Command::new("otool") + .arg("-vt") + .arg(&me) + .output() + .expect("failed to execute otool"); + println!( + "{}\n{}", + output.status, + String::from_utf8_lossy(&output.stderr) + ); + assert!(output.status.success()); + + String::from_utf8_lossy(Vec::leak(output.stdout)) + } else { + let objdump = env::var("OBJDUMP").unwrap_or_else(|_| "objdump".to_string()); + let output = Command::new(objdump.clone()) + .arg("--disassemble") + .arg("--no-show-raw-insn") + .arg(&me) + .output() + .unwrap_or_else(|_| panic!("failed to execute objdump. OBJDUMP={}", objdump)); + println!( + "{}\n{}", + output.status, + String::from_utf8_lossy(&output.stderr) + ); + assert!(output.status.success()); + + String::from_utf8_lossy(Vec::leak(output.stdout)) + }; parse(&disassembly) } @@ -147,20 +157,13 @@ fn parse(output: &str) -> HashSet { .skip_while(|s| *s == "lock") // skip x86-specific prefix .collect::>() } else { - // objdump + // objdump with --no-show-raw-insn // Each line of instructions should look like: // - // $rel_offset: ab cd ef 00 $instruction... - let expected_len = if cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64") { - 8 - } else { - 2 - }; - + // $rel_offset: $instruction... instruction .split_whitespace() .skip(1) - .skip_while(|s| s.len() == expected_len && usize::from_str_radix(s, 16).is_ok()) .skip_while(|s| *s == "lock") // skip x86-specific prefix .map(std::string::ToString::to_string) .collect::>() diff --git a/library/stdarch/crates/stdarch-test/src/lib.rs b/library/stdarch/crates/stdarch-test/src/lib.rs index 03711e911e..88409f5dd4 100644 --- a/library/stdarch/crates/stdarch-test/src/lib.rs +++ b/library/stdarch/crates/stdarch-test/src/lib.rs @@ -3,6 +3,7 @@ //! This basically just disassembles the current executable and then parses the //! output once globally and then provides the `assert` function which makes //! assertions about the disassembly of a function. +#![feature(test)] // For black_box #![allow(clippy::missing_docs_in_private_items, clippy::print_stdout)] extern crate assert_instr_macro; @@ -16,7 +17,7 @@ extern crate cfg_if; pub use assert_instr_macro::*; pub use simd_test_macro::*; -use std::{cmp, collections::HashSet, env, hash, str, sync::atomic::AtomicPtr}; +use std::{cmp, collections::HashSet, env, hash, hint::black_box, str, sync::atomic::AtomicPtr}; cfg_if! { if #[cfg(target_arch = "wasm32")] { @@ -63,7 +64,10 @@ impl hash::Hash for Function { /// /// This asserts that the function at `fnptr` contains the instruction /// `expected` provided. -pub fn assert(_fnptr: usize, fnname: &str, expected: &str) { +pub fn assert(shim_addr: usize, fnname: &str, expected: &str) { + // Make sure that the shim is not removed + black_box(shim_addr); + //eprintln!("shim name: {}", fnname); let function = &DISASSEMBLY .get(&Function::new(fnname)) diff --git a/library/stdarch/crates/stdarch-verify/src/lib.rs b/library/stdarch/crates/stdarch-verify/src/lib.rs index 6d9dfe6229..acf22d19da 100644 --- a/library/stdarch/crates/stdarch-verify/src/lib.rs +++ b/library/stdarch/crates/stdarch-verify/src/lib.rs @@ -147,6 +147,8 @@ fn to_type(t: &syn::Type) -> proc_macro2::TokenStream { "__m512i" => quote! { &M512I }, "__mmask8" => quote! { &MMASK8 }, "__mmask16" => quote! { &MMASK16 }, + "__mmask32" => quote! { &MMASK32 }, + "__mmask64" => quote! { &MMASK64 }, "_MM_CMPINT_ENUM" => quote! { &MM_CMPINT_ENUM }, "_MM_MANTISSA_NORM_ENUM" => quote! { &MM_MANTISSA_NORM_ENUM }, "_MM_MANTISSA_SIGN_ENUM" => quote! { &MM_MANTISSA_SIGN_ENUM }, @@ -164,6 +166,8 @@ fn to_type(t: &syn::Type) -> proc_macro2::TokenStream { "u64" => quote! { &U64 }, "u128" => quote! { &U128 }, "u8" => quote! { &U8 }, + "p8" => quote! { &P8 }, + "p16" => quote! { &P16 }, "Ordering" => quote! { &ORDERING }, "CpuidResult" => quote! { &CPUID }, @@ -209,13 +213,13 @@ fn to_type(t: &syn::Type) -> proc_macro2::TokenStream { "poly8x16x2_t" => quote! { &POLY8X16X2 }, "poly8x16x3_t" => quote! { &POLY8X16X3 }, "poly8x16x4_t" => quote! { &POLY8X16X4 }, - "poly64_t" => quote! { &P64 }, + "p64" => quote! { &P64 }, "poly64x1_t" => quote! { &POLY64X1 }, "poly64x2_t" => quote! { &POLY64X2 }, "poly8x16_t" => quote! { &POLY8X16 }, "poly16x4_t" => quote! { &POLY16X4 }, "poly16x8_t" => quote! { &POLY16X8 }, - "poly128_t" => quote! { &P128 }, + "p128" => quote! { &P128 }, "v16i8" => quote! { &v16i8 }, "v8i16" => quote! { &v8i16 }, @@ -336,7 +340,7 @@ fn find_instrs(attrs: &[syn::Attribute]) -> Vec { } else if let Ok(ident) = instrs.call(syn::Ident::parse_any) { instr.push_str(&ident.to_string()); } else if instrs.parse::().is_ok() { - instr.push_str("."); + instr.push('.'); } else if instrs.parse::().is_ok() { // consume everything remaining drop(instrs.parse::()); diff --git a/library/stdarch/crates/stdarch-verify/tests/arm.rs b/library/stdarch/crates/stdarch-verify/tests/arm.rs index 26239a43aa..597645489c 100644 --- a/library/stdarch/crates/stdarch-verify/tests/arm.rs +++ b/library/stdarch/crates/stdarch-verify/tests/arm.rs @@ -331,6 +331,46 @@ fn verify_all_signatures() { "_cls_u32", "_cls_u64", "_prefetch", + "vsli_n_s8", + "vsliq_n_s8", + "vsli_n_s16", + "vsliq_n_s16", + "vsli_n_s32", + "vsliq_n_s32", + "vsli_n_s64", + "vsliq_n_s64", + "vsli_n_u8", + "vsliq_n_u8", + "vsli_n_u16", + "vsliq_n_u16", + "vsli_n_u32", + "vsliq_n_u32", + "vsli_n_u64", + "vsliq_n_u64", + "vsli_n_p8", + "vsliq_n_p8", + "vsli_n_p16", + "vsliq_n_p16", + "vsri_n_s8", + "vsriq_n_s8", + "vsri_n_s16", + "vsriq_n_s16", + "vsri_n_s32", + "vsriq_n_s32", + "vsri_n_s64", + "vsriq_n_s64", + "vsri_n_u8", + "vsriq_n_u8", + "vsri_n_u16", + "vsriq_n_u16", + "vsri_n_u32", + "vsriq_n_u32", + "vsri_n_u64", + "vsriq_n_u64", + "vsri_n_p8", + "vsriq_n_p8", + "vsri_n_p16", + "vsriq_n_p16", ]; if !skip.contains(&rust.name) { println!( @@ -428,7 +468,7 @@ fn matches(rust: &Function, arm: &Intrinsic) -> Result<(), String> { } // sometimes arm says `foo` and disassemblers say `vfoo`, or // sometimes disassemblers say `vfoo` and arm says `sfoo` or `ffoo` - if instr.starts_with("v") + if instr.starts_with('v') && (arm.instruction.starts_with(&instr[1..]) || arm.instruction[1..].starts_with(&instr[1..])) { @@ -451,10 +491,10 @@ fn matches(rust: &Function, arm: &Intrinsic) -> Result<(), String> { fn find_accordion(node: &Rc) -> Option> { if let NodeData::Element { attrs, .. } = &node.data { for attr in attrs.borrow().iter() { - if attr.name.local.eq_str_ignore_ascii_case("class") { - if attr.value.to_string() == "intrinsic-accordion" { - return Some(node.clone()); - } + if attr.name.local.eq_str_ignore_ascii_case("class") + && attr.value.to_string() == "intrinsic-accordion" + { + return Some(node.clone()); } } } @@ -482,7 +522,7 @@ fn parse_intrinsics(node: &Rc) -> HashMap { ret.insert(f.name.clone(), f); } } - return ret; + ret } fn parse_intrinsic(node: &Rc) -> Intrinsic { @@ -495,10 +535,9 @@ fn parse_intrinsic(node: &Rc) -> Intrinsic { // ... let children = node.children.borrow(); - let mut children = children.iter().filter(|node| match node.data { - NodeData::Element { .. } => true, - _ => false, - }); + let mut children = children + .iter() + .filter(|node| matches!(node.data, NodeData::Element { .. })); let _input = children.next().expect("no "); let label = children.next().expect("no
"); @@ -518,10 +557,9 @@ fn parse_intrinsic(node: &Rc) -> Intrinsic { // Find contents of inner `
` in `
in (); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 7a451903e9..4be625ba90 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -2,7 +2,12 @@ error[E0282]: type annotations needed --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` + | ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo` + | +help: consider specifying the const argument + | +LL | Foo.foo::(); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.rs b/src/test/ui/const-generics/infer/uninferred-consts.rs index ec5b3ffe54..00fb6eac99 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.rs +++ b/src/test/ui/const-generics/infer/uninferred-consts.rs @@ -8,7 +8,7 @@ // taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893 struct Foo; impl Foo { - fn foo(self) {} + fn foo(self) {} } fn main() { Foo.foo(); diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr index 20a8d9fdaa..02467df193 100644 --- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr +++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr @@ -5,6 +5,7 @@ LL | T: Trait<{std::intrinsics::type_name::()}> | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22 @@ -13,7 +14,7 @@ LL | trait Trait {} | ^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/invalid-constant-in-args.rs b/src/test/ui/const-generics/invalid-constant-in-args.rs index 40df237ee7..0bd9cbf4f4 100644 --- a/src/test/ui/const-generics/invalid-constant-in-args.rs +++ b/src/test/ui/const-generics/invalid-constant-in-args.rs @@ -1,3 +1,6 @@ +use std::cell::Cell; + fn main() { - let _: Vec<&str, "a"> = Vec::new(); //~ ERROR wrong number of const arguments + let _: Cell<&str, "a"> = Cell::new(""); + //~^ ERROR wrong number of generic arguments } diff --git a/src/test/ui/const-generics/invalid-constant-in-args.stderr b/src/test/ui/const-generics/invalid-constant-in-args.stderr index b9f874ff18..9b8a5d1ae4 100644 --- a/src/test/ui/const-generics/invalid-constant-in-args.stderr +++ b/src/test/ui/const-generics/invalid-constant-in-args.stderr @@ -1,8 +1,8 @@ -error[E0107]: wrong number of const arguments: expected 0, found 1 - --> $DIR/invalid-constant-in-args.rs:2:22 +error[E0107]: wrong number of generic arguments: expected 1, found 2 + --> $DIR/invalid-constant-in-args.rs:4:23 | -LL | let _: Vec<&str, "a"> = Vec::new(); - | ^^^ unexpected const argument +LL | let _: Cell<&str, "a"> = Cell::new(""); + | ^^^ unexpected const argument error: aborting due to previous error diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs index ceb188a0d3..4ca10ed8b7 100644 --- a/src/test/ui/const-generics/invalid-enum.rs +++ b/src/test/ui/const-generics/invalid-enum.rs @@ -20,20 +20,16 @@ impl Example { pub fn main() { test_1::(); //~^ ERROR: expected type, found variant - //~| ERROR: wrong number of const arguments - //~| ERROR: wrong number of type arguments + //~| ERROR: type provided when a constant was expected test_2::<_, CompileFlag::A>(0); //~^ ERROR: expected type, found variant - //~| ERROR: wrong number of const arguments - //~| ERROR: wrong number of type arguments + //~| ERROR: type provided when a constant was expected let _: Example = Example { x: 0 }; //~^ ERROR: expected type, found variant - //~| ERROR: wrong number of const arguments - //~| ERROR: wrong number of type arguments + //~| ERROR: type provided when a constant was expected let _: Example = Example { x: 0 }; - //~^ ERROR: wrong number of const arguments - //~| ERROR: wrong number of type arguments + //~^ ERROR: type provided when a constant was expected } diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr index 965abbc9cb..7822fc072e 100644 --- a/src/test/ui/const-generics/invalid-enum.stderr +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -8,7 +8,7 @@ LL | test_1::(); | help: try using the variant's enum: `CompileFlag` error[E0573]: expected type, found variant `CompileFlag::A` - --> $DIR/invalid-enum.rs:26:15 + --> $DIR/invalid-enum.rs:25:15 | LL | test_2::<_, CompileFlag::A>(0); | ^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | test_2::<_, CompileFlag::A>(0); | help: try using the variant's enum: `CompileFlag` error[E0573]: expected type, found variant `CompileFlag::A` - --> $DIR/invalid-enum.rs:31:18 + --> $DIR/invalid-enum.rs:29:18 | LL | let _: Example = Example { x: 0 }; | ^^^^^^^^^^^^^^ @@ -25,75 +25,51 @@ LL | let _: Example = Example { x: 0 }; | not a type | help: try using the variant's enum: `CompileFlag` -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/invalid-enum.rs:31:10 +error[E0747]: type provided when a constant was expected + --> $DIR/invalid-enum.rs:29:18 | LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument - -error[E0107]: wrong number of type arguments: expected at most 1, found 2 - --> $DIR/invalid-enum.rs:31:10 - | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | ^^^^^^^^^^^^^^ | -help: If this generic argument was intended as a const parameter, try surrounding it with braces: +help: if this generic argument was intended as a const parameter, try surrounding it with braces: | LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; | ^ ^ -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/invalid-enum.rs:36:10 +error[E0747]: type provided when a constant was expected + --> $DIR/invalid-enum.rs:33:18 | LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument - -error[E0107]: wrong number of type arguments: expected at most 1, found 2 - --> $DIR/invalid-enum.rs:36:10 - | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | ^^^^^^^^^^^^^^^^^^^ | -help: If this generic argument was intended as a const parameter, try surrounding it with braces: +help: if this generic argument was intended as a const parameter, try surrounding it with braces: | LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; | ^ ^ -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/invalid-enum.rs:21:3 - | -LL | test_1::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument - -error[E0107]: wrong number of type arguments: expected 0, found 1 +error[E0747]: type provided when a constant was expected --> $DIR/invalid-enum.rs:21:12 | LL | test_1::(); - | ^^^^^^^^^^^^^^ unexpected type argument + | ^^^^^^^^^^^^^^ | -help: If this generic argument was intended as a const parameter, try surrounding it with braces: +help: if this generic argument was intended as a const parameter, try surrounding it with braces: | LL | test_1::<{ CompileFlag::A }>(); | ^ ^ -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/invalid-enum.rs:26:3 +error[E0747]: type provided when a constant was expected + --> $DIR/invalid-enum.rs:25:15 | LL | test_2::<_, CompileFlag::A>(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument - -error[E0107]: wrong number of type arguments: expected 1, found 2 - --> $DIR/invalid-enum.rs:26:15 - | -LL | test_2::<_, CompileFlag::A>(0); - | ^^^^^^^^^^^^^^ unexpected type argument + | ^^^^^^^^^^^^^^ | -help: If this generic argument was intended as a const parameter, try surrounding it with braces: +help: if this generic argument was intended as a const parameter, try surrounding it with braces: | LL | test_2::<_, { CompileFlag::A }>(0); | ^ ^ -error: aborting due to 11 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0107, E0573. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0573, E0747. +For more information about an error, try `rustc --explain E0573`. diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr index 526807f0a2..2eaef95c23 100644 --- a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr +++ b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr @@ -5,6 +5,7 @@ LL | pub struct MyArray([u8; COUNT + 1]); | ^^^^^ cannot perform const operation using `COUNT` | = help: const parameters may only be used as standalone arguments, i.e. `COUNT` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-61522-array-len-succ.rs:12:30 @@ -13,6 +14,7 @@ LL | fn inner(&self) -> &[u8; COUNT + 1] { | ^^^^^ cannot perform const operation using `COUNT` | = help: const parameters may only be used as standalone arguments, i.e. `COUNT` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr index 786ded3c2f..1c2e7e069a 100644 --- a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr +++ b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr @@ -5,7 +5,7 @@ LL | trait Trait { | ^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issue-67375.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr index 3c344edbf1..da96b5374a 100644 --- a/src/test/ui/const-generics/issue-67375.min.stderr +++ b/src/test/ui/const-generics/issue-67375.min.stderr @@ -5,6 +5,7 @@ LL | inner: [(); { [|_: &T| {}; 0].len() }], | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error[E0392]: parameter `T` is never used --> $DIR/issue-67375.rs:7:12 diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr index 804236c30b..8fea130baa 100644 --- a/src/test/ui/const-generics/issue-67945-1.min.stderr +++ b/src/test/ui/const-generics/issue-67945-1.min.stderr @@ -5,6 +5,7 @@ LL | let x: S = MaybeUninit::uninit(); | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-67945-1.rs:17:45 @@ -13,6 +14,7 @@ LL | let b = &*(&x as *const _ as *const S); | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-1.rs:11:12 diff --git a/src/test/ui/const-generics/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr index 2de942c122..50633772b7 100644 --- a/src/test/ui/const-generics/issue-67945-2.min.stderr +++ b/src/test/ui/const-generics/issue-67945-2.min.stderr @@ -5,6 +5,7 @@ LL | let x: S = MaybeUninit::uninit(); | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-67945-2.rs:15:45 @@ -13,6 +14,7 @@ LL | let b = &*(&x as *const _ as *const S); | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-2.rs:9:12 diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr index b176f9d1c7..1de9e71b6e 100644 --- a/src/test/ui/const-generics/issues/issue-61747.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.min.stderr @@ -5,6 +5,7 @@ LL | fn successor() -> Const<{C + 1}> { | ^ cannot perform const operation using `C` | = help: const parameters may only be used as standalone arguments, i.e. `C` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr index 9e31466259..b1d92056a5 100644 --- a/src/test/ui/const-generics/issues/issue-61935.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr @@ -5,6 +5,7 @@ LL | Self:FooImpl<{N==0}> | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr index 3bd127ee74..b338cdb87e 100644 --- a/src/test/ui/const-generics/issues/issue-62220.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr @@ -5,6 +5,7 @@ LL | pub type TruncatedVector = Vector; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr index c73f62a4a0..a4b501a7bb 100644 --- a/src/test/ui/const-generics/issues/issue-62456.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr @@ -5,6 +5,7 @@ LL | let _ = [0u64; N + 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr index 6903b20fad..5117e20d62 100644 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr @@ -5,7 +5,7 @@ LL | fn foo() -> bool { | ^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62878.full.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr index c8b9db8941..dce2e27c71 100644 --- a/src/test/ui/const-generics/issues/issue-62878.full.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -4,17 +4,13 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn foo() {} | ^ the type must not depend on the parameter `N` -error[E0107]: wrong number of const arguments: expected 2, found 1 - --> $DIR/issue-62878.rs:11:5 - | -LL | foo::<_, {[1]}>(); - | ^^^^^^^^^^^^^^^ expected 2 const arguments - -error[E0107]: wrong number of type arguments: expected 0, found 1 +error[E0747]: type provided when a constant was expected --> $DIR/issue-62878.rs:11:11 | LL | foo::<_, {[1]}>(); - | ^ unexpected type argument + | ^ + | + = help: const arguments cannot yet be inferred with `_` error[E0308]: mismatched types --> $DIR/issue-62878.rs:11:15 @@ -22,7 +18,7 @@ error[E0308]: mismatched types LL | foo::<_, {[1]}>(); | ^^^ expected `usize`, found array `[{integer}; 1]` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0308, E0770. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0308, E0747, E0770. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-62878.min.stderr b/src/test/ui/const-generics/issues/issue-62878.min.stderr index 34edd09b51..9f95e5d886 100644 --- a/src/test/ui/const-generics/issues/issue-62878.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.min.stderr @@ -11,7 +11,7 @@ LL | fn foo() {} | ^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs index 0487dda2fe..c087711e5f 100644 --- a/src/test/ui/const-generics/issues/issue-62878.rs +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -9,7 +9,6 @@ fn foo() {} fn main() { foo::<_, {[1]}>(); - //[full]~^ ERROR wrong number of const arguments - //[full]~| ERROR wrong number of type arguments + //[full]~^ ERROR type provided when a constant was expected //[full]~| ERROR mismatched types } diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr index e6d9fb7a24..5dbfdc6d65 100644 --- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr @@ -5,7 +5,7 @@ LL | fn test() { | ^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter --> $DIR/issue-63322-forbid-dyn.rs:10:18 diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr index 8b02fd108b..681166b1d2 100644 --- a/src/test/ui/const-generics/issues/issue-64494.min.stderr +++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr @@ -5,6 +5,7 @@ LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} | ^^^^^^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-64494.rs:19:38 @@ -13,6 +14,7 @@ LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} | ^^^^^^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error[E0119]: conflicting implementations of trait `MyTrait`: --> $DIR/issue-64494.rs:19:1 diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr index 282f72be6d..ecd96ac37e 100644 --- a/src/test/ui/const-generics/issues/issue-66205.min.stderr +++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr @@ -5,6 +5,7 @@ LL | fact::<{ N - 1 }>(); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr index b900a0d096..acaf4a33ee 100644 --- a/src/test/ui/const-generics/issues/issue-68366.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr @@ -5,6 +5,7 @@ LL | impl Collatz<{Some(N)}> {} | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-68366.rs:12:13 diff --git a/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr index 81c8f4392c..59653114a6 100644 --- a/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr @@ -5,7 +5,7 @@ LL | struct Const {} | ^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-68615-array.min.stderr b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr index 8f55a92fce..1ee881b96e 100644 --- a/src/test/ui/const-generics/issues/issue-68615-array.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr @@ -5,7 +5,7 @@ LL | struct Foo {} | ^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr index 7828d85939..ea91df1e0b 100644 --- a/src/test/ui/const-generics/issues/issue-68977.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr @@ -5,6 +5,7 @@ LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; | ^^^^^^^^ cannot perform const operation using `INT_BITS` | = help: const parameters may only be used as standalone arguments, i.e. `INT_BITS` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-68977.rs:29:28 @@ -13,6 +14,7 @@ LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; | ^^^^^^^^^ cannot perform const operation using `FRAC_BITS` | = help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-71169.min.stderr b/src/test/ui/const-generics/issues/issue-71169.min.stderr index 79d6344335..9b0a2946ca 100644 --- a/src/test/ui/const-generics/issues/issue-71169.min.stderr +++ b/src/test/ui/const-generics/issues/issue-71169.min.stderr @@ -11,7 +11,7 @@ LL | fn foo() {} | ^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr index d960d9513b..27bbc28011 100644 --- a/src/test/ui/const-generics/issues/issue-72787.min.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -5,6 +5,7 @@ LL | Condition<{ LHS <= RHS }>: True | ^^^ cannot perform const operation using `LHS` | = help: const parameters may only be used as standalone arguments, i.e. `LHS` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:11:24 @@ -13,6 +14,7 @@ LL | Condition<{ LHS <= RHS }>: True | ^^^ cannot perform const operation using `RHS` | = help: const parameters may only be used as standalone arguments, i.e. `RHS` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:26:25 @@ -21,6 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments, i.e. `I` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:26:36 @@ -29,6 +32,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `J` | = help: const parameters may only be used as standalone arguments, i.e. `J` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error[E0283]: type annotations needed --> $DIR/issue-72787.rs:22:26 diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr index e4105a3df1..b499400472 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr @@ -1,8 +1,8 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72819-generic-in-const-eval.rs:9:47 + --> $DIR/issue-72819-generic-in-const-eval.rs:9:39 | -LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, - | ^^^^^^ +LL | where Assert::<{N < usize::MAX / 2}>: IsTrue, + | ^^^^^^ | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr index 9fec3eb946..8df3c85ec1 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr @@ -1,10 +1,11 @@ error: generic parameters may not be used in const operations --> $DIR/issue-72819-generic-in-const-eval.rs:9:17 | -LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, +LL | where Assert::<{N < usize::MAX / 2}>: IsTrue, | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs index 6182042bde..4c0004795f 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -6,7 +6,7 @@ #![cfg_attr(min, feature(min_const_generics))] struct Arr -where Assert::<{N < usize::max_value() / 2}>: IsTrue, +where Assert::<{N < usize::MAX / 2}>: IsTrue, //[full]~^ ERROR constant expression depends on a generic parameter //[min]~^^ ERROR generic parameters may not be used in const operations { @@ -19,5 +19,5 @@ trait IsTrue {} impl IsTrue for Assert {} fn main() { - let x: Arr<{usize::max_value()}> = Arr {}; + let x: Arr<{usize::MAX}> = Arr {}; } diff --git a/src/test/ui/const-generics/issues/issue-73260.rs b/src/test/ui/const-generics/issues/issue-73260.rs index 351d6849af..04e4e9cd52 100644 --- a/src/test/ui/const-generics/issues/issue-73260.rs +++ b/src/test/ui/const-generics/issues/issue-73260.rs @@ -3,7 +3,7 @@ #![feature(const_generics)] #![allow(incomplete_features)] struct Arr -where Assert::<{N < usize::max_value() / 2}>: IsTrue, //~ ERROR constant expression +where Assert::<{N < usize::MAX / 2}>: IsTrue, //~ ERROR constant expression { } @@ -14,7 +14,7 @@ trait IsTrue {} impl IsTrue for Assert {} fn main() { - let x: Arr<{usize::max_value()}> = Arr {}; + let x: Arr<{usize::MAX}> = Arr {}; //~^ ERROR mismatched types //~| ERROR mismatched types } diff --git a/src/test/ui/const-generics/issues/issue-73260.stderr b/src/test/ui/const-generics/issues/issue-73260.stderr index e22612ed5e..6a912ffc3c 100644 --- a/src/test/ui/const-generics/issues/issue-73260.stderr +++ b/src/test/ui/const-generics/issues/issue-73260.stderr @@ -1,25 +1,25 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-73260.rs:6:47 + --> $DIR/issue-73260.rs:6:39 | -LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, - | ^^^^^^ +LL | where Assert::<{N < usize::MAX / 2}>: IsTrue, + | ^^^^^^ | = note: this may fail depending on what value the parameter takes error[E0308]: mismatched types --> $DIR/issue-73260.rs:17:12 | -LL | let x: Arr<{usize::max_value()}> = Arr {}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` +LL | let x: Arr<{usize::MAX}> = Arr {}; + | ^^^^^^^^^^^^^^^^^ expected `false`, found `true` | = note: expected type `false` found type `true` error[E0308]: mismatched types - --> $DIR/issue-73260.rs:17:40 + --> $DIR/issue-73260.rs:17:32 | -LL | let x: Arr<{usize::max_value()}> = Arr {}; - | ^^^ expected `false`, found `true` +LL | let x: Arr<{usize::MAX}> = Arr {}; + | ^^^ expected `false`, found `true` | = note: expected type `false` found type `true` diff --git a/src/test/ui/const-generics/issues/issue-73491.min.stderr b/src/test/ui/const-generics/issues/issue-73491.min.stderr index 5bf3671d38..3ff0563acc 100644 --- a/src/test/ui/const-generics/issues/issue-73491.min.stderr +++ b/src/test/ui/const-generics/issues/issue-73491.min.stderr @@ -5,7 +5,7 @@ LL | fn hoge() {} | ^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-74101.min.stderr b/src/test/ui/const-generics/issues/issue-74101.min.stderr index 8062faefbe..1351246667 100644 --- a/src/test/ui/const-generics/issues/issue-74101.min.stderr +++ b/src/test/ui/const-generics/issues/issue-74101.min.stderr @@ -5,7 +5,7 @@ LL | fn test() {} | ^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `[u8; _]` is forbidden as the type of a const generic parameter --> $DIR/issue-74101.rs:10:21 @@ -14,7 +14,7 @@ LL | struct Foo; | ^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-74255.min.stderr b/src/test/ui/const-generics/issues/issue-74255.min.stderr index 86937d715c..e3e8502ae6 100644 --- a/src/test/ui/const-generics/issues/issue-74255.min.stderr +++ b/src/test/ui/const-generics/issues/issue-74255.min.stderr @@ -5,7 +5,7 @@ LL | fn ice_struct_fn() {} | ^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-74950.min.stderr b/src/test/ui/const-generics/issues/issue-74950.min.stderr index f093e6651b..12947a2ab3 100644 --- a/src/test/ui/const-generics/issues/issue-74950.min.stderr +++ b/src/test/ui/const-generics/issues/issue-74950.min.stderr @@ -5,7 +5,7 @@ LL | struct Outer; | ^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 @@ -14,7 +14,7 @@ LL | struct Outer; | ^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 @@ -23,7 +23,7 @@ LL | struct Outer; | ^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 @@ -32,7 +32,7 @@ LL | struct Outer; | ^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 @@ -41,7 +41,7 @@ LL | struct Outer; | ^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 5 previous errors diff --git a/src/test/ui/const-generics/issues/issue-75047.min.stderr b/src/test/ui/const-generics/issues/issue-75047.min.stderr index edc54b082d..b87bb18a5a 100644 --- a/src/test/ui/const-generics/issues/issue-75047.min.stderr +++ b/src/test/ui/const-generics/issues/issue-75047.min.stderr @@ -5,7 +5,7 @@ LL | struct Foo::value()]>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs index 9fdbbff66e..04c0190151 100644 --- a/src/test/ui/const-generics/issues/issue-76595.rs +++ b/src/test/ui/const-generics/issues/issue-76595.rs @@ -13,5 +13,5 @@ fn test() where Bool<{core::mem::size_of::() > 4}>: True { fn main() { test::<2>(); - //~^ ERROR wrong number of type + //~^ ERROR wrong number of generic arguments } diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr index f258d29771..1e37f9dcb1 100644 --- a/src/test/ui/const-generics/issues/issue-76595.stderr +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -1,8 +1,8 @@ -error[E0107]: wrong number of type arguments: expected 1, found 0 +error[E0107]: wrong number of generic arguments: expected 2, found 1 --> $DIR/issue-76595.rs:15:5 | LL | test::<2>(); - | ^^^^^^^^^ expected 1 type argument + | ^^^^^^^^^ expected 2 generic arguments error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr index c10db84ea6..551b8e43e1 100644 --- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr @@ -5,6 +5,7 @@ LL | fn ty_param() -> [u8; std::mem::size_of::()] { | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-76701-ty-param-in-const.rs:12:42 @@ -13,6 +14,7 @@ LL | fn const_param() -> [u8; N + 1] { | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.full.stderr b/src/test/ui/const-generics/macro_rules-braces.full.stderr index f6e9aabd90..3c9d4c9b47 100644 --- a/src/test/ui/const-generics/macro_rules-braces.full.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.full.stderr @@ -1,16 +1,27 @@ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/macro_rules-braces.rs:34:17 + --> $DIR/macro_rules-braces.rs:49:17 | -LL | let _: baz!(N); - | ^ +LL | let _: baz!(m::P); + | ^^^^ | help: enclose the `const` expression in braces | -LL | let _: baz!({ N }); - | ^ ^ +LL | let _: baz!({ m::P }); + | ^ ^ + +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/macro_rules-braces.rs:69:17 + | +LL | let _: baz!(10 + 7); + | ^^^^^^ + | +help: enclose the `const` expression in braces + | +LL | let _: baz!({ 10 + 7 }); + | ^ ^ error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:10:13 + --> $DIR/macro_rules-braces.rs:16:13 | LL | [u8; $x] | ^^^^^^^^ @@ -22,7 +33,7 @@ LL | let _: foo!({{ N }}); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:15:13 + --> $DIR/macro_rules-braces.rs:21:13 | LL | [u8; { $x }] | ^^^^^^^^^^^^ @@ -34,7 +45,7 @@ LL | let _: bar!({ N }); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:20:13 + --> $DIR/macro_rules-braces.rs:26:13 | LL | Foo<$x> | ^^^^^^^ @@ -46,7 +57,7 @@ LL | let _: baz!({{ N }}); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: constant expression depends on a generic parameter - --> $DIR/macro_rules-braces.rs:25:13 + --> $DIR/macro_rules-braces.rs:31:13 | LL | Foo<{ $x }> | ^^^^^^^^^^^ @@ -57,5 +68,5 @@ LL | let _: biz!({ N }); = note: this may fail depending on what value the parameter takes = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.min.stderr b/src/test/ui/const-generics/macro_rules-braces.min.stderr index 1fe18e3fc0..c400e2c814 100644 --- a/src/test/ui/const-generics/macro_rules-braces.min.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.min.stderr @@ -1,45 +1,60 @@ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/macro_rules-braces.rs:34:17 + --> $DIR/macro_rules-braces.rs:49:17 | -LL | let _: baz!(N); - | ^ +LL | let _: baz!(m::P); + | ^^^^ | help: enclose the `const` expression in braces | -LL | let _: baz!({ N }); - | ^ ^ +LL | let _: baz!({ m::P }); + | ^ ^ + +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/macro_rules-braces.rs:69:17 + | +LL | let _: baz!(10 + 7); + | ^^^^^^ + | +help: enclose the `const` expression in braces + | +LL | let _: baz!({ 10 + 7 }); + | ^ ^ error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:31:20 + --> $DIR/macro_rules-braces.rs:37:20 | LL | let _: foo!({{ N }}); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:33:19 + --> $DIR/macro_rules-braces.rs:41:19 | LL | let _: bar!({ N }); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:36:20 + --> $DIR/macro_rules-braces.rs:46:20 | LL | let _: baz!({{ N }}); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/macro_rules-braces.rs:38:19 + --> $DIR/macro_rules-braces.rs:51:19 | LL | let _: biz!({ N }); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.rs b/src/test/ui/const-generics/macro_rules-braces.rs index c3e2c8ba20..c6b43bec24 100644 --- a/src/test/ui/const-generics/macro_rules-braces.rs +++ b/src/test/ui/const-generics/macro_rules-braces.rs @@ -3,6 +3,12 @@ #![cfg_attr(full, feature(const_generics))] #![cfg_attr(min, feature(min_const_generics))] +mod m { + pub const P: usize = 0; +} + +const Q: usize = 0; + fn test() { struct Foo; macro_rules! foo { @@ -29,13 +35,42 @@ fn test() { let _: foo!(N); let _: foo!({ N }); let _: foo!({{ N }}); //[min]~ ERROR generic parameters may not + let _: foo!(Q); + let _: foo!(m::P); let _: bar!(N); let _: bar!({ N }); //[min]~ ERROR generic parameters may not - let _: baz!(N); //~ ERROR expressions must be enclosed in braces + let _: bar!(Q); + let _: bar!(m::P); + let _: baz!(N); let _: baz!({ N }); let _: baz!({{ N }}); //[min]~ ERROR generic parameters may not + let _: baz!(Q); + let _: baz!({ m::P }); + let _: baz!(m::P); //~ ERROR expressions must be enclosed in braces let _: biz!(N); let _: biz!({ N }); //[min]~ ERROR generic parameters may not + let _: biz!(Q); + let _: biz!(m::P); + let _: foo!(3); + let _: foo!({ 3 }); + let _: foo!({{ 3 }}); + let _: bar!(3); + let _: bar!({ 3 }); + let _: baz!(3); + let _: baz!({ 3 }); + let _: baz!({{ 3 }}); + let _: biz!(3); + let _: biz!({ 3 }); + let _: foo!(10 + 7); + let _: foo!({ 10 + 7 }); + let _: foo!({{ 10 + 7 }}); + let _: bar!(10 + 7); + let _: bar!({ 10 + 7 }); + let _: baz!(10 + 7); //~ ERROR expressions must be enclosed in braces + let _: baz!({ 10 + 7 }); + let _: baz!({{ 10 + 7 }}); + let _: biz!(10 + 7); + let _: biz!({ 10 + 7 }); } fn main() { diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr index a8de987e16..2ea66279d4 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr @@ -5,6 +5,7 @@ LL | struct Break0([u8; { N + 1 }]); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:14:40 @@ -13,6 +14,7 @@ LL | struct Break1([u8; { { N } }]); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:18:17 @@ -21,6 +23,7 @@ LL | let _: [u8; N + 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:23:17 @@ -29,6 +32,7 @@ LL | let _ = [0; N + 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:27:45 @@ -37,6 +41,7 @@ LL | struct BreakTy0(T, [u8; { size_of::<*mut T>() }]); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:30:47 @@ -45,6 +50,7 @@ LL | struct BreakTy1(T, [u8; { { size_of::<*mut T>() } }]); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:34:32 @@ -53,6 +59,7 @@ LL | let _: [u8; size_of::<*mut T>() + 1]; | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions warning: cannot use constants which depend on generic parameters in types --> $DIR/complex-expression.rs:39:17 diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.stderr b/src/test/ui/const-generics/min_const_generics/complex-types.stderr index 52ed3c1c6e..5d473f1f87 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-types.stderr +++ b/src/test/ui/const-generics/min_const_generics/complex-types.stderr @@ -5,7 +5,7 @@ LL | struct Foo; | ^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `()` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:7:21 @@ -14,7 +14,7 @@ LL | struct Bar; | ^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `No` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:12:21 @@ -23,7 +23,7 @@ LL | struct Fez; | ^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `&'static u8` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:15:21 @@ -32,7 +32,7 @@ LL | struct Faz; | ^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `!` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:18:21 @@ -41,7 +41,7 @@ LL | struct Fiz; | ^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `()` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:21:19 @@ -50,7 +50,7 @@ LL | enum Goo { A, B } | ^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `()` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:24:20 @@ -59,7 +59,7 @@ LL | union Boo { a: () } | ^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 7 previous errors diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs index aea3def5ae..b96d5c561f 100644 --- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs +++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs @@ -13,8 +13,7 @@ fn b() { foo::(); //~^ ERROR expected trait, found constant `BAR` //~| ERROR expected trait, found constant `BAR` - //~| ERROR wrong number of const arguments: expected 1, found 0 - //~| ERROR wrong number of type arguments: expected 0, found 1 + //~| ERROR type provided when a constant was expected //~| WARN trait objects without an explicit `dyn` are deprecated } fn c() { diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr index 47e9dc034e..6adcf6a3e3 100644 --- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr +++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr @@ -10,7 +10,7 @@ LL | foo::<{ BAR + 3 }>(); | ^ ^ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/const-expression-suggest-missing-braces.rs:21:11 + --> $DIR/const-expression-suggest-missing-braces.rs:20:11 | LL | foo::<3 + 3>(); | ^^^^^ @@ -21,7 +21,7 @@ LL | foo::<{ 3 + 3 }>(); | ^ ^ error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:24:15 + --> $DIR/const-expression-suggest-missing-braces.rs:23:15 | LL | foo::(); | ^ expected one of `,` or `>` @@ -32,7 +32,7 @@ LL | foo::<{ BAR - 3 }>(); | ^ ^ error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:27:15 + --> $DIR/const-expression-suggest-missing-braces.rs:26:15 | LL | foo::(); | ^ expected one of `,` or `>` @@ -43,7 +43,7 @@ LL | foo::<{ BAR - BAR }>(); | ^ ^ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/const-expression-suggest-missing-braces.rs:30:11 + --> $DIR/const-expression-suggest-missing-braces.rs:29:11 | LL | foo::<100 - BAR>(); | ^^^^^^^^^ @@ -54,7 +54,7 @@ LL | foo::<{ 100 - BAR }>(); | ^ ^ error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:33:19 + --> $DIR/const-expression-suggest-missing-braces.rs:32:19 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -65,7 +65,7 @@ LL | foo::<{ bar() }>(); | ^ ^ error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:36:21 + --> $DIR/const-expression-suggest-missing-braces.rs:35:21 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -76,7 +76,7 @@ LL | foo::<{ bar::() }>(); | ^ ^ error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:39:21 + --> $DIR/const-expression-suggest-missing-braces.rs:38:21 | LL | foo::() + BAR>(); | ^ expected one of `,` or `>` @@ -87,7 +87,7 @@ LL | foo::<{ bar::() + BAR }>(); | ^ ^ error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:42:21 + --> $DIR/const-expression-suggest-missing-braces.rs:41:21 | LL | foo::() - BAR>(); | ^ expected one of `,` or `>` @@ -98,7 +98,7 @@ LL | foo::<{ bar::() - BAR }>(); | ^ ^ error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:45:15 + --> $DIR/const-expression-suggest-missing-braces.rs:44:15 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -109,7 +109,7 @@ LL | foo::<{ BAR - bar::() }>(); | ^ ^ error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:48:15 + --> $DIR/const-expression-suggest-missing-braces.rs:47:15 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -139,19 +139,13 @@ LL | foo::(); | = note: `#[warn(bare_trait_objects)]` on by default -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/const-expression-suggest-missing-braces.rs:13:5 - | -LL | foo::(); - | ^^^^^^^^^^^^^^^^ expected 1 const argument - -error[E0107]: wrong number of type arguments: expected 0, found 1 +error[E0747]: type provided when a constant was expected --> $DIR/const-expression-suggest-missing-braces.rs:13:11 | LL | foo::(); - | ^^^^^^^^^ unexpected type argument + | ^^^^^^^^^ -error: aborting due to 15 previous errors; 1 warning emitted +error: aborting due to 14 previous errors; 1 warning emitted -Some errors have detailed explanations: E0107, E0404. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0404, E0747. +For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/const-generics/min_const_generics/inferred_const.rs b/src/test/ui/const-generics/min_const_generics/inferred_const.rs new file mode 100644 index 0000000000..dcd069ce3b --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/inferred_const.rs @@ -0,0 +1,8 @@ +#![feature(min_const_generics)] +fn foo(data: [u32; N]) -> [u32; K] { + [0; K] +} +fn main() { + let a = foo::<_, 2>([0, 1, 2]); + //~^ ERROR type provided when a constant was expected +} diff --git a/src/test/ui/const-generics/min_const_generics/inferred_const.stderr b/src/test/ui/const-generics/min_const_generics/inferred_const.stderr new file mode 100644 index 0000000000..e17105b2aa --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/inferred_const.stderr @@ -0,0 +1,11 @@ +error[E0747]: type provided when a constant was expected + --> $DIR/inferred_const.rs:6:19 + | +LL | let a = foo::<_, 2>([0, 1, 2]); + | ^ + | + = help: const arguments cannot yet be inferred with `_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/min_const_generics/macro-fail.rs b/src/test/ui/const-generics/min_const_generics/macro-fail.rs index 7f16f2f33d..1bd0c46f55 100644 --- a/src/test/ui/const-generics/min_const_generics/macro-fail.rs +++ b/src/test/ui/const-generics/min_const_generics/macro-fail.rs @@ -14,11 +14,9 @@ trait Marker {} impl Marker for Example {} fn make_marker() -> impl Marker { - //~^ ERROR wrong number of const - //~| ERROR wrong number of type + //~^ ERROR: type provided when a constant was expected Example:: - //~^ ERROR wrong number of const - //~| ERROR wrong number of type + //~^ ERROR: type provided when a constant was expected } fn from_marker(_: impl Marker<{ @@ -38,11 +36,9 @@ fn main() { }>; let _fail = Example::; - //~^ ERROR wrong number of const - //~| ERROR wrong number of type + //~^ ERROR: type provided when a constant was expected let _fail = Example::; - //~^ ERROR wrong number of const - //~| ERROR wrong number of type + //~^ ERROR: type provided when a constant was expected //~| ERROR unexpected end of macro invocation } diff --git a/src/test/ui/const-generics/min_const_generics/macro-fail.stderr b/src/test/ui/const-generics/min_const_generics/macro-fail.stderr index fe7a4a5c38..a5dedf6fe2 100644 --- a/src/test/ui/const-generics/min_const_generics/macro-fail.stderr +++ b/src/test/ui/const-generics/min_const_generics/macro-fail.stderr @@ -1,5 +1,5 @@ error: expected type, found `{` - --> $DIR/macro-fail.rs:33:27 + --> $DIR/macro-fail.rs:31:27 | LL | fn make_marker() -> impl Marker { | ---------------------- @@ -13,7 +13,7 @@ LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: expected type, found `{` - --> $DIR/macro-fail.rs:33:27 + --> $DIR/macro-fail.rs:31:27 | LL | Example:: | ---------------------- @@ -46,7 +46,7 @@ LL | let _fail = Example::; = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected end of macro invocation - --> $DIR/macro-fail.rs:44:25 + --> $DIR/macro-fail.rs:41:25 | LL | macro_rules! gimme_a_const { | -------------------------- when calling this macro @@ -54,54 +54,30 @@ LL | macro_rules! gimme_a_const { LL | let _fail = Example::; | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/macro-fail.rs:16:26 - | -LL | fn make_marker() -> impl Marker { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument - -error[E0107]: wrong number of type arguments: expected 0, found 1 +error[E0747]: type provided when a constant was expected --> $DIR/macro-fail.rs:16:33 | LL | fn make_marker() -> impl Marker { - | ^^^^^^^^^^^^^^^^^^^^^^ unexpected type argument - -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/macro-fail.rs:19:3 - | -LL | Example:: - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/macro-fail.rs:19:13 +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail.rs:18:13 | LL | Example:: - | ^^^^^^^^^^^^^^^^^^^^^^ unexpected type argument + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/macro-fail.rs:40:15 +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail.rs:38:25 | LL | let _fail = Example::; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument - -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/macro-fail.rs:40:25 - | -LL | let _fail = Example::; - | ^^^^^^^^^^^^^^^^^ unexpected type argument - -error[E0107]: wrong number of const arguments: expected 1, found 0 - --> $DIR/macro-fail.rs:44:15 - | -LL | let _fail = Example::; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + | ^^^^^^^^^^^^^^^^^ -error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/macro-fail.rs:44:25 +error[E0747]: type provided when a constant was expected + --> $DIR/macro-fail.rs:41:25 | LL | let _fail = Example::; - | ^^^^^^^^^^^^^^^^ unexpected type argument + | ^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/min_const_generics/macro.rs b/src/test/ui/const-generics/min_const_generics/macro.rs index 85ecce551d..575fbd3357 100644 --- a/src/test/ui/const-generics/min_const_generics/macro.rs +++ b/src/test/ui/const-generics/min_const_generics/macro.rs @@ -15,14 +15,14 @@ impl Marker for Example {} fn make_marker() -> impl Marker<{ #[macro_export] - macro_rules! const_macro { () => {{ 3 }} }; inline!() + macro_rules! const_macro { () => {{ 3 }} } inline!() }> { Example::<{ const_macro!() }> } fn from_marker(_: impl Marker<{ #[macro_export] - macro_rules! inline { () => {{ 3 }} }; inline!() + macro_rules! inline { () => {{ 3 }} } inline!() }>) {} fn main() { @@ -30,7 +30,7 @@ fn main() { #[macro_export] macro_rules! gimme_a_const { ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} - }; + } gimme_a_const!(run) }>; @@ -42,13 +42,13 @@ fn main() { let _ok: [u8; { #[macro_export] - macro_rules! const_two { () => {{ 2 }} }; + macro_rules! const_two { () => {{ 2 }} } const_two!() }]; let _ok = [0; { #[macro_export] - macro_rules! const_three { () => {{ 3 }} }; + macro_rules! const_three { () => {{ 3 }} } const_three!() }]; let _ok = [0; const_three!()]; diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 64da5e07df..40c73f0b95 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -5,6 +5,7 @@ LL | fn t1() -> [u8; std::mem::size_of::()]; | ^^^^ cannot perform const operation using `Self` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/self-ty-in-const-1.rs:14:41 diff --git a/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr index cc32d8a67f..6c39f6b4c1 100644 --- a/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr +++ b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr @@ -5,7 +5,7 @@ LL | fn a() {} | ^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr index 063120ad07..6b90329b72 100644 --- a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr +++ b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr @@ -5,7 +5,7 @@ LL | struct Const; | ^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to previous error diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index 075bdceccf..06ab9a6ff2 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -4,13 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/nested-type.rs:16:5 - | -LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr index 733b02fa85..369e387508 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -12,7 +12,7 @@ LL | | }]>; | |__^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants --> $DIR/nested-type.rs:16:5 @@ -20,13 +20,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/nested-type.rs:16:5 - | -LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs index 8372551fb4..c566098398 100644 --- a/src/test/ui/const-generics/nested-type.rs +++ b/src/test/ui/const-generics/nested-type.rs @@ -15,7 +15,6 @@ struct Foo::value() //~^ ERROR calls in constants are limited to constant functions - //~| ERROR evaluation of constant value failed }]>; fn main() {} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-5.rs b/src/test/ui/const-generics/occurs-check/unused-substs-5.rs new file mode 100644 index 0000000000..e5d487d89b --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-5.rs @@ -0,0 +1,20 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// `N + 1` also depends on `T` here even if it doesn't use it. +fn q(_: T) -> [u8; N + 1] { + todo!() +} + +fn supplier() -> T { + todo!() +} + +fn catch_me() where [u8; N + 1]: Default { + let mut x = supplier(); + x = q::<_, N>(x); //~ ERROR mismatched types +} + +fn main() { + catch_me::<3>(); +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-5.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-5.stderr new file mode 100644 index 0000000000..239569dab0 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-5.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/unused-substs-5.rs:15:9 + | +LL | x = q::<_, N>(x); + | ^^^^^^^^^^^^ + | | + | cyclic type of infinite size + | help: try using a conversion method: `q::<_, N>(x).to_vec()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index 39aa8087ce..9e0837a0a6 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -13,6 +13,7 @@ LL | struct Foo()]>(T, U); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: constant values inside of type parameter defaults must not depend on generic parameters --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21 diff --git a/src/test/ui/const-generics/promotion.rs b/src/test/ui/const-generics/promotion.rs new file mode 100644 index 0000000000..ac568bb75f --- /dev/null +++ b/src/test/ui/const-generics/promotion.rs @@ -0,0 +1,11 @@ +// run-pass +// tests that promoting expressions containing const parameters is allowed. +#![feature(min_const_generics)] + +fn promotion_test() -> &'static usize { + &(3 + N) +} + +fn main() { + assert_eq!(promotion_test::<13>(), &16); +} diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr index 1f711bef4a..46997fed77 100644 --- a/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr +++ b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr @@ -5,7 +5,7 @@ LL | struct ConstString; | ^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `&'static [u8]` is forbidden as the type of a const generic parameter --> $DIR/slice-const-param-mismatch.rs:10:28 @@ -14,7 +14,7 @@ LL | struct ConstBytes; | ^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/slice-const-param.min.stderr b/src/test/ui/const-generics/slice-const-param.min.stderr index 2a49619e66..7a9f65233e 100644 --- a/src/test/ui/const-generics/slice-const-param.min.stderr +++ b/src/test/ui/const-generics/slice-const-param.min.stderr @@ -5,7 +5,7 @@ LL | pub fn function_with_str() -> &'static str { | ^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `&'static [u8]` is forbidden as the type of a const generic parameter --> $DIR/slice-const-param.rs:13:41 @@ -14,7 +14,7 @@ LL | pub fn function_with_bytes() -> &'static [u8] { | ^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/std/const-generics-range.min.stderr b/src/test/ui/const-generics/std/const-generics-range.min.stderr index 97be6ee644..9274ccd2b9 100644 --- a/src/test/ui/const-generics/std/const-generics-range.min.stderr +++ b/src/test/ui/const-generics/std/const-generics-range.min.stderr @@ -5,7 +5,7 @@ LL | struct _Range>; | ^^^^^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `RangeFrom` is forbidden as the type of a const generic parameter --> $DIR/const-generics-range.rs:13:28 @@ -14,7 +14,7 @@ LL | struct _RangeFrom>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `RangeFull` is forbidden as the type of a const generic parameter --> $DIR/const-generics-range.rs:18:28 @@ -23,7 +23,7 @@ LL | struct _RangeFull; | ^^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `RangeInclusive` is forbidden as the type of a const generic parameter --> $DIR/const-generics-range.rs:24:33 @@ -32,7 +32,7 @@ LL | struct _RangeInclusive>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `RangeTo` is forbidden as the type of a const generic parameter --> $DIR/const-generics-range.rs:29:26 @@ -41,7 +41,7 @@ LL | struct _RangeTo>; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `RangeToInclusive` is forbidden as the type of a const generic parameter --> $DIR/const-generics-range.rs:34:35 @@ -50,7 +50,7 @@ LL | struct _RangeToInclusive>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr index 8656239605..8f240f0d93 100644 --- a/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr +++ b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -5,7 +5,7 @@ LL | trait Get<'a, const N: &'static str> { | ^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/issue-71348.rs:19:25 @@ -14,7 +14,7 @@ LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Ta | ^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` - = note: more complex types are supported with `#[feature(const_generics)]` + = help: more complex types are supported with `#[feature(const_generics)]` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/wf-misc.min.stderr b/src/test/ui/const-generics/wf-misc.min.stderr index 935f12dd2c..99142cb6ce 100644 --- a/src/test/ui/const-generics/wf-misc.min.stderr +++ b/src/test/ui/const-generics/wf-misc.min.stderr @@ -5,6 +5,7 @@ LL | let _: [u8; N + 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/wf-misc.rs:17:21 @@ -13,6 +14,7 @@ LL | let _: Const::<{N + 1}>; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/ascii_ctype.rs b/src/test/ui/consts/ascii_ctype.rs deleted file mode 100644 index ef2f7322f2..0000000000 --- a/src/test/ui/consts/ascii_ctype.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass - -macro_rules! suite { - ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { - $( - mod $fn { - const CHAR_A_LOWER: bool = 'a'.$fn(); - const CHAR_A_UPPER: bool = 'A'.$fn(); - const CHAR_NINE: bool = '9'.$fn(); - const CHAR_DOT: bool = '.'.$fn(); - const CHAR_SPACE: bool = ' '.$fn(); - - const U8_A_LOWER: bool = b'a'.$fn(); - const U8_A_UPPER: bool = b'A'.$fn(); - const U8_NINE: bool = b'9'.$fn(); - const U8_DOT: bool = b'.'.$fn(); - const U8_SPACE: bool = b' '.$fn(); - - pub fn run() { - assert_eq!(CHAR_A_LOWER, $a); - assert_eq!(CHAR_A_UPPER, $A); - assert_eq!(CHAR_NINE, $nine); - assert_eq!(CHAR_DOT, $dot); - assert_eq!(CHAR_SPACE, $space); - - assert_eq!(U8_A_LOWER, $a); - assert_eq!(U8_A_UPPER, $A); - assert_eq!(U8_NINE, $nine); - assert_eq!(U8_DOT, $dot); - assert_eq!(U8_SPACE, $space); - } - } - )* - - fn main() { - $( $fn::run(); )* - } - } -} - -suite! { - // 'a' 'A' '9' '.' ' ' - is_ascii_alphabetic => [true, true, false, false, false]; - is_ascii_uppercase => [false, true, false, false, false]; - is_ascii_lowercase => [true, false, false, false, false]; - is_ascii_alphanumeric => [true, true, true, false, false]; - is_ascii_digit => [false, false, true, false, false]; - is_ascii_hexdigit => [true, true, true, false, false]; - is_ascii_punctuation => [false, false, false, true, false]; - is_ascii_graphic => [true, true, true, true, false]; - is_ascii_whitespace => [false, false, false, false, true]; - is_ascii_control => [false, false, false, false, false]; -} diff --git a/src/test/ui/consts/assume-type-intrinsics.rs b/src/test/ui/consts/assume-type-intrinsics.rs new file mode 100644 index 0000000000..77370e1ccc --- /dev/null +++ b/src/test/ui/consts/assume-type-intrinsics.rs @@ -0,0 +1,13 @@ +// error-pattern: any use of this value will cause an error + +#![feature(never_type)] +#![feature(const_maybe_uninit_assume_init)] + +#[allow(invalid_value)] +fn main() { + use std::mem::MaybeUninit; + + const _BAD: () = unsafe { + MaybeUninit::::uninit().assume_init(); + }; +} diff --git a/src/test/ui/consts/assume-type-intrinsics.stderr b/src/test/ui/consts/assume-type-intrinsics.stderr new file mode 100644 index 0000000000..ed09f74e9b --- /dev/null +++ b/src/test/ui/consts/assume-type-intrinsics.stderr @@ -0,0 +1,21 @@ +error: any use of this value will cause an error + --> $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | +LL | intrinsics::assert_inhabited::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | aborted execution: attempted to instantiate uninhabited type `!` + | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | inside `_BAD` at $DIR/assume-type-intrinsics.rs:11:9 + | + ::: $DIR/assume-type-intrinsics.rs:10:5 + | +LL | / const _BAD: () = unsafe { +LL | | MaybeUninit::::uninit().assume_init(); +LL | | }; + | |______- + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs index 3d5b64ed4c..db64298897 100644 --- a/src/test/ui/consts/const-call.rs +++ b/src/test/ui/consts/const-call.rs @@ -5,5 +5,4 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions - //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index d11add818d..9761348bab 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -4,13 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | let _ = [0; f(2)]; | ^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/const-call.rs:6:17 - | -LL | let _ = [0; f(2)]; - | ^^^^ calling non-const function `f` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-err-early.rs b/src/test/ui/consts/const-err-early.rs index bae2cd286e..13dfe7fac9 100644 --- a/src/test/ui/consts/const-err-early.rs +++ b/src/test/ui/consts/const-err-early.rs @@ -1,6 +1,6 @@ #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR const_err +pub const A: i8 = -i8::MIN; //~ ERROR const_err pub const B: u8 = 200u8 + 200u8; //~ ERROR const_err pub const C: u8 = 200u8 * 4; //~ ERROR const_err pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR const_err diff --git a/src/test/ui/consts/const-err-early.stderr b/src/test/ui/consts/const-err-early.stderr index 36b36db7c1..ec55139f17 100644 --- a/src/test/ui/consts/const-err-early.stderr +++ b/src/test/ui/consts/const-err-early.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error --> $DIR/const-err-early.rs:3:19 | -LL | pub const A: i8 = -std::i8::MIN; - | ------------------^^^^^^^^^^^^^- +LL | pub const A: i8 = -i8::MIN; + | ------------------^^^^^^^^- | | | attempt to negate `i8::MIN`, which would overflow | diff --git a/src/test/ui/consts/const-err-multi.rs b/src/test/ui/consts/const-err-multi.rs index fa3ad832c6..ce74fae981 100644 --- a/src/test/ui/consts/const-err-multi.rs +++ b/src/test/ui/consts/const-err-multi.rs @@ -1,6 +1,6 @@ #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; +pub const A: i8 = -i8::MIN; //~^ ERROR const_err pub const B: i8 = A; //~^ ERROR const_err diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr index 5b688d4c6d..b3123b4e35 100644 --- a/src/test/ui/consts/const-err-multi.stderr +++ b/src/test/ui/consts/const-err-multi.stderr @@ -1,8 +1,8 @@ error: any use of this value will cause an error --> $DIR/const-err-multi.rs:3:19 | -LL | pub const A: i8 = -std::i8::MIN; - | ------------------^^^^^^^^^^^^^- +LL | pub const A: i8 = -i8::MIN; + | ------------------^^^^^^^^- | | | attempt to negate `i8::MIN`, which would overflow | diff --git a/src/test/ui/consts/const-err2.noopt.stderr b/src/test/ui/consts/const-err2.noopt.stderr index 2473632cbc..8b1688c4a8 100644 --- a/src/test/ui/consts/const-err2.noopt.stderr +++ b/src/test/ui/consts/const-err2.noopt.stderr @@ -1,16 +1,16 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | -LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow +LL | let a = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | -LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow +LL | let a_i128 = -i128::MIN; + | ^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 @@ -21,8 +21,8 @@ LL | let b = 200u8 + 200u8 + 200u8; error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | -LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow +LL | let b_i128 = i128::MIN - i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 diff --git a/src/test/ui/consts/const-err2.opt.stderr b/src/test/ui/consts/const-err2.opt.stderr index 2473632cbc..8b1688c4a8 100644 --- a/src/test/ui/consts/const-err2.opt.stderr +++ b/src/test/ui/consts/const-err2.opt.stderr @@ -1,16 +1,16 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | -LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow +LL | let a = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | -LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow +LL | let a_i128 = -i128::MIN; + | ^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 @@ -21,8 +21,8 @@ LL | let b = 200u8 + 200u8 + 200u8; error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | -LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow +LL | let b_i128 = i128::MIN - i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 diff --git a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr index 2473632cbc..8b1688c4a8 100644 --- a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr @@ -1,16 +1,16 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | -LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow +LL | let a = -i8::MIN; + | ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | -LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow +LL | let a_i128 = -i128::MIN; + | ^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 @@ -21,8 +21,8 @@ LL | let b = 200u8 + 200u8 + 200u8; error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | -LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow +LL | let b_i128 = i128::MIN - i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs index 2c6a987180..db49ec25aa 100644 --- a/src/test/ui/consts/const-err2.rs +++ b/src/test/ui/consts/const-err2.rs @@ -16,13 +16,13 @@ fn black_box(_: T) { } fn main() { - let a = -std::i8::MIN; + let a = -i8::MIN; //~^ ERROR arithmetic operation will overflow - let a_i128 = -std::i128::MIN; + let a_i128 = -i128::MIN; //~^ ERROR arithmetic operation will overflow let b = 200u8 + 200u8 + 200u8; //~^ ERROR arithmetic operation will overflow - let b_i128 = std::i128::MIN - std::i128::MAX; + let b_i128 = i128::MIN - i128::MAX; //~^ ERROR arithmetic operation will overflow let c = 200u8 * 4; //~^ ERROR arithmetic operation will overflow diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs index 6fd8e9cbc8..bcc966dc96 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs @@ -12,8 +12,6 @@ #![allow(unused_imports)] use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; const A_I8_I : [u32; (i8::MAX as usize) + 1] diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr index 0ae51786b3..73f421b5b1 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-eval-overflow-3.rs:20:11 + --> $DIR/const-eval-overflow-3.rs:18:11 | LL | = [0; (i8::MAX + 1) as usize]; | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs index db6f17a671..480069e67f 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs @@ -10,8 +10,6 @@ #![allow(unused_imports)] use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; const A_I8_I : [u32; (i8::MAX as usize) + 1] diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 2696d5a0b3..2b96b66819 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/const-eval-overflow-3b.rs:18:22 + --> $DIR/const-eval-overflow-3b.rs:16:22 | LL | = [0; (i8::MAX + 1u8) as usize]; | ^^^ expected `i8`, found `u8` error[E0277]: cannot add `u8` to `i8` - --> $DIR/const-eval-overflow-3b.rs:18:20 + --> $DIR/const-eval-overflow-3b.rs:16:20 | LL | = [0; (i8::MAX + 1u8) as usize]; | ^ no implementation for `i8 + u8` diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4.rs b/src/test/ui/consts/const-eval/const-eval-overflow-4.rs index 0b12a438f9..762c7a968a 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4.rs @@ -6,8 +6,6 @@ #![allow(unused_imports)] use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr index e548fc266c..94f4193195 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-eval-overflow-4.rs:13:13 + --> $DIR/const-eval-overflow-4.rs:11:13 | LL | : [u32; (i8::MAX as i8 + 1i8) as usize] | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs index 2a4585faf1..ce9c980de0 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs @@ -5,9 +5,6 @@ #![allow(unused_imports)] -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; - const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] //~^ ERROR mismatched types diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index e695e9f75f..1e181c465d 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/const-eval-overflow-4b.rs:12:30 + --> $DIR/const-eval-overflow-4b.rs:9:30 | LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | ^^^ expected `i8`, found `u8` error[E0277]: cannot add `u8` to `i8` - --> $DIR/const-eval-overflow-4b.rs:12:28 + --> $DIR/const-eval-overflow-4b.rs:9:28 | LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | ^ no implementation for `i8 + u8` @@ -13,7 +13,7 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] = help: the trait `Add` is not implemented for `i8` error[E0604]: only `u8` can be cast as `char`, not `i8` - --> $DIR/const-eval-overflow-4b.rs:25:13 + --> $DIR/const-eval-overflow-4b.rs:22:13 | LL | : [u32; 5i8 as char as usize] | ^^^^^^^^^^^ invalid cast diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.rs b/src/test/ui/consts/const-eval/const-eval-overflow2.rs index a0dbcc88ce..57a9dd55c8 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow2.rs @@ -8,8 +8,6 @@ #![deny(const_err)] use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = ( diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr index 51a810b8f3..8864bc170f 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr @@ -1,5 +1,5 @@ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:16:6 + --> $DIR/const-eval-overflow2.rs:14:6 | LL | / const VALS_I8: (i8,) = LL | | ( @@ -15,7 +15,7 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:22:6 + --> $DIR/const-eval-overflow2.rs:20:6 | LL | / const VALS_I16: (i16,) = LL | | ( @@ -25,7 +25,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:28:6 + --> $DIR/const-eval-overflow2.rs:26:6 | LL | / const VALS_I32: (i32,) = LL | | ( @@ -35,7 +35,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:34:6 + --> $DIR/const-eval-overflow2.rs:32:6 | LL | / const VALS_I64: (i64,) = LL | | ( @@ -45,7 +45,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:40:6 + --> $DIR/const-eval-overflow2.rs:38:6 | LL | / const VALS_U8: (u8,) = LL | | ( @@ -55,7 +55,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:45:6 + --> $DIR/const-eval-overflow2.rs:43:6 | LL | / const VALS_U16: (u16,) = ( LL | | u16::MIN - 1, @@ -64,7 +64,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:50:6 + --> $DIR/const-eval-overflow2.rs:48:6 | LL | / const VALS_U32: (u32,) = ( LL | | u32::MIN - 1, @@ -73,7 +73,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2.rs:56:6 + --> $DIR/const-eval-overflow2.rs:54:6 | LL | / const VALS_U64: (u64,) = LL | | ( diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.rs b/src/test/ui/consts/const-eval/const-eval-overflow2b.rs index da883671a6..e87952ab0f 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.rs @@ -8,8 +8,6 @@ #![deny(const_err)] use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = ( diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr index eec440fcb7..e66e80c8f1 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -1,5 +1,5 @@ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:16:6 + --> $DIR/const-eval-overflow2b.rs:14:6 | LL | / const VALS_I8: (i8,) = LL | | ( @@ -15,7 +15,7 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:22:6 + --> $DIR/const-eval-overflow2b.rs:20:6 | LL | / const VALS_I16: (i16,) = LL | | ( @@ -25,7 +25,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:28:6 + --> $DIR/const-eval-overflow2b.rs:26:6 | LL | / const VALS_I32: (i32,) = LL | | ( @@ -35,7 +35,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:34:6 + --> $DIR/const-eval-overflow2b.rs:32:6 | LL | / const VALS_I64: (i64,) = LL | | ( @@ -45,7 +45,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:40:6 + --> $DIR/const-eval-overflow2b.rs:38:6 | LL | / const VALS_U8: (u8,) = LL | | ( @@ -55,7 +55,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:45:6 + --> $DIR/const-eval-overflow2b.rs:43:6 | LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX + 1, @@ -64,7 +64,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:50:6 + --> $DIR/const-eval-overflow2b.rs:48:6 | LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX + 1, @@ -73,7 +73,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2b.rs:56:6 + --> $DIR/const-eval-overflow2b.rs:54:6 | LL | / const VALS_U64: (u64,) = LL | | ( diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.rs b/src/test/ui/consts/const-eval/const-eval-overflow2c.rs index e87344405a..84d3dd20a9 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2c.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.rs @@ -8,8 +8,6 @@ #![deny(const_err)] use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = ( diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr index e44f94c202..10e308938f 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -1,5 +1,5 @@ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:16:6 + --> $DIR/const-eval-overflow2c.rs:14:6 | LL | / const VALS_I8: (i8,) = LL | | ( @@ -15,7 +15,7 @@ LL | #![deny(const_err)] | ^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:22:6 + --> $DIR/const-eval-overflow2c.rs:20:6 | LL | / const VALS_I16: (i16,) = LL | | ( @@ -25,7 +25,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:28:6 + --> $DIR/const-eval-overflow2c.rs:26:6 | LL | / const VALS_I32: (i32,) = LL | | ( @@ -35,7 +35,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:34:6 + --> $DIR/const-eval-overflow2c.rs:32:6 | LL | / const VALS_I64: (i64,) = LL | | ( @@ -45,7 +45,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:40:6 + --> $DIR/const-eval-overflow2c.rs:38:6 | LL | / const VALS_U8: (u8,) = LL | | ( @@ -55,7 +55,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:45:6 + --> $DIR/const-eval-overflow2c.rs:43:6 | LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX * 2, @@ -64,7 +64,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:50:6 + --> $DIR/const-eval-overflow2c.rs:48:6 | LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX * 2, @@ -73,7 +73,7 @@ LL | | ); | |_______- error: any use of this value will cause an error - --> $DIR/const-eval-overflow2c.rs:56:6 + --> $DIR/const-eval-overflow2c.rs:54:6 | LL | / const VALS_U64: (u64,) = LL | | ( diff --git a/src/test/ui/consts/const-eval/dangling.rs b/src/test/ui/consts/const-eval/dangling.rs index 78cf000db0..72e97c0322 100644 --- a/src/test/ui/consts/const-eval/dangling.rs +++ b/src/test/ui/consts/const-eval/dangling.rs @@ -1,6 +1,6 @@ #![feature(const_raw_ptr_deref)] -use std::{mem, usize}; +use std::mem; // Make sure we error with the right kind of error on a too large slice. const TEST: () = { unsafe { //~ NOTE diff --git a/src/test/ui/consts/const-eval/erroneous-const.rs b/src/test/ui/consts/const-eval/erroneous-const.rs index 3df491bf22..16bf1adf7d 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.rs +++ b/src/test/ui/consts/const-eval/erroneous-const.rs @@ -9,11 +9,11 @@ impl PrintName { const fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR evaluation of constant value failed + let _ = PrintName::::VOID; //~ERROR could not evaluate static initializer } } -pub static FOO: () = no_codegen::(); //~ERROR could not evaluate static initializer +pub static FOO: () = no_codegen::(); fn main() { FOO diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr index 7087a6f668..040cc3fcf7 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.stderr +++ b/src/test/ui/consts/const-eval/erroneous-const.stderr @@ -24,18 +24,18 @@ note: the lint level is defined here LL | #![warn(const_err, unconditional_panic)] | ^^^^^^^^^ -error[E0080]: evaluation of constant value failed +error[E0080]: could not evaluate static initializer --> $DIR/erroneous-const.rs:12:17 | LL | let _ = PrintName::::VOID; - | ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors - -error[E0080]: could not evaluate static initializer - --> $DIR/erroneous-const.rs:16:22 - | + | ^^^^^^^^^^^^^^^^^^^^ + | | + | referenced constant has errors + | inside `no_codegen::` at $DIR/erroneous-const.rs:12:17 +... LL | pub static FOO: () = no_codegen::(); - | ^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | ------------------- inside `FOO` at $DIR/erroneous-const.rs:16:22 -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs new file mode 100644 index 0000000000..0d809ca9a6 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -0,0 +1,17 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); +const fn foo() -> i32 { + unsafe { + let _ = intrinsics::const_allocate(4, 3) as * mut i32; + //~^ error: any use of this value will cause an error [const_err] + } + 1 + +} + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr new file mode 100644 index 0000000000..41c1b97726 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -0,0 +1,17 @@ +error: any use of this value will cause an error + --> $DIR/alloc_intrinsic_errors.rs:10:17 + | +LL | const FOO: i32 = foo(); + | ----------------------- +... +LL | let _ = intrinsics::const_allocate(4, 3) as * mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | align has to be a power of 2, `3` is not a power of 2 + | inside `foo` at $DIR/alloc_intrinsic_errors.rs:10:17 + | inside `FOO` at $DIR/alloc_intrinsic_errors.rs:7:18 + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs new file mode 100644 index 0000000000..de7fb65f68 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: &i32 = foo(); + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { + assert_eq!(*FOO, 20) +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs new file mode 100644 index 0000000000..e6ef9974aa --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs @@ -0,0 +1,19 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: *const i32 = foo(); +//~^ ERROR untyped pointers are not allowed in constant + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr new file mode 100644 index 0000000000..08679350d6 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_nontransient_fail.rs:7:1 + | +LL | const FOO: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs new file mode 100644 index 0000000000..c55cd32d26 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); + +const fn foo() -> i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { *t } +} +fn main() { + assert_eq!(FOO, 20); +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs new file mode 100644 index 0000000000..998b6cef84 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -0,0 +1,10 @@ +// compile-test +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +//~^ error: it is undefined behavior to use this value +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr new file mode 100644 index 0000000000..866f877f54 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr @@ -0,0 +1,11 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc_intrinsic_uninit.rs:8:1 + | +LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at ., but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs new file mode 100644 index 0000000000..625f7670bc --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -0,0 +1,10 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; +//~^ error: untyped pointers are not allowed in constant + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr new file mode 100644 index 0000000000..ee84f8e54f --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_untyped.rs:7:1 + | +LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/issue-52442.rs b/src/test/ui/consts/const-eval/issue-52442.rs index ea24578c7d..159b48d42b 100644 --- a/src/test/ui/consts/const-eval/issue-52442.rs +++ b/src/test/ui/consts/const-eval/issue-52442.rs @@ -1,5 +1,4 @@ fn main() { [(); { &loop { break } as *const _ as usize } ]; //~^ ERROR casting pointers to integers in constants is unstable - //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index 53a87837e1..2a8f34279c 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -7,13 +7,6 @@ LL | [(); { &loop { break } as *const _ as usize } ]; = note: see issue #51910 for more information = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0080]: evaluation of constant value failed - --> $DIR/issue-52442.rs:2:13 - | -LL | [(); { &loop { break } as *const _ as usize } ]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0080, E0658. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs index f6b5ad005a..d980eb92a2 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs @@ -5,7 +5,6 @@ fn main() { let _: [u8; 0] = [4; { match &1 as *const i32 as usize { //~^ ERROR casting pointers to integers in constants - //~| ERROR evaluation of constant value failed 0 => 42, n => n, } diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr index 48dbe66149..22d6bb1694 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr @@ -7,13 +7,6 @@ LL | match &1 as *const i32 as usize { = note: see issue #51910 for more information = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0080]: evaluation of constant value failed - --> $DIR/match-test-ptr-null.rs:6:15 - | -LL | match &1 as *const i32 as usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0080, E0658. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs index b8b95dea1e..2dc8e14bed 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.rs +++ b/src/test/ui/consts/const-eval/unwind-abort.rs @@ -2,10 +2,10 @@ #[unwind(aborts)] const fn foo() { - panic!() //~ evaluation of constant value failed + panic!() //~ ERROR any use of this value will cause an error [const_err] } -const _: () = foo(); //~ any use of this value will cause an error +const _: () = foo(); // Ensure that the CTFE engine handles calls to `#[unwind(aborts)]` gracefully fn main() { diff --git a/src/test/ui/consts/const-eval/unwind-abort.stderr b/src/test/ui/consts/const-eval/unwind-abort.stderr index 084beb19eb..eee1a35a0d 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.stderr +++ b/src/test/ui/consts/const-eval/unwind-abort.stderr @@ -1,21 +1,18 @@ -error[E0080]: evaluation of constant value failed +error: any use of this value will cause an error --> $DIR/unwind-abort.rs:5:5 | LL | panic!() - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5 - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: any use of this value will cause an error - --> $DIR/unwind-abort.rs:8:15 - | + | ^^^^^^^^ + | | + | the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5 + | inside `foo` at $SRC_DIR/std/src/macros.rs:LL:COL + | inside `_` at $DIR/unwind-abort.rs:8:15 +... LL | const _: () = foo(); - | --------------^^^^^- - | | - | referenced constant has errors + | -------------------- | = note: `#[deny(const_err)]` on by default + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-fn-feature-flags.rs b/src/test/ui/consts/const-fn-feature-flags.rs deleted file mode 100644 index 30e7e102b8..0000000000 --- a/src/test/ui/consts/const-fn-feature-flags.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass -// Test use of stabilized const fns in std formerly using individual feature gates. - -use std::cell::Cell; - -const CELL: Cell = Cell::new(42); - -fn main() { - let v = CELL.get(); - CELL.set(v+1); - - assert_eq!(CELL.get(), v); -} diff --git a/src/test/ui/consts/const-int-arithmetic.rs b/src/test/ui/consts/const-int-arithmetic.rs index 9b2e30961a..e0d722ede9 100644 --- a/src/test/ui/consts/const-int-arithmetic.rs +++ b/src/test/ui/consts/const-int-arithmetic.rs @@ -5,8 +5,6 @@ #![feature(const_overflowing_int_methods)] #![feature(const_wrapping_int_methods)] -use std::{i8, i128}; - macro_rules! suite { ($( $fn:ident -> $ty:ty { $( $label:ident : $expr:expr, $result:expr; )* } diff --git a/src/test/ui/consts/const-int-overflowing-rpass.rs b/src/test/ui/consts/const-int-overflowing-rpass.rs index eecb88beca..75e77fdf1b 100644 --- a/src/test/ui/consts/const-int-overflowing-rpass.rs +++ b/src/test/ui/consts/const-int-overflowing-rpass.rs @@ -16,7 +16,7 @@ const SHR_A: (u32, bool) = 0x10u32.overflowing_shr(4); const SHR_B: (u32, bool) = 0x10u32.overflowing_shr(132); const NEG_A: (u32, bool) = 0u32.overflowing_neg(); -const NEG_B: (u32, bool) = core::u32::MAX.overflowing_neg(); +const NEG_B: (u32, bool) = u32::MAX.overflowing_neg(); const ABS_POS: (i32, bool) = 10i32.overflowing_abs(); const ABS_NEG: (i32, bool) = (-10i32).overflowing_abs(); diff --git a/src/test/ui/consts/const-int-pow-rpass.rs b/src/test/ui/consts/const-int-pow-rpass.rs index 4f936236db..30bcb78bcf 100644 --- a/src/test/ui/consts/const-int-pow-rpass.rs +++ b/src/test/ui/consts/const-int-pow-rpass.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(const_int_pow)] #![feature(wrapping_next_power_of_two)] const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two(); diff --git a/src/test/ui/consts/const-negation.rs b/src/test/ui/consts/const-negation.rs index 1c8e27ae61..26c3c0b836 100644 --- a/src/test/ui/consts/const-negation.rs +++ b/src/test/ui/consts/const-negation.rs @@ -8,19 +8,19 @@ fn main() { const I: isize = -2147483648isize; #[cfg(target_pointer_width = "64")] const I: isize = -9223372036854775808isize; - assert_eq!(::std::i32::MIN as u64, 0xffffffff80000000); + assert_eq!(i32::MIN as u64, 0xffffffff80000000); assert_eq!(-2147483648isize as u64, 0xffffffff80000000); assert_eq!(-2147483648i32 as u64, 0xffffffff80000000); - assert_eq!(::std::i64::MIN as u64, 0x8000000000000000); + assert_eq!(i64::MIN as u64, 0x8000000000000000); #[cfg(target_pointer_width = "64")] assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000); #[cfg(target_pointer_width = "32")] assert_eq!(-9223372036854775808isize as u64, 0); assert_eq!(-9223372036854775808i32 as u64, 0); - const J: usize = ::std::i32::MAX as usize; + const J: usize = i32::MAX as usize; const K: usize = -1i32 as u32 as usize; - const L: usize = ::std::i32::MIN as usize; - const M: usize = ::std::i64::MIN as usize; + const L: usize = i32::MIN as usize; + const M: usize = i64::MIN as usize; match 5 { J => {}, K => {}, diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 42e2749b20..129457ebdf 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -14,16 +14,6 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`.. | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `std::mem::size_of`... - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - | -LL | pub const fn size_of() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `std::intrinsics::size_of`... - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL - | -LL | pub fn size_of() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle diff --git a/src/test/ui/consts/const-str-ptr.rs b/src/test/ui/consts/const-str-ptr.rs deleted file mode 100644 index 56fd9d9f55..0000000000 --- a/src/test/ui/consts/const-str-ptr.rs +++ /dev/null @@ -1,17 +0,0 @@ -// run-pass -#![allow(unused_imports)] -use std::{str, string}; - -const A: [u8; 2] = ['h' as u8, 'i' as u8]; -const B: &'static [u8; 2] = &A; -const C: *const u8 = B as *const u8; - -pub fn main() { - unsafe { - let foo = &A as *const u8; - assert_eq!(foo, C); - assert_eq!(str::from_utf8_unchecked(&A), "hi"); - assert_eq!(*C, A[0]); - assert_eq!(*(&B[0] as *const u8), A[0]); - } -} diff --git a/src/test/ui/consts/issue-63952.rs b/src/test/ui/consts/issue-63952.rs index 35cbc7003f..f50e1e51f6 100644 --- a/src/test/ui/consts/issue-63952.rs +++ b/src/test/ui/consts/issue-63952.rs @@ -1,7 +1,5 @@ // Regression test for #63952, shouldn't hang. -use std::usize; - #[repr(C)] #[derive(Copy, Clone)] struct SliceRepr { diff --git a/src/test/ui/consts/issue-63952.stderr b/src/test/ui/consts/issue-63952.stderr index 5e85be45b1..503c5706fa 100644 --- a/src/test/ui/consts/issue-63952.stderr +++ b/src/test/ui/consts/issue-63952.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/issue-63952.rs:18:1 + --> $DIR/issue-63952.rs:16:1 | LL | / const SLICE_WAY_TOO_LONG: &[u8] = unsafe { LL | | SliceTransmute { diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.rs b/src/test/ui/consts/issue-68542-closure-in-array-len.rs index 2e721b8533..d77fd9aa83 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.rs +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.rs @@ -4,7 +4,6 @@ struct Bug { a: [(); (|| { 0 })()] //~ ERROR calls in constants are limited to - //~^ ERROR evaluation of constant value failed } fn main() {} diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr index 8c839f94e3..74d70e18a2 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr @@ -4,13 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | a: [(); (|| { 0 })()] | ^^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/issue-68542-closure-in-array-len.rs:6:13 - | -LL | a: [(); (|| { 0 })()] - | ^^^^^^^^^^^^ calling non-const function `Bug::a::{constant#0}::{closure#0}` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/issue-76064.rs b/src/test/ui/consts/issue-76064.rs new file mode 100644 index 0000000000..2da764b47c --- /dev/null +++ b/src/test/ui/consts/issue-76064.rs @@ -0,0 +1,3 @@ +struct Bug([u8; panic!(1)]); //~ ERROR panicking in constants is unstable + +fn main() {} diff --git a/src/test/ui/consts/issue-76064.stderr b/src/test/ui/consts/issue-76064.stderr new file mode 100644 index 0000000000..f939ff3397 --- /dev/null +++ b/src/test/ui/consts/issue-76064.stderr @@ -0,0 +1,13 @@ +error[E0658]: panicking in constants is unstable + --> $DIR/issue-76064.rs:1:17 + | +LL | struct Bug([u8; panic!(1)]); + | ^^^^^^^^^ + | + = note: see issue #51999 for more information + = help: add `#![feature(const_panic)]` to the crate attributes to enable + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/issue-79137-monomorphic.rs b/src/test/ui/consts/issue-79137-monomorphic.rs new file mode 100644 index 0000000000..58e0c387ff --- /dev/null +++ b/src/test/ui/consts/issue-79137-monomorphic.rs @@ -0,0 +1,19 @@ +// check-pass + +// Verify that variant count intrinsic can still evaluate for types like `Option`. + +#![feature(variant_count)] + +pub struct GetVariantCount(T); + +impl GetVariantCount { + pub const VALUE: usize = std::mem::variant_count::(); +} + +const fn check_variant_count() -> bool { + matches!(GetVariantCount::>::VALUE, GetVariantCount::>::VALUE) +} + +fn main() { + assert!(check_variant_count::<()>()); +} diff --git a/src/test/ui/consts/issue-79137-toogeneric.rs b/src/test/ui/consts/issue-79137-toogeneric.rs new file mode 100644 index 0000000000..456035458c --- /dev/null +++ b/src/test/ui/consts/issue-79137-toogeneric.rs @@ -0,0 +1,19 @@ +// Test that `variant_count` only gets evaluated once the type is concrete enough. + +#![feature(variant_count)] + +pub struct GetVariantCount(T); + +impl GetVariantCount { + pub const VALUE: usize = std::mem::variant_count::(); +} + +const fn check_variant_count() -> bool { + matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE) + //~^ ERROR constant pattern depends on a generic parameter + //~| ERROR constant pattern depends on a generic parameter +} + +fn main() { + assert!(check_variant_count::>()); +} diff --git a/src/test/ui/consts/issue-79137-toogeneric.stderr b/src/test/ui/consts/issue-79137-toogeneric.stderr new file mode 100644 index 0000000000..579e6aa09b --- /dev/null +++ b/src/test/ui/consts/issue-79137-toogeneric.stderr @@ -0,0 +1,14 @@ +error: constant pattern depends on a generic parameter + --> $DIR/issue-79137-toogeneric.rs:12:43 + | +LL | matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: constant pattern depends on a generic parameter + --> $DIR/issue-79137-toogeneric.rs:12:43 + | +LL | matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/issue-79152-const-array-index.rs b/src/test/ui/consts/issue-79152-const-array-index.rs new file mode 100644 index 0000000000..95518e1bbd --- /dev/null +++ b/src/test/ui/consts/issue-79152-const-array-index.rs @@ -0,0 +1,11 @@ +// check-pass +// Regression test for issue #79152 +// +// Tests that we can index an array in a const function + +const fn foo() { + let mut array = [[0; 1]; 1]; + array[0][0] = 1; +} + +fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 52662ef9ea..b65e50eb9f 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -146,6 +146,11 @@ help: skipping check that does not even have a feature gate | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:32:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check for `const_panic` feature --> $DIR/const_refers_to_static_cross_crate.rs:32:77 | diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs index 30bb9917bf..1e4d8586b8 100644 --- a/src/test/ui/consts/promote-not.rs +++ b/src/test/ui/consts/promote-not.rs @@ -3,6 +3,8 @@ #![allow(unconditional_panic, const_err)] #![feature(const_fn, const_fn_union)] +use std::cell::Cell; + // We do not promote mutable references. static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed @@ -32,4 +34,14 @@ const TEST_UNION: () = { let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed }; -fn main() {} +// In a `const`, we do not promote things with interior mutability. Not even if we "project it away". +const TEST_INTERIOR_MUT: () = { + // The "0." case is already ruled out by not permitting any interior mutability in `const`. + let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed +}; + +fn main() { + // We must not promote things with interior mutability. Not even if we "project it away". + let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed +} diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr index 6ca7a4c273..6e76d9ee6c 100644 --- a/src/test/ui/consts/promote-not.stderr +++ b/src/test/ui/consts/promote-not.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:7:50 + --> $DIR/promote-not.rs:9:50 | LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | ----------^^^^^^^^^- @@ -9,7 +9,7 @@ LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:10:18 + --> $DIR/promote-not.rs:12:18 | LL | let x = &mut [1,2,3]; | ^^^^^^^ creates a temporary which is freed while still in use @@ -19,7 +19,7 @@ LL | }; | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:19:32 + --> $DIR/promote-not.rs:21:32 | LL | let _x: &'static () = &foo(); | ----------- ^^^^^ creates a temporary which is freed while still in use @@ -29,7 +29,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:27:29 + --> $DIR/promote-not.rs:29:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use @@ -39,7 +39,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:32:29 + --> $DIR/promote-not.rs:34:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use @@ -48,6 +48,37 @@ LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; LL | }; | - temporary value is freed at the end of this statement -error: aborting due to 5 previous errors +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:40:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).1; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:45:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).0; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let _val: &'static _ = &(Cell::new(1), 2).1; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:46:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).1; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/promote_fn_calls_std.rs b/src/test/ui/consts/promote_fn_calls_std.rs index bdb472f3a9..557f6a434f 100644 --- a/src/test/ui/consts/promote_fn_calls_std.rs +++ b/src/test/ui/consts/promote_fn_calls_std.rs @@ -1,3 +1,4 @@ +#![allow(deprecated, deprecated_in_future)] // can be removed if different fns are chosen // build-pass (FIXME(62277): could be check-pass?) fn main() { diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index 5f84030a9e..e6f5c3d27c 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -13,5 +13,5 @@ fn main() { // make sure that these do not cause trouble despite overflowing baz_u32(&(0-1)); - baz_i32(&-std::i32::MIN); + baz_i32(&-i32::MIN); } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs new file mode 100644 index 0000000000..65d02317d3 --- /dev/null +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-repeat.rs @@ -0,0 +1,27 @@ +// run-pass + +// Repeating a *constant* of non-Copy type (not just a constant expression) is already stable. + +const EMPTY: Vec = Vec::new(); + +pub fn bar() -> [Vec; 2] { + [EMPTY; 2] +} + +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + panic!("BOOM!"); + } +} + +const BOOM: Bomb = Bomb; + +fn main() { + let _x = bar(); + + // Make sure the destructor does not get called for empty arrays. `[CONST; N]` should + // instantiate (and then later drop) the const exactly `N` times. + let _x = [BOOM; 0]; +} diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs index 15436f9c1b..2f4b7578d1 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.rs +++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs @@ -1,15 +1,15 @@ // build-fail pub const unsafe fn fake_type() -> T { - hint_unreachable() + hint_unreachable() //~ ERROR any use of this value will cause an error [const_err] } pub const unsafe fn hint_unreachable() -> ! { - fake_type() //~ ERROR evaluation of constant value failed + fake_type() } trait Const { - const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR any use of this value will cause an err + const CONSTANT: i32 = unsafe { fake_type() }; } impl Const for T {} diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr index 024f9782d4..1fb5ac11df 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr +++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr @@ -1,150 +1,141 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/uninhabited-const-issue-61744.rs:8:5 +error: any use of this value will cause an error + --> $DIR/uninhabited-const-issue-61744.rs:4:5 | LL | hint_unreachable() - | ------------------ + | ^^^^^^^^^^^^^^^^^^ | | + | reached the configured maximum number of stack frames | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `::CONSTANT` at $DIR/uninhabited-const-issue-61744.rs:12:36 ... -LL | fake_type() - | ^^^^^^^^^^^ - | | - | reached the configured maximum number of stack frames - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - -error: any use of this value will cause an error - --> $DIR/uninhabited-const-issue-61744.rs:12:36 - | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | -------------------------------^^^^^^^^^^^--- - | | - | referenced constant has errors + | --------------------------------------------- | = note: `#[deny(const_err)]` on by default @@ -154,6 +145,6 @@ error[E0080]: erroneous constant used LL | dbg!(i32::CONSTANT); | ^^^^^^^^^^^^^ referenced constant has errors -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/core-run-destroy.rs b/src/test/ui/core-run-destroy.rs index b3614bfd5b..5fd418e6c8 100644 --- a/src/test/ui/core-run-destroy.rs +++ b/src/test/ui/core-run-destroy.rs @@ -5,7 +5,6 @@ #![allow(deprecated)] #![allow(unused_imports)] // compile-flags:--test -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes // ignore-vxworks no 'cat' and 'sleep' diff --git a/src/test/ui/cross/cross-file-errors/main.rs b/src/test/ui/cross/cross-file-errors/main.rs index 74e9461803..1902ab94d4 100644 --- a/src/test/ui/cross/cross-file-errors/main.rs +++ b/src/test/ui/cross/cross-file-errors/main.rs @@ -3,5 +3,6 @@ mod underscore; fn main() { underscore!(); - //~^ ERROR expected expression, found reserved identifier `_` + //~^ ERROR `_` can only be used on the left-hand side of an assignment + //~| ERROR destructuring assignments are unstable } diff --git a/src/test/ui/cross/cross-file-errors/main.stderr b/src/test/ui/cross/cross-file-errors/main.stderr index f9101d8a58..b865874506 100644 --- a/src/test/ui/cross/cross-file-errors/main.stderr +++ b/src/test/ui/cross/cross-file-errors/main.stderr @@ -1,15 +1,31 @@ -error: expected expression, found reserved identifier `_` +error[E0658]: destructuring assignments are unstable --> $DIR/underscore.rs:8:9 | LL | _ - | ^ expected expression + | ^ | ::: $DIR/main.rs:5:5 | LL | underscore!(); | -------------- in this macro invocation | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/underscore.rs:8:9 + | +LL | _ + | ^ `_` not allowed here + | + ::: $DIR/main.rs:5:5 + | +LL | underscore!(); + | -------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/default-alloc-error-hook.rs b/src/test/ui/default-alloc-error-hook.rs index 6871977c79..100e974977 100644 --- a/src/test/ui/default-alloc-error-hook.rs +++ b/src/test/ui/default-alloc-error-hook.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.rs b/src/test/ui/deprecation/rustc_deprecation-in-future.rs index 6a619bcc49..11f7960b75 100644 --- a/src/test/ui/deprecation/rustc_deprecation-in-future.rs +++ b/src/test/ui/deprecation/rustc_deprecation-in-future.rs @@ -8,8 +8,13 @@ #[rustc_deprecated(since = "99.99.99", reason = "effectively never")] #[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] -pub struct S; +pub struct S1; + +#[rustc_deprecated(since = "TBD", reason = "literally never")] +#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] +pub struct S2; fn main() { - let _ = S; //~ ERROR use of unit struct `S` that will be deprecated in future version 99.99.99: effectively never + let _ = S1; //~ ERROR use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never + let _ = S2; //~ ERROR use of unit struct `S2` that will be deprecated in a future Rust version: literally never } diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr index e4f50d10da..b5a7dd3c28 100644 --- a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr +++ b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr @@ -1,8 +1,8 @@ -error: use of unit struct `S` that will be deprecated in future version 99.99.99: effectively never - --> $DIR/rustc_deprecation-in-future.rs:14:13 +error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never + --> $DIR/rustc_deprecation-in-future.rs:18:13 | -LL | let _ = S; - | ^ +LL | let _ = S1; + | ^^ | note: the lint level is defined here --> $DIR/rustc_deprecation-in-future.rs:3:9 @@ -10,5 +10,11 @@ note: the lint level is defined here LL | #![deny(deprecated_in_future)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never + --> $DIR/rustc_deprecation-in-future.rs:19:13 + | +LL | let _ = S2; + | ^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/deref-mut-on-ref.rs b/src/test/ui/deref-mut-on-ref.rs deleted file mode 100644 index a6df5495a2..0000000000 --- a/src/test/ui/deref-mut-on-ref.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass -// Test that `&mut T` implements `DerefMut` - - -use std::ops::{Deref, DerefMut}; - -fn inc + DerefMut>(mut t: T) { - *t += 1; -} - -fn main() { - let mut x: isize = 5; - inc(&mut x); - assert_eq!(x, 6); -} diff --git a/src/test/ui/deref-on-ref.rs b/src/test/ui/deref-on-ref.rs deleted file mode 100644 index 973e61c9d5..0000000000 --- a/src/test/ui/deref-on-ref.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// Test that `&T` and `&mut T` implement `Deref` - - -use std::ops::Deref; - -fn deref>(t: T) -> U { - *t -} - -fn main() { - let x: isize = 3; - let y = deref(&x); - assert_eq!(y, 3); - - let mut x: isize = 4; - let y = deref(&mut x); - assert_eq!(y, 4); -} diff --git a/src/test/ui/issues/issue-36617.rs b/src/test/ui/derives/issue-36617.rs similarity index 68% rename from src/test/ui/issues/issue-36617.rs rename to src/test/ui/derives/issue-36617.rs index 58f44f4252..1102f3c464 100644 --- a/src/test/ui/issues/issue-36617.rs +++ b/src/test/ui/derives/issue-36617.rs @@ -1,5 +1,4 @@ #![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions //~| ERROR cannot determine resolution for the derive macro `Copy` - //~| ERROR cannot determine resolution for the derive macro `Copy` fn main() {} diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/derives/issue-36617.stderr similarity index 65% rename from src/test/ui/issues/issue-36617.stderr rename to src/test/ui/derives/issue-36617.stderr index 586dcf2cea..dc6ef16925 100644 --- a/src/test/ui/issues/issue-36617.stderr +++ b/src/test/ui/derives/issue-36617.stderr @@ -12,14 +12,6 @@ LL | #![derive(Copy)] | = note: import resolution is stuck, try simplifying macro imports -error: cannot determine resolution for the derive macro `Copy` - --> $DIR/issue-36617.rs:1:11 - | -LL | #![derive(Copy)] - | ^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/destructuring-assignment/drop-order.rs b/src/test/ui/destructuring-assignment/drop-order.rs new file mode 100644 index 0000000000..d06b31c7f2 --- /dev/null +++ b/src/test/ui/destructuring-assignment/drop-order.rs @@ -0,0 +1,44 @@ +// run-pass + +//! Test that let bindings and destructuring assignments have consistent drop orders + +#![feature(destructuring_assignment)] +#![allow(unused_variables, unused_assignments)] + +use std::cell::RefCell; + +thread_local! { + static DROP_ORDER: RefCell> = RefCell::new(Vec::new()); +} + +struct DropRecorder(usize); +impl Drop for DropRecorder { + fn drop(&mut self) { + DROP_ORDER.with(|d| d.borrow_mut().push(self.0)); + } +} + +fn main() { + let expected_drop_order = vec![1, 4, 5, 3, 2]; + // Check the drop order for let bindings: + { + let _ = DropRecorder(1); + let _val = DropRecorder(2); + let (x, _) = (DropRecorder(3), DropRecorder(4)); + drop(DropRecorder(5)); + } + DROP_ORDER.with(|d| { + assert_eq!(&*d.borrow(), &expected_drop_order); + d.borrow_mut().clear(); + }); + // Check that the drop order for destructuring assignment is the same: + { + let _val; + let x; + _ = DropRecorder(1); + _val = DropRecorder(2); + (x, _) = (DropRecorder(3), DropRecorder(4)); + drop(DropRecorder(5)); + } + DROP_ORDER.with(|d| assert_eq!(&*d.borrow(), &expected_drop_order)); +} diff --git a/src/test/ui/destructuring-assignment/nested_destructure.rs b/src/test/ui/destructuring-assignment/nested_destructure.rs index 393dfc16c0..0d45ff7da7 100644 --- a/src/test/ui/destructuring-assignment/nested_destructure.rs +++ b/src/test/ui/destructuring-assignment/nested_destructure.rs @@ -14,4 +14,7 @@ fn main() { Struct { a: TupleStruct((a, b), c), b: [d] } = Struct { a: TupleStruct((0, 1), 2), b: [3] }; assert_eq!((a, b, c, d), (0, 1, 2, 3)); + + // unnested underscore: just discard + _ = 1; } diff --git a/src/test/ui/destructuring-assignment/slice_destructure.rs b/src/test/ui/destructuring-assignment/slice_destructure.rs index 3dd10aff19..76cdc1260f 100644 --- a/src/test/ui/destructuring-assignment/slice_destructure.rs +++ b/src/test/ui/destructuring-assignment/slice_destructure.rs @@ -9,6 +9,8 @@ fn main() { let mut c; [a, .., b, c] = [1, 2, 3, 4, 5]; assert_eq!((a, b, c), (1, 4, 5)); + [_, a, _] = [1, 2, 3]; + assert_eq!((a, b), (2, 4)); [..] = [1, 2, 3]; [c, ..] = [5, 6, 6]; assert_eq!(c, 5); diff --git a/src/test/ui/destructuring-assignment/slice_destructure_fail.rs b/src/test/ui/destructuring-assignment/slice_destructure_fail.rs index f636ea3511..90d93892f7 100644 --- a/src/test/ui/destructuring-assignment/slice_destructure_fail.rs +++ b/src/test/ui/destructuring-assignment/slice_destructure_fail.rs @@ -4,4 +4,5 @@ fn main() { let (mut a, mut b); [a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern [a, a, b] = [1, 2]; //~ ERROR pattern requires 3 elements but array has 2 + [_] = [1, 2]; //~ ERROR pattern requires 1 element but array has 2 } diff --git a/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr b/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr index 728687deb8..cc412c72df 100644 --- a/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr @@ -12,6 +12,12 @@ error[E0527]: pattern requires 3 elements but array has 2 LL | [a, a, b] = [1, 2]; | ^^^^^^^^^ expected 2 elements -error: aborting due to 2 previous errors +error[E0527]: pattern requires 1 element but array has 2 + --> $DIR/slice_destructure_fail.rs:7:3 + | +LL | [_] = [1, 2]; + | ^^^ expected 2 elements + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0527`. diff --git a/src/test/ui/destructuring-assignment/struct_destructure.rs b/src/test/ui/destructuring-assignment/struct_destructure.rs index b3a96ee157..2bcbd9d0d7 100644 --- a/src/test/ui/destructuring-assignment/struct_destructure.rs +++ b/src/test/ui/destructuring-assignment/struct_destructure.rs @@ -12,8 +12,10 @@ fn main() { assert_eq!((a, b), (0, 1)); Struct { a: b, b: a } = Struct { a: 1, b: 2 }; assert_eq!((a,b), (2, 1)); + Struct { a: _, b } = Struct { a: 1, b: 2 }; + assert_eq!((a, b), (2, 2)); Struct { a, .. } = Struct { a: 1, b: 3 }; - assert_eq!((a, b), (1, 1)); + assert_eq!((a, b), (1, 2)); Struct { .. } = Struct { a: 1, b: 4 }; - assert_eq!((a, b), (1, 1)); + assert_eq!((a, b), (1, 2)); } diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.rs b/src/test/ui/destructuring-assignment/struct_destructure_fail.rs index c22695ed38..4aa327b61f 100644 --- a/src/test/ui/destructuring-assignment/struct_destructure_fail.rs +++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.rs @@ -9,6 +9,8 @@ fn main() { let mut c; let d = Struct { a: 0, b: 1 }; Struct { a, b, c } = Struct { a: 0, b: 1 }; //~ ERROR does not have a field named `c` + Struct { a, _ } = Struct { a: 1, b: 2 }; //~ ERROR pattern does not mention field `b` + //~| ERROR expected identifier, found reserved identifier `_` Struct { a, ..d } = Struct { a: 1, b: 2 }; //~^ ERROR functional record updates are not allowed in destructuring assignments Struct { a, .. }; //~ ERROR base expression required after `..` diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr index 4da4698804..81661a357e 100644 --- a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr @@ -1,11 +1,19 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/struct_destructure_fail.rs:12:17 + | +LL | Struct { a, _ } = Struct { a: 1, b: 2 }; + | ------ ^ expected identifier, found reserved identifier + | | + | while parsing this struct + error: functional record updates are not allowed in destructuring assignments - --> $DIR/struct_destructure_fail.rs:12:19 + --> $DIR/struct_destructure_fail.rs:14:19 | LL | Struct { a, ..d } = Struct { a: 1, b: 2 }; | ^ help: consider removing the trailing pattern error: base expression required after `..` - --> $DIR/struct_destructure_fail.rs:14:19 + --> $DIR/struct_destructure_fail.rs:16:19 | LL | Struct { a, .. }; | ^ add a base expression here @@ -16,6 +24,22 @@ error[E0026]: struct `Struct` does not have a field named `c` LL | Struct { a, b, c } = Struct { a: 0, b: 1 }; | ^ struct `Struct` does not have this field -error: aborting due to 3 previous errors +error[E0027]: pattern does not mention field `b` + --> $DIR/struct_destructure_fail.rs:12:5 + | +LL | Struct { a, _ } = Struct { a: 1, b: 2 }; + | ^^^^^^^^^^^^^^^ missing field `b` + | +help: include the missing field in the pattern + | +LL | Struct { a, b, _ } = Struct { a: 1, b: 2 }; + | ^^^ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | Struct { a, .., _ } = Struct { a: 1, b: 2 }; + | ^^^^ + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0026`. +Some errors have detailed explanations: E0026, E0027. +For more information about an error, try `rustc --explain E0026`. diff --git a/src/test/ui/destructuring-assignment/tuple_destructure.rs b/src/test/ui/destructuring-assignment/tuple_destructure.rs index 16aafc4693..2096182d42 100644 --- a/src/test/ui/destructuring-assignment/tuple_destructure.rs +++ b/src/test/ui/destructuring-assignment/tuple_destructure.rs @@ -16,6 +16,8 @@ fn main() { assert_eq!((a, b), (2, 2)); (b, ..) = (5, 6, 7); assert_eq!(b, 5); + (a, _) = (8, 9); + assert_eq!(a, 8); // Test for a non-Copy type (String): let (mut c, mut d); diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs index b76f4968e6..5524e91dc4 100644 --- a/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs +++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs @@ -7,4 +7,5 @@ fn main() { (a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern (a, a, b) = (1, 2); //~ ERROR mismatched types (C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment + (_,) = (1, 2); //~ ERROR mismatched types } diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr index a60e1cb1ee..1146b88278 100644 --- a/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr @@ -25,7 +25,18 @@ LL | (C, ..) = (0,1); | | | cannot assign to this expression -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/tuple_destructure_fail.rs:10:5 + | +LL | (_,) = (1, 2); + | ^^^^ ------ this expression has type `({integer}, {integer})` + | | + | expected a tuple with 2 elements, found one with 1 element + | + = note: expected type `({integer}, {integer})` + found tuple `(_,)` + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0070, E0308. For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs b/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs index 106a9b16db..7b5c5ad2ba 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs @@ -23,8 +23,10 @@ fn main() { assert_eq!((a, b), (0, 1)); TupleStruct(a, .., b) = TupleStruct(1, 2); assert_eq!((a, b), (1, 2)); + TupleStruct(_, a) = TupleStruct(2, 2); + assert_eq!((a, b), (2, 2)); TupleStruct(..) = TupleStruct(3, 4); - assert_eq!((a, b), (1, 2)); + assert_eq!((a, b), (2, 2)); TupleStruct(5,6).assign(&mut a, &mut b); assert_eq!((a, b), (5, 6)); Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8); diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs index 61ae42a517..c39db06117 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs @@ -29,8 +29,12 @@ fn main() { TupleStruct(a, a, b) = TupleStruct(1, 2); //~^ ERROR this pattern has 3 fields, but the corresponding tuple struct has 2 fields + TupleStruct(_) = TupleStruct(1, 2); + //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2); //~^ ERROR this pattern has 3 fields, but the corresponding tuple variant has 2 fields + Enum::SingleVariant(_) = Enum::SingleVariant(1, 2); + //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields // Check if `test` is recognized as not a tuple struct but a function call: test() = TupleStruct(0, 0); diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index 863eedecf7..0e7174e5b1 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -23,17 +23,35 @@ LL | struct TupleStruct(S, T); LL | TupleStruct(a, a, b) = TupleStruct(1, 2); | ^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3 -error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields --> $DIR/tuple_struct_destructure_fail.rs:32:5 | +LL | struct TupleStruct(S, T); + | ------------------------------- tuple struct defined here +... +LL | TupleStruct(_) = TupleStruct(1, 2); + | ^^^^^^^^^^^^^^ expected 2 fields, found 1 + +error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields + --> $DIR/tuple_struct_destructure_fail.rs:34:5 + | LL | SingleVariant(S, T) | ------------------- tuple variant defined here ... LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3 +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/tuple_struct_destructure_fail.rs:36:5 + | +LL | SingleVariant(S, T) + | ------------------- tuple variant defined here +... +LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1 + error[E0070]: invalid left-hand side of assignment - --> $DIR/tuple_struct_destructure_fail.rs:36:12 + --> $DIR/tuple_struct_destructure_fail.rs:40:12 | LL | test() = TupleStruct(0, 0); | ------ ^ @@ -41,7 +59,7 @@ LL | test() = TupleStruct(0, 0); | cannot assign to this expression error[E0070]: invalid left-hand side of assignment - --> $DIR/tuple_struct_destructure_fail.rs:38:14 + --> $DIR/tuple_struct_destructure_fail.rs:42:14 | LL | (test)() = TupleStruct(0, 0); | -------- ^ @@ -49,14 +67,14 @@ LL | (test)() = TupleStruct(0, 0); | cannot assign to this expression error[E0070]: invalid left-hand side of assignment - --> $DIR/tuple_struct_destructure_fail.rs:40:38 + --> $DIR/tuple_struct_destructure_fail.rs:44:38 | LL | as Test>::test() = TupleStruct(0, 0); | -------------------------------- ^ | | | cannot assign to this expression -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0023, E0070. For more information about an error, try `rustc --explain E0023`. diff --git a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs b/src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs index b41f2f52a3..4ed4f56702 100644 --- a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs +++ b/src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs @@ -4,5 +4,7 @@ struct S { x : u32 } #[cfg(FALSE)] fn foo() { + _; //~ ERROR destructuring assignments are unstable + S { x: 5, .. }; //~ ERROR destructuring assignments are unstable } diff --git a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr b/src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr index 442e36cd30..a5ed761a01 100644 --- a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr +++ b/src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr @@ -1,5 +1,14 @@ error[E0658]: destructuring assignments are unstable - --> $DIR/underscore-range-expr-gating.rs:7:15 + --> $DIR/underscore-range-expr-gating.rs:7:5 + | +LL | _; + | ^ + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + +error[E0658]: destructuring assignments are unstable + --> $DIR/underscore-range-expr-gating.rs:9:15 | LL | S { x: 5, .. }; | ^^ @@ -7,6 +16,6 @@ LL | S { x: 5, .. }; = note: see issue #71126 for more information = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index d05d6d120b..26c24d7432 100644 --- a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -47,46 +47,19 @@ error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:67:10 | LL | for x, _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | for (x, _barr_body) in women.iter().map(|woman| woman.allosomes.clone()) { - | ^^^^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { - | ^^^^^^^^^^^^^^ + | -^----------- help: try adding parentheses to match on a tuple: `(x, _barr_body)` error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:75:10 | LL | for x, y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | for (x, y @ Allosome::Y(_)) in men.iter().map(|man| man.allosomes.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^ + | -^------------------- help: try adding parentheses to match on a tuple: `(x, y @ Allosome::Y(_))` error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:84:14 | LL | let women, men: (Vec, Vec) = genomes.iter().cloned() - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | let (women, men): (Vec, Vec) = genomes.iter().cloned() - | ^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | let women | men: (Vec, Vec) = genomes.iter().cloned() - | ^^^^^^^^^^^ + | -----^---- help: try adding parentheses to match on a tuple: `(women, men)` error: aborting due to 6 previous errors diff --git a/src/test/ui/discrim/discrim-ill-typed.rs b/src/test/ui/discrim/discrim-ill-typed.rs index 98c90f0ea6..3cf0ea0e6b 100644 --- a/src/test/ui/discrim/discrim-ill-typed.rs +++ b/src/test/ui/discrim/discrim-ill-typed.rs @@ -7,8 +7,6 @@ #![allow(dead_code, unused_variables, unused_imports)] -use std::{i8,u8,i16,u16,i32,u32,i64, u64}; - fn f_i8() { #[repr(i8)] enum A { diff --git a/src/test/ui/discrim/discrim-ill-typed.stderr b/src/test/ui/discrim/discrim-ill-typed.stderr index 7b9f086151..9a695a8987 100644 --- a/src/test/ui/discrim/discrim-ill-typed.stderr +++ b/src/test/ui/discrim/discrim-ill-typed.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:17:16 + --> $DIR/discrim-ill-typed.rs:15:16 | LL | OhNo = 0_u8, | ^^^^ expected `i8`, found `u8` @@ -10,7 +10,7 @@ LL | OhNo = 0_i8, | ^^^^ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:30:16 + --> $DIR/discrim-ill-typed.rs:28:16 | LL | OhNo = 0_i8, | ^^^^ expected `u8`, found `i8` @@ -21,7 +21,7 @@ LL | OhNo = 0_u8, | ^^^^ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:43:16 + --> $DIR/discrim-ill-typed.rs:41:16 | LL | OhNo = 0_u16, | ^^^^^ expected `i16`, found `u16` @@ -32,7 +32,7 @@ LL | OhNo = 0_i16, | ^^^^^ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:56:16 + --> $DIR/discrim-ill-typed.rs:54:16 | LL | OhNo = 0_i16, | ^^^^^ expected `u16`, found `i16` @@ -43,7 +43,7 @@ LL | OhNo = 0_u16, | ^^^^^ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:69:16 + --> $DIR/discrim-ill-typed.rs:67:16 | LL | OhNo = 0_u32, | ^^^^^ expected `i32`, found `u32` @@ -54,7 +54,7 @@ LL | OhNo = 0_i32, | ^^^^^ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:82:16 + --> $DIR/discrim-ill-typed.rs:80:16 | LL | OhNo = 0_i32, | ^^^^^ expected `u32`, found `i32` @@ -65,7 +65,7 @@ LL | OhNo = 0_u32, | ^^^^^ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:95:16 + --> $DIR/discrim-ill-typed.rs:93:16 | LL | OhNo = 0_u64, | ^^^^^ expected `i64`, found `u64` @@ -76,7 +76,7 @@ LL | OhNo = 0_i64, | ^^^^^ error[E0308]: mismatched types - --> $DIR/discrim-ill-typed.rs:108:16 + --> $DIR/discrim-ill-typed.rs:106:16 | LL | OhNo = 0_i64, | ^^^^^ expected `u64`, found `i64` diff --git a/src/test/ui/discrim/discrim-overflow-2.rs b/src/test/ui/discrim/discrim-overflow-2.rs index f8f565f4d9..ca24317c54 100644 --- a/src/test/ui/discrim/discrim-overflow-2.rs +++ b/src/test/ui/discrim/discrim-overflow-2.rs @@ -5,8 +5,6 @@ // See also run-pass/discrim-explicit-23030.rs where the suggested // workaround is tested. -use std::{i8,u8,i16,u16,i32,u32,i64, u64}; - fn f_i8() { #[repr(i8)] enum A { diff --git a/src/test/ui/discrim/discrim-overflow-2.stderr b/src/test/ui/discrim/discrim-overflow-2.stderr index 198ebe9eb5..3ca84c6675 100644 --- a/src/test/ui/discrim/discrim-overflow-2.stderr +++ b/src/test/ui/discrim/discrim-overflow-2.stderr @@ -1,5 +1,5 @@ error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:15:9 + --> $DIR/discrim-overflow-2.rs:13:9 | LL | OhNo, | ^^^^ overflowed on value after 127 @@ -7,7 +7,7 @@ LL | OhNo, = note: explicitly set `OhNo = -128` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:24:9 + --> $DIR/discrim-overflow-2.rs:22:9 | LL | OhNo, | ^^^^ overflowed on value after 255 @@ -15,7 +15,7 @@ LL | OhNo, = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:33:9 + --> $DIR/discrim-overflow-2.rs:31:9 | LL | OhNo, | ^^^^ overflowed on value after 32767 @@ -23,7 +23,7 @@ LL | OhNo, = note: explicitly set `OhNo = -32768` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:42:9 + --> $DIR/discrim-overflow-2.rs:40:9 | LL | OhNo, | ^^^^ overflowed on value after 65535 @@ -31,7 +31,7 @@ LL | OhNo, = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:51:9 + --> $DIR/discrim-overflow-2.rs:49:9 | LL | OhNo, | ^^^^ overflowed on value after 2147483647 @@ -39,7 +39,7 @@ LL | OhNo, = note: explicitly set `OhNo = -2147483648` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:60:9 + --> $DIR/discrim-overflow-2.rs:58:9 | LL | OhNo, | ^^^^ overflowed on value after 4294967295 @@ -47,7 +47,7 @@ LL | OhNo, = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:69:9 + --> $DIR/discrim-overflow-2.rs:67:9 | LL | OhNo, | ^^^^ overflowed on value after 9223372036854775807 @@ -55,7 +55,7 @@ LL | OhNo, = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow-2.rs:78:9 + --> $DIR/discrim-overflow-2.rs:76:9 | LL | OhNo, | ^^^^ overflowed on value after 18446744073709551615 diff --git a/src/test/ui/discrim/discrim-overflow.rs b/src/test/ui/discrim/discrim-overflow.rs index d8a9dacfa5..774ced93c1 100644 --- a/src/test/ui/discrim/discrim-overflow.rs +++ b/src/test/ui/discrim/discrim-overflow.rs @@ -3,8 +3,6 @@ // See also run-pass/discrim-explicit-23030.rs where the suggested // workaround is tested. -use std::{i8,u8,i16,u16,i32,u32,i64, u64}; - fn f_i8() { #[repr(i8)] enum A { diff --git a/src/test/ui/discrim/discrim-overflow.stderr b/src/test/ui/discrim/discrim-overflow.stderr index a2ae4863f9..1b331bb1b8 100644 --- a/src/test/ui/discrim/discrim-overflow.stderr +++ b/src/test/ui/discrim/discrim-overflow.stderr @@ -1,5 +1,5 @@ error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:13:9 + --> $DIR/discrim-overflow.rs:11:9 | LL | OhNo, | ^^^^ overflowed on value after 127 @@ -7,7 +7,7 @@ LL | OhNo, = note: explicitly set `OhNo = -128` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:24:9 + --> $DIR/discrim-overflow.rs:22:9 | LL | OhNo, | ^^^^ overflowed on value after 255 @@ -15,7 +15,7 @@ LL | OhNo, = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:35:9 + --> $DIR/discrim-overflow.rs:33:9 | LL | OhNo, | ^^^^ overflowed on value after 32767 @@ -23,7 +23,7 @@ LL | OhNo, = note: explicitly set `OhNo = -32768` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:46:9 + --> $DIR/discrim-overflow.rs:44:9 | LL | OhNo, | ^^^^ overflowed on value after 65535 @@ -31,7 +31,7 @@ LL | OhNo, = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:58:9 + --> $DIR/discrim-overflow.rs:56:9 | LL | OhNo, | ^^^^ overflowed on value after 2147483647 @@ -39,7 +39,7 @@ LL | OhNo, = note: explicitly set `OhNo = -2147483648` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:70:9 + --> $DIR/discrim-overflow.rs:68:9 | LL | OhNo, | ^^^^ overflowed on value after 4294967295 @@ -47,7 +47,7 @@ LL | OhNo, = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:82:9 + --> $DIR/discrim-overflow.rs:80:9 | LL | OhNo, | ^^^^ overflowed on value after 9223372036854775807 @@ -55,7 +55,7 @@ LL | OhNo, = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome error[E0370]: enum discriminant overflowed - --> $DIR/discrim-overflow.rs:94:9 + --> $DIR/discrim-overflow.rs:92:9 | LL | OhNo, | ^^^^ overflowed on value after 18446744073709551615 diff --git a/src/test/ui/doc-alias-crate-level.rs b/src/test/ui/doc-alias-crate-level.rs index b1b17f2de8..9b596ece5b 100644 --- a/src/test/ui/doc-alias-crate-level.rs +++ b/src/test/ui/doc-alias-crate-level.rs @@ -4,4 +4,7 @@ #![crate_type = "lib"] -#![doc(alias = "shouldn't work!")] //~ ERROR +#![doc(alias = "not working!")] //~ ERROR + +#[doc(alias = "shouldn't work!")] //~ ERROR +pub struct Foo; diff --git a/src/test/ui/doc-alias-crate-level.stderr b/src/test/ui/doc-alias-crate-level.stderr index 45756d6a04..b6437fad5d 100644 --- a/src/test/ui/doc-alias-crate-level.stderr +++ b/src/test/ui/doc-alias-crate-level.stderr @@ -1,8 +1,14 @@ error: '\'' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/doc-alias-crate-level.rs:9:15 + | +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ + +error: `#![doc(alias = "...")]` isn't allowed as a crate level attribute --> $DIR/doc-alias-crate-level.rs:7:8 | -LL | #![doc(alias = "shouldn't work!")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![doc(alias = "not working!")] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/doc_keyword.rs b/src/test/ui/doc_keyword.rs new file mode 100644 index 0000000000..4c72e7e968 --- /dev/null +++ b/src/test/ui/doc_keyword.rs @@ -0,0 +1,12 @@ +#![crate_type = "lib"] +#![feature(doc_keyword)] + +#![doc(keyword = "hello")] //~ ERROR + +#[doc(keyword = "hell")] //~ ERROR +mod foo { + fn hell() {} +} + +#[doc(keyword = "hall")] //~ ERROR +fn foo() {} diff --git a/src/test/ui/doc_keyword.stderr b/src/test/ui/doc_keyword.stderr new file mode 100644 index 0000000000..d72a876163 --- /dev/null +++ b/src/test/ui/doc_keyword.stderr @@ -0,0 +1,20 @@ +error: `#[doc(keyword = "...")]` can only be used on empty modules + --> $DIR/doc_keyword.rs:6:7 + | +LL | #[doc(keyword = "hell")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(keyword = "...")]` can only be used on modules + --> $DIR/doc_keyword.rs:11:7 + | +LL | #[doc(keyword = "hall")] + | ^^^^^^^^^^^^^^^^ + +error: `#![doc(keyword = "...")]` isn't allowed as a crate level attribute + --> $DIR/doc_keyword.rs:4:8 + | +LL | #![doc(keyword = "hello")] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index b027faa9d7..c4f7c37861 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -18,7 +18,6 @@ use std::{ ptr, rc::Rc, task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - usize, }; struct InjectedFailure; diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index 6d0cd101db..88f557055f 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -12,7 +12,6 @@ use std::mem::ManuallyDrop; use std::ops::Generator; use std::panic; use std::pin::Pin; -use std::usize; struct InjectedFailure; diff --git a/src/test/ui/issues/issue-38868.rs b/src/test/ui/dropck/issue-38868.rs similarity index 100% rename from src/test/ui/issues/issue-38868.rs rename to src/test/ui/dropck/issue-38868.rs diff --git a/src/test/ui/issues/issue-38868.stderr b/src/test/ui/dropck/issue-38868.stderr similarity index 100% rename from src/test/ui/issues/issue-38868.stderr rename to src/test/ui/dropck/issue-38868.stderr diff --git a/src/test/ui/reject-specialized-drops-8142.rs b/src/test/ui/dropck/reject-specialized-drops-8142.rs similarity index 88% rename from src/test/ui/reject-specialized-drops-8142.rs rename to src/test/ui/dropck/reject-specialized-drops-8142.rs index c4671736d7..02e8665cd2 100644 --- a/src/test/ui/reject-specialized-drops-8142.rs +++ b/src/test/ui/dropck/reject-specialized-drops-8142.rs @@ -1,5 +1,6 @@ // Issue 8142: Test that Drop impls cannot be specialized beyond the // predicates attached to the type definition itself. +#![feature(min_const_generics)] trait Bound { fn foo(&self) { } } struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } @@ -15,6 +16,8 @@ struct T<'t,Ts:'t> { x: &'t Ts } struct U; struct V { x: *const Tva, y: *const Tvb } struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } +struct X; +struct Y; enum Enum { Variant(T) } struct TupleStruct(T); @@ -58,6 +61,12 @@ impl Drop for V { fn drop(&mut self) { } } // REJECT impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'lw` +impl Drop for X<3> { fn drop(&mut self) { } } // REJECT +//~^ ERROR `Drop` impls cannot be specialized + +impl Drop for Y { fn drop(&mut self) { } } // REJECT +//~^ ERROR `Drop` impls cannot be specialized + impl Drop for Enum { fn drop(&mut self) { } } // REJECT //~^ ERROR `Drop` impl requires `AddsBnd: Bound` diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/dropck/reject-specialized-drops-8142.stderr similarity index 71% rename from src/test/ui/reject-specialized-drops-8142.stderr rename to src/test/ui/dropck/reject-specialized-drops-8142.stderr index eac2461753..284cf59c82 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/dropck/reject-specialized-drops-8142.stderr @@ -1,151 +1,175 @@ error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:23:20 + --> $DIR/reject-specialized-drops-8142.rs:26:20 | LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT | ^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:5:1 + --> $DIR/reject-specialized-drops-8142.rs:6:1 | LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:27:67 + --> $DIR/reject-specialized-drops-8142.rs:30:67 | LL | impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT | ^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:6:1 + --> $DIR/reject-specialized-drops-8142.rs:7:1 | LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/reject-specialized-drops-8142.rs:33:1 + --> $DIR/reject-specialized-drops-8142.rs:36:1 | LL | impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected struct `N<'n>` found struct `N<'static>` -note: the lifetime `'n` as defined on the struct at 8:10... - --> $DIR/reject-specialized-drops-8142.rs:8:10 +note: the lifetime `'n` as defined on the struct at 9:10... + --> $DIR/reject-specialized-drops-8142.rs:9:10 | LL | struct N<'n> { x: &'n i8 } | ^^ = note: ...does not necessarily outlive the static lifetime error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:40:1 + --> $DIR/reject-specialized-drops-8142.rs:43:1 | LL | impl Drop for P { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: use the same sequence of generic type, lifetime and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:10:1 + --> $DIR/reject-specialized-drops-8142.rs:11:1 | LL | struct P { x: *const Tp } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:43:14 + --> $DIR/reject-specialized-drops-8142.rs:46:14 | LL | impl Drop for Q { fn drop(&mut self) { } } // REJECT | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:11:1 + --> $DIR/reject-specialized-drops-8142.rs:12:1 | LL | struct Q { x: *const Tq } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:46:21 + --> $DIR/reject-specialized-drops-8142.rs:49:21 | LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R { fn drop(&mut self) { } } // REJECT | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:12:1 + --> $DIR/reject-specialized-drops-8142.rs:13:1 | LL | struct R { x: *const Tr } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized - --> $DIR/reject-specialized-drops-8142.rs:55:1 + --> $DIR/reject-specialized-drops-8142.rs:58:1 | LL | impl Drop for V { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: use the same sequence of generic type, lifetime and const parameters as the struct definition - --> $DIR/reject-specialized-drops-8142.rs:16:1 + --> $DIR/reject-specialized-drops-8142.rs:17:1 | LL | struct V { x: *const Tva, y: *const Tvb } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'lw` due to conflicting requirements - --> $DIR/reject-specialized-drops-8142.rs:58:1 + --> $DIR/reject-specialized-drops-8142.rs:61:1 | LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 17:10... - --> $DIR/reject-specialized-drops-8142.rs:17:10 +note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 18:10... + --> $DIR/reject-specialized-drops-8142.rs:18:10 | LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } | ^^^ -note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 17:15... - --> $DIR/reject-specialized-drops-8142.rs:17:15 +note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 18:15... + --> $DIR/reject-specialized-drops-8142.rs:18:15 | LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } | ^^^ note: ...so that the types are compatible - --> $DIR/reject-specialized-drops-8142.rs:58:1 + --> $DIR/reject-specialized-drops-8142.rs:61:1 | LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected `W<'l1, 'l2>` found `W<'_, '_>` +error[E0366]: `Drop` impls cannot be specialized + --> $DIR/reject-specialized-drops-8142.rs:64:1 + | +LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: use the same sequence of generic type, lifetime and const parameters as the struct definition + --> $DIR/reject-specialized-drops-8142.rs:19:1 + | +LL | struct X; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0366]: `Drop` impls cannot be specialized + --> $DIR/reject-specialized-drops-8142.rs:67:1 + | +LL | impl Drop for Y { fn drop(&mut self) { } } // REJECT + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: use the same sequence of generic type, lifetime and const parameters as the struct definition + --> $DIR/reject-specialized-drops-8142.rs:20:1 + | +LL | struct Y; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:61:14 + --> $DIR/reject-specialized-drops-8142.rs:70:14 | LL | impl Drop for Enum { fn drop(&mut self) { } } // REJECT | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:19:1 + --> $DIR/reject-specialized-drops-8142.rs:22:1 | LL | enum Enum { Variant(T) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:64:14 + --> $DIR/reject-specialized-drops-8142.rs:73:14 | LL | impl Drop for TupleStruct { fn drop(&mut self) { } } // REJECT | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:20:1 + --> $DIR/reject-specialized-drops-8142.rs:23:1 | LL | struct TupleStruct(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:67:21 + --> $DIR/reject-specialized-drops-8142.rs:76:21 | LL | impl Drop for Union { fn drop(&mut self) { } } // REJECT | ^^^^^ | note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:21:1 + --> $DIR/reject-specialized-drops-8142.rs:24:1 | LL | union Union { f: T } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors Some errors have detailed explanations: E0308, E0366, E0367, E0495. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/env-args-reverse-iterator.rs b/src/test/ui/env-args-reverse-iterator.rs index 0ffd74f87a..7f06718c03 100644 --- a/src/test/ui/env-args-reverse-iterator.rs +++ b/src/test/ui/env-args-reverse-iterator.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/env-funky-keys.rs b/src/test/ui/env-funky-keys.rs index c5c824ac58..4548d33394 100644 --- a/src/test/ui/env-funky-keys.rs +++ b/src/test/ui/env-funky-keys.rs @@ -3,7 +3,6 @@ // ignore-android // ignore-windows -// ignore-cloudabi no execve // ignore-emscripten no execve // ignore-sgx no execve // ignore-vxworks no execve diff --git a/src/test/ui/env-home-dir.rs b/src/test/ui/env-home-dir.rs deleted file mode 100644 index a75be48fd5..0000000000 --- a/src/test/ui/env-home-dir.rs +++ /dev/null @@ -1,51 +0,0 @@ -// run-pass - -#![allow(unused_variables)] -#![allow(deprecated)] -// ignore-cloudabi no environment variables present -// ignore-emscripten env vars don't work? -// ignore-sgx env vars cannot be modified - -use std::env::*; -use std::path::PathBuf; - -#[cfg(unix)] -fn main() { - let oldhome = var("HOME"); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - if cfg!(target_os = "android") { - assert!(home_dir().is_none()); - } else { - // When HOME is not set, some platforms return `None`, - // but others return `Some` with a default. - // Just check that it is not "/home/MountainView". - assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - } -} - -#[cfg(windows)] -fn main() { - let oldhome = var("HOME"); - let olduserprofile = var("USERPROFILE"); - - remove_var("HOME"); - remove_var("USERPROFILE"); - - assert!(home_dir().is_some()); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - - set_var("USERPROFILE", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - set_var("HOME", "/home/MountainView"); - set_var("USERPROFILE", "/home/PaloAlto"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); -} diff --git a/src/test/ui/env-vars.rs b/src/test/ui/env-vars.rs index 2ea906788e..f5035bb2c6 100644 --- a/src/test/ui/env-vars.rs +++ b/src/test/ui/env-vars.rs @@ -1,11 +1,18 @@ // run-pass -// ignore-cloudabi no env vars // ignore-wasm32-bare no env vars use std::env::*; fn main() { for (k, v) in vars_os() { + // On Windows, the environment variable NUMBER_OF_PROCESSORS has special meaning. + // Unfortunately, you can get different answers, depending on whether you are + // enumerating all environment variables or querying a specific variable. + // This was causing this test to fail on machines with more than 64 processors. + if cfg!(target_os = "windows") && k == "NUMBER_OF_PROCESSORS" { + continue; + } + let v2 = var_os(&k); assert!(v2.as_ref().map(|s| &**s) == Some(&*v), "bad vars->var transition: {:?} {:?} {:?}", k, v, v2); diff --git a/src/test/ui/error-codes/E0077.stderr b/src/test/ui/error-codes/E0077.stderr index 4f85d175ce..1938a9a272 100644 --- a/src/test/ui/error-codes/E0077.stderr +++ b/src/test/ui/error-codes/E0077.stderr @@ -1,4 +1,4 @@ -error[E0077]: SIMD vector element type should be machine type +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type --> $DIR/E0077.rs:4:1 | LL | struct Bad(String); diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index 2692fe6945..46966f22b6 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -9,132 +9,7 @@ LL | impl Foo for T where Bar: Foo {} | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`) = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>` + = note: 127 redundant requirements hidden = note: required because of the requirements on the impl of `Foo` for `Bar` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277.rs b/src/test/ui/error-codes/E0277.rs index e60d83098b..f0de4e3deb 100644 --- a/src/test/ui/error-codes/E0277.rs +++ b/src/test/ui/error-codes/E0277.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::path - use std::path::Path; trait Foo { diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index 647e0c7d76..1f54af4d15 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/E0277.rs:13:6 + --> $DIR/E0277.rs:11:6 | LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time @@ -13,7 +13,7 @@ LL | fn f(&p: Path) { } | ^ error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/E0277.rs:17:15 + --> $DIR/E0277.rs:15:15 | LL | fn some_func(foo: T) { | --- required by this bound in `some_func` diff --git a/src/test/ui/error-codes/E0390.stderr b/src/test/ui/error-codes/E0390.stderr index 3ca3a77c74..be47e93d19 100644 --- a/src/test/ui/error-codes/E0390.stderr +++ b/src/test/ui/error-codes/E0390.stderr @@ -4,11 +4,7 @@ error[E0390]: only a single inherent implementation marked with `#[lang = "mut_p LL | impl *mut Foo {} | ^^^^^^^^^^^^^^^^ | -help: consider using a trait to implement these methods - --> $DIR/E0390.rs:5:1 - | -LL | impl *mut Foo {} - | ^^^^^^^^^^^^^^^^ + = help: consider using a trait error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0396.rs b/src/test/ui/error-codes/E0396.rs index b32853e483..58ed3c2c72 100644 --- a/src/test/ui/error-codes/E0396.rs +++ b/src/test/ui/error-codes/E0396.rs @@ -5,5 +5,16 @@ const REG_ADDR: *const u8 = 0x5f3759df as *const u8; const VALUE: u8 = unsafe { *REG_ADDR }; //~^ ERROR dereferencing raw pointers in constants is unstable +const unsafe fn unreachable() -> ! { + use std::convert::Infallible; + + const INFALLIBLE: *const Infallible = [].as_ptr(); + match *INFALLIBLE {} + //~^ ERROR dereferencing raw pointers in constant functions is unstable + + const BAD: () = unsafe { match *INFALLIBLE {} }; + //~^ ERROR dereferencing raw pointers in constants is unstable +} + fn main() { } diff --git a/src/test/ui/error-codes/E0396.stderr b/src/test/ui/error-codes/E0396.stderr index 7d2544f939..20dad1b983 100644 --- a/src/test/ui/error-codes/E0396.stderr +++ b/src/test/ui/error-codes/E0396.stderr @@ -7,6 +7,24 @@ LL | const VALUE: u8 = unsafe { *REG_ADDR }; = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: dereferencing raw pointers in constant functions is unstable + --> $DIR/E0396.rs:12:11 + | +LL | match *INFALLIBLE {} + | ^^^^^^^^^^^ + | + = note: see issue #51911 for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/E0396.rs:15:36 + | +LL | const BAD: () = unsafe { match *INFALLIBLE {} }; + | ^^^^^^^^^^^ + | + = note: see issue #51911 for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/error-codes/E0453.rs b/src/test/ui/error-codes/E0453.rs index 69155b0688..6fa8dd9717 100644 --- a/src/test/ui/error-codes/E0453.rs +++ b/src/test/ui/error-codes/E0453.rs @@ -1,8 +1,8 @@ #![forbid(non_snake_case)] #[allow(non_snake_case)] -//~^ ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case) -//~| ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case) -//~| ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case) +//~^ ERROR allow(non_snake_case) incompatible +//~| ERROR allow(non_snake_case) incompatible +//~| ERROR allow(non_snake_case) incompatible fn main() { } diff --git a/src/test/ui/error-codes/E0453.stderr b/src/test/ui/error-codes/E0453.stderr index 138e848346..21c43cc052 100644 --- a/src/test/ui/error-codes/E0453.stderr +++ b/src/test/ui/error-codes/E0453.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case) +error[E0453]: allow(non_snake_case) incompatible with previous forbid --> $DIR/E0453.rs:3:9 | LL | #![forbid(non_snake_case)] @@ -7,7 +7,7 @@ LL | LL | #[allow(non_snake_case)] | ^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case) +error[E0453]: allow(non_snake_case) incompatible with previous forbid --> $DIR/E0453.rs:3:9 | LL | #![forbid(non_snake_case)] @@ -16,7 +16,7 @@ LL | LL | #[allow(non_snake_case)] | ^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case) +error[E0453]: allow(non_snake_case) incompatible with previous forbid --> $DIR/E0453.rs:3:9 | LL | #![forbid(non_snake_case)] diff --git a/src/test/ui/error-codes/E0496.stderr b/src/test/ui/error-codes/E0496.stderr index b0294eef04..80ca2b1fbd 100644 --- a/src/test/ui/error-codes/E0496.stderr +++ b/src/test/ui/error-codes/E0496.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> Foo<'a> { | -- first declared here LL | fn f<'a>(x: &'a i32) { - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error: aborting due to previous error diff --git a/src/test/ui/error-codes/e0119/conflict-with-std.stderr b/src/test/ui/error-codes/e0119/conflict-with-std.stderr index 9dc1a509cd..68551f4377 100644 --- a/src/test/ui/error-codes/e0119/conflict-with-std.stderr +++ b/src/test/ui/error-codes/e0119/conflict-with-std.stderr @@ -6,7 +6,7 @@ LL | impl AsRef for Box { | = note: conflicting implementation in crate `alloc`: - impl AsRef for Box - where A: AllocRef, T: ?Sized; + where A: Allocator, T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: --> $DIR/conflict-with-std.rs:12:1 diff --git a/src/test/ui/exec-env.rs b/src/test/ui/exec-env.rs index 230fac10d3..d7f15bcae7 100644 --- a/src/test/ui/exec-env.rs +++ b/src/test/ui/exec-env.rs @@ -1,6 +1,5 @@ // run-pass // exec-env:TEST_EXEC_ENV=22 -// ignore-cloudabi no env vars // ignore-emscripten FIXME: issue #31622 // ignore-sgx unsupported diff --git a/src/test/ui/explain.stdout b/src/test/ui/explain.stdout index c50c46ee56..62f1a7f98e 100644 --- a/src/test/ui/explain.stdout +++ b/src/test/ui/explain.stdout @@ -1,12 +1,18 @@ Per [RFC 401][rfc401], if you have a function declaration `foo`: ``` +struct S; + // For the purposes of this explanation, all of these // different kinds of `fn` declarations are equivalent: -struct S; + fn foo(x: S) { /* ... */ } -extern "C" { fn foo(x: S); } -impl S { fn foo(self) { /* ... */ } } +extern "C" { + fn foo(x: S); +} +impl S { + fn foo(self) { /* ... */ } +} ``` the type of `foo` is **not** `fn(S)`, as one might expect. @@ -34,8 +40,10 @@ extern "C" fn foo(userdata: Box) { /* ... */ } -let f: extern "C" fn(*mut i32) = transmute(foo); -callback(f); +unsafe { + let f: extern "C" fn(*mut i32) = transmute(foo); + callback(f); +} ``` Here, transmute is being used to convert the types of the fn arguments. diff --git a/src/test/ui/expr/compound-assignment/eval-order.rs b/src/test/ui/expr/compound-assignment/eval-order.rs new file mode 100644 index 0000000000..658adae193 --- /dev/null +++ b/src/test/ui/expr/compound-assignment/eval-order.rs @@ -0,0 +1,76 @@ +// Test evaluation order of operands of the compound assignment operators + +// run-pass + +use std::ops::AddAssign; + +enum Side { + Lhs, + Rhs, +} + +// In the following tests, we place our value into a wrapper type so that we +// can do an element access as the outer place expression. If we just had the +// block expression, it'd be a value expression and not compile. +struct Wrapper(T); + +// Evaluation order for `a op= b` where typeof(a) and typeof(b) are primitives +// is first `b` then `a`. +fn primitive_compound() { + let mut side_order = vec![]; + let mut int = Wrapper(0); + + { + side_order.push(Side::Lhs); + int + }.0 += { + side_order.push(Side::Rhs); + 0 + }; + + assert!(matches!(side_order[..], [Side::Rhs, Side::Lhs])); +} + +// Evaluation order for `a op=b` otherwise is first `a` then `b`. +fn generic_compound + Default>() { + let mut side_order = vec![]; + let mut add_assignable: Wrapper = Wrapper(Default::default()); + + { + side_order.push(Side::Lhs); + add_assignable + }.0 += { + side_order.push(Side::Rhs); + Default::default() + }; + + assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs])); +} + +fn custom_compound() { + struct Custom; + + impl AddAssign<()> for Custom { + fn add_assign(&mut self, _: ()) { + // this block purposely left blank + } + } + + let mut side_order = vec![]; + let mut custom = Wrapper(Custom); + + { + side_order.push(Side::Lhs); + custom + }.0 += { + side_order.push(Side::Rhs); + }; + + assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs])); +} + +fn main() { + primitive_compound(); + generic_compound::(); + custom_compound(); +} diff --git a/src/test/ui/if-bot.rs b/src/test/ui/expr/if-bot.rs similarity index 100% rename from src/test/ui/if-bot.rs rename to src/test/ui/expr/if-bot.rs diff --git a/src/test/ui/if-attrs/bad-cfg.rs b/src/test/ui/expr/if/attrs/bad-cfg.rs similarity index 100% rename from src/test/ui/if-attrs/bad-cfg.rs rename to src/test/ui/expr/if/attrs/bad-cfg.rs diff --git a/src/test/ui/if-attrs/bad-cfg.stderr b/src/test/ui/expr/if/attrs/bad-cfg.stderr similarity index 100% rename from src/test/ui/if-attrs/bad-cfg.stderr rename to src/test/ui/expr/if/attrs/bad-cfg.stderr diff --git a/src/test/ui/if-attrs/builtin-if-attr.rs b/src/test/ui/expr/if/attrs/builtin-if-attr.rs similarity index 100% rename from src/test/ui/if-attrs/builtin-if-attr.rs rename to src/test/ui/expr/if/attrs/builtin-if-attr.rs diff --git a/src/test/ui/if-attrs/cfg-false-if-attr.rs b/src/test/ui/expr/if/attrs/cfg-false-if-attr.rs similarity index 100% rename from src/test/ui/if-attrs/cfg-false-if-attr.rs rename to src/test/ui/expr/if/attrs/cfg-false-if-attr.rs diff --git a/src/test/ui/if-attrs/else-attrs.rs b/src/test/ui/expr/if/attrs/else-attrs.rs similarity index 100% rename from src/test/ui/if-attrs/else-attrs.rs rename to src/test/ui/expr/if/attrs/else-attrs.rs diff --git a/src/test/ui/if-attrs/else-attrs.stderr b/src/test/ui/expr/if/attrs/else-attrs.stderr similarity index 100% rename from src/test/ui/if-attrs/else-attrs.stderr rename to src/test/ui/expr/if/attrs/else-attrs.stderr diff --git a/src/test/ui/if-attrs/gate-whole-expr.rs b/src/test/ui/expr/if/attrs/gate-whole-expr.rs similarity index 100% rename from src/test/ui/if-attrs/gate-whole-expr.rs rename to src/test/ui/expr/if/attrs/gate-whole-expr.rs diff --git a/src/test/ui/if-attrs/let-chains-attr.rs b/src/test/ui/expr/if/attrs/let-chains-attr.rs similarity index 100% rename from src/test/ui/if-attrs/let-chains-attr.rs rename to src/test/ui/expr/if/attrs/let-chains-attr.rs diff --git a/src/test/ui/if-attrs/let-chains-attr.stderr b/src/test/ui/expr/if/attrs/let-chains-attr.stderr similarity index 100% rename from src/test/ui/if-attrs/let-chains-attr.stderr rename to src/test/ui/expr/if/attrs/let-chains-attr.stderr diff --git a/src/test/ui/if-attrs/stmt-expr-gated.rs b/src/test/ui/expr/if/attrs/stmt-expr-gated.rs similarity index 100% rename from src/test/ui/if-attrs/stmt-expr-gated.rs rename to src/test/ui/expr/if/attrs/stmt-expr-gated.rs diff --git a/src/test/ui/if-attrs/stmt-expr-gated.stderr b/src/test/ui/expr/if/attrs/stmt-expr-gated.stderr similarity index 100% rename from src/test/ui/if-attrs/stmt-expr-gated.stderr rename to src/test/ui/expr/if/attrs/stmt-expr-gated.stderr diff --git a/src/test/ui/if/expr-if-panic-fn.rs b/src/test/ui/expr/if/expr-if-panic-fn.rs similarity index 100% rename from src/test/ui/if/expr-if-panic-fn.rs rename to src/test/ui/expr/if/expr-if-panic-fn.rs diff --git a/src/test/ui/if/expr-if-panic.rs b/src/test/ui/expr/if/expr-if-panic.rs similarity index 100% rename from src/test/ui/if/expr-if-panic.rs rename to src/test/ui/expr/if/expr-if-panic.rs diff --git a/src/test/ui/if/if-branch-types.rs b/src/test/ui/expr/if/if-branch-types.rs similarity index 100% rename from src/test/ui/if/if-branch-types.rs rename to src/test/ui/expr/if/if-branch-types.rs diff --git a/src/test/ui/if/if-branch-types.stderr b/src/test/ui/expr/if/if-branch-types.stderr similarity index 100% rename from src/test/ui/if/if-branch-types.stderr rename to src/test/ui/expr/if/if-branch-types.stderr diff --git a/src/test/ui/if/if-check-panic.rs b/src/test/ui/expr/if/if-check-panic.rs similarity index 100% rename from src/test/ui/if/if-check-panic.rs rename to src/test/ui/expr/if/if-check-panic.rs diff --git a/src/test/ui/if-check.rs b/src/test/ui/expr/if/if-check.rs similarity index 100% rename from src/test/ui/if-check.rs rename to src/test/ui/expr/if/if-check.rs diff --git a/src/test/ui/if/if-cond-bot.rs b/src/test/ui/expr/if/if-cond-bot.rs similarity index 100% rename from src/test/ui/if/if-cond-bot.rs rename to src/test/ui/expr/if/if-cond-bot.rs diff --git a/src/test/ui/if-else-type-mismatch.rs b/src/test/ui/expr/if/if-else-type-mismatch.rs similarity index 100% rename from src/test/ui/if-else-type-mismatch.rs rename to src/test/ui/expr/if/if-else-type-mismatch.rs diff --git a/src/test/ui/if-else-type-mismatch.stderr b/src/test/ui/expr/if/if-else-type-mismatch.stderr similarity index 100% rename from src/test/ui/if-else-type-mismatch.stderr rename to src/test/ui/expr/if/if-else-type-mismatch.stderr diff --git a/src/test/ui/if/if-let-arm-types.rs b/src/test/ui/expr/if/if-let-arm-types.rs similarity index 100% rename from src/test/ui/if/if-let-arm-types.rs rename to src/test/ui/expr/if/if-let-arm-types.rs diff --git a/src/test/ui/if/if-let-arm-types.stderr b/src/test/ui/expr/if/if-let-arm-types.stderr similarity index 100% rename from src/test/ui/if/if-let-arm-types.stderr rename to src/test/ui/expr/if/if-let-arm-types.stderr diff --git a/src/test/ui/if/if-let.rs b/src/test/ui/expr/if/if-let.rs similarity index 100% rename from src/test/ui/if/if-let.rs rename to src/test/ui/expr/if/if-let.rs diff --git a/src/test/ui/if/if-let.stderr b/src/test/ui/expr/if/if-let.stderr similarity index 100% rename from src/test/ui/if/if-let.stderr rename to src/test/ui/expr/if/if-let.stderr diff --git a/src/test/ui/if/if-loop.rs b/src/test/ui/expr/if/if-loop.rs similarity index 100% rename from src/test/ui/if/if-loop.rs rename to src/test/ui/expr/if/if-loop.rs diff --git a/src/test/ui/if/if-no-match-bindings.rs b/src/test/ui/expr/if/if-no-match-bindings.rs similarity index 100% rename from src/test/ui/if/if-no-match-bindings.rs rename to src/test/ui/expr/if/if-no-match-bindings.rs diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/expr/if/if-no-match-bindings.stderr similarity index 100% rename from src/test/ui/if/if-no-match-bindings.stderr rename to src/test/ui/expr/if/if-no-match-bindings.stderr diff --git a/src/test/ui/if-ret.rs b/src/test/ui/expr/if/if-ret.rs similarity index 100% rename from src/test/ui/if-ret.rs rename to src/test/ui/expr/if/if-ret.rs diff --git a/src/test/ui/if-ret.stderr b/src/test/ui/expr/if/if-ret.stderr similarity index 100% rename from src/test/ui/if-ret.stderr rename to src/test/ui/expr/if/if-ret.stderr diff --git a/src/test/ui/if/if-typeck.rs b/src/test/ui/expr/if/if-typeck.rs similarity index 100% rename from src/test/ui/if/if-typeck.rs rename to src/test/ui/expr/if/if-typeck.rs diff --git a/src/test/ui/if/if-typeck.stderr b/src/test/ui/expr/if/if-typeck.stderr similarity index 100% rename from src/test/ui/if/if-typeck.stderr rename to src/test/ui/expr/if/if-typeck.stderr diff --git a/src/test/ui/if/if-without-block.rs b/src/test/ui/expr/if/if-without-block.rs similarity index 100% rename from src/test/ui/if/if-without-block.rs rename to src/test/ui/expr/if/if-without-block.rs diff --git a/src/test/ui/if/if-without-block.stderr b/src/test/ui/expr/if/if-without-block.stderr similarity index 100% rename from src/test/ui/if/if-without-block.stderr rename to src/test/ui/expr/if/if-without-block.stderr diff --git a/src/test/ui/if/if-without-else-as-fn-expr.rs b/src/test/ui/expr/if/if-without-else-as-fn-expr.rs similarity index 100% rename from src/test/ui/if/if-without-else-as-fn-expr.rs rename to src/test/ui/expr/if/if-without-else-as-fn-expr.rs diff --git a/src/test/ui/if/if-without-else-as-fn-expr.stderr b/src/test/ui/expr/if/if-without-else-as-fn-expr.stderr similarity index 100% rename from src/test/ui/if/if-without-else-as-fn-expr.stderr rename to src/test/ui/expr/if/if-without-else-as-fn-expr.stderr diff --git a/src/test/ui/if/if-without-else-result.rs b/src/test/ui/expr/if/if-without-else-result.rs similarity index 100% rename from src/test/ui/if/if-without-else-result.rs rename to src/test/ui/expr/if/if-without-else-result.rs diff --git a/src/test/ui/if/if-without-else-result.stderr b/src/test/ui/expr/if/if-without-else-result.stderr similarity index 100% rename from src/test/ui/if/if-without-else-result.stderr rename to src/test/ui/expr/if/if-without-else-result.stderr diff --git a/src/test/ui/extend-for-unit.rs b/src/test/ui/extend-for-unit.rs deleted file mode 100644 index 01d743f70b..0000000000 --- a/src/test/ui/extend-for-unit.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - -pub fn main() { - let mut x = 0; - { - let iter = (0..5).map(|_| { - x += 1; - }); - ().extend(iter); - } - assert_eq!(x, 5); -} diff --git a/src/test/ui/fds-are-cloexec.rs b/src/test/ui/fds-are-cloexec.rs index 2010b5b668..4482b7032a 100644 --- a/src/test/ui/fds-are-cloexec.rs +++ b/src/test/ui/fds-are-cloexec.rs @@ -1,7 +1,6 @@ // run-pass // ignore-windows // ignore-android -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-haiku // ignore-sgx no processes diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-test.rs b/src/test/ui/feature-gate/issue-43106-gating-of-test.rs index d343746955..ee3fe712e3 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-test.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-test.rs @@ -1,5 +1,6 @@ // The non-crate level cases are in issue-43106-gating-of-builtin-attrs.rs. +#![allow(soft_unstable)] #![test = "4200"] //~^ ERROR cannot determine resolution for the attribute macro `test` diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr index a7d3a1e168..335af5e790 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr @@ -1,5 +1,5 @@ error: cannot determine resolution for the attribute macro `test` - --> $DIR/issue-43106-gating-of-test.rs:3:4 + --> $DIR/issue-43106-gating-of-test.rs:4:4 | LL | #![test = "4200"] | ^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs index e89dc4d5a0..31f09cc61f 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.rs +++ b/src/test/ui/feature-gates/feature-gate-abi.rs @@ -15,7 +15,7 @@ extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental //~^ ERROR intrinsic must be in extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change -extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change +extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental extern "ptx-kernel" fn f6() {} //~ ERROR PTX ABIs are experimental and subject to change extern "x86-interrupt" fn f7() {} //~ ERROR x86-interrupt ABI is experimental @@ -30,7 +30,7 @@ trait Tr { extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental //~^ ERROR intrinsic must be in extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change - extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change + extern "rust-call" fn m4(_: ()); //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental extern "ptx-kernel" fn m6(); //~ ERROR PTX ABIs are experimental and subject to change extern "x86-interrupt" fn m7(); //~ ERROR x86-interrupt ABI is experimental @@ -39,7 +39,7 @@ trait Tr { extern "efiapi" fn m10(); //~ ERROR efiapi ABI is experimental and subject to change extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change - extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change + extern "rust-call" fn dm4(_: ()) {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental extern "ptx-kernel" fn dm6() {} //~ ERROR PTX ABIs are experimental and subject to change extern "x86-interrupt" fn dm7() {} //~ ERROR x86-interrupt ABI is experimental @@ -57,7 +57,7 @@ impl Tr for S { extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental //~^ ERROR intrinsic must be in extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change - extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change + extern "rust-call" fn m4(_: ()) {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental extern "ptx-kernel" fn m6() {} //~ ERROR PTX ABIs are experimental and subject to change extern "x86-interrupt" fn m7() {} //~ ERROR x86-interrupt ABI is experimental @@ -73,7 +73,7 @@ impl S { extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental //~^ ERROR intrinsic must be in extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change - extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change + extern "rust-call" fn im4(_: ()) {} //~ ERROR rust-call ABI is subject to change extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental extern "ptx-kernel" fn im6() {} //~ ERROR PTX ABIs are experimental and subject to change extern "x86-interrupt" fn im7() {} //~ ERROR x86-interrupt ABI is experimental @@ -86,7 +86,7 @@ impl S { type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change -type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change +type A4 = extern "rust-call" fn(_: ()); //~ ERROR rust-call ABI is subject to change type A5 = extern "msp430-interrupt" fn(); //~ ERROR msp430-interrupt ABI is experimental type A6 = extern "ptx-kernel" fn (); //~ ERROR PTX ABIs are experimental and subject to change type A7 = extern "x86-interrupt" fn(); //~ ERROR x86-interrupt ABI is experimental diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr index 50cd8bc68a..25f0c259d1 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi.stderr @@ -26,7 +26,7 @@ LL | extern "vectorcall" fn f3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:18:8 | -LL | extern "rust-call" fn f4() {} +LL | extern "rust-call" fn f4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -113,7 +113,7 @@ LL | extern "vectorcall" fn m3(); error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:33:12 | -LL | extern "rust-call" fn m4(); +LL | extern "rust-call" fn m4(_: ()); | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -183,7 +183,7 @@ LL | extern "vectorcall" fn dm3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:42:12 | -LL | extern "rust-call" fn dm4() {} +LL | extern "rust-call" fn dm4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -270,7 +270,7 @@ LL | extern "vectorcall" fn m3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:60:12 | -LL | extern "rust-call" fn m4() {} +LL | extern "rust-call" fn m4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -357,7 +357,7 @@ LL | extern "vectorcall" fn im3() {} error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:76:12 | -LL | extern "rust-call" fn im4() {} +LL | extern "rust-call" fn im4(_: ()) {} | ^^^^^^^^^^^ | = note: see issue #29625 for more information @@ -444,7 +444,7 @@ LL | type A3 = extern "vectorcall" fn(); error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:89:18 | -LL | type A4 = extern "rust-call" fn(); +LL | type A4 = extern "rust-call" fn(_: ()); | ^^^^^^^^^^^ | = note: see issue #29625 for more information diff --git a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.rs b/src/test/ui/feature-gates/feature-gate-auto-traits.rs similarity index 89% rename from src/test/ui/feature-gates/feature-gate-optin-builtin-traits.rs rename to src/test/ui/feature-gates/feature-gate-auto-traits.rs index 35c05b75d3..80cfa9cee8 100644 --- a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.rs +++ b/src/test/ui/feature-gates/feature-gate-auto-traits.rs @@ -1,5 +1,5 @@ // Test that default and negative trait implementations are gated by -// `optin_builtin_traits` feature gate +// `auto_traits` feature gate struct DummyStruct; diff --git a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr b/src/test/ui/feature-gates/feature-gate-auto-traits.stderr similarity index 78% rename from src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr rename to src/test/ui/feature-gates/feature-gate-auto-traits.stderr index 1553d0531d..e015418161 100644 --- a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr +++ b/src/test/ui/feature-gates/feature-gate-auto-traits.stderr @@ -1,14 +1,14 @@ error[E0658]: auto traits are experimental and possibly buggy - --> $DIR/feature-gate-optin-builtin-traits.rs:6:1 + --> $DIR/feature-gate-auto-traits.rs:6:1 | LL | auto trait AutoDummyTrait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #13231 for more information - = help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable + = help: add `#![feature(auto_traits)]` to the crate attributes to enable error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now - --> $DIR/feature-gate-optin-builtin-traits.rs:9:6 + --> $DIR/feature-gate-auto-traits.rs:9:6 | LL | impl !AutoDummyTrait for DummyStruct {} | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr index b33710ce04..f228711171 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr @@ -1,50 +1,50 @@ -error: cannot find attribute `lt_hof` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:51:21 +error: cannot find attribute `lt_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:4:15 | -LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 - | ^^^^^^ +LL | struct StLt<#[lt_struct] 'a>(&'a u32); + | ^^^^^^^^^ -error: cannot find attribute `ty_meth` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:46:15 +error: cannot find attribute `ty_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:6:15 | -LL | fn m_ty<#[ty_meth] P>(_: P) { } - | ^^^^^^^ +LL | struct StTy<#[ty_struct] I>(I); + | ^^^^^^^^^ -error: cannot find attribute `lt_meth` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:44:15 +error: cannot find attribute `lt_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:9:13 | -LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } - | ^^^^^^^ +LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } + | ^^^^^^^ -error: cannot find attribute `ty_fn` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:40:11 +error: cannot find attribute `ty_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:11:13 | -LL | fn f_ty<#[ty_fn] O>(_: O) { } - | ^^^^^ +LL | enum EnTy<#[ty_enum] J> { A(J), B } + | ^^^^^^^ -error: cannot find attribute `lt_fn` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:38:11 +error: cannot find attribute `lt_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:14:14 | -LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } - | ^^^^^ +LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } + | ^^^^^^^^ -error: cannot find attribute `ty_impl_for` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:33:8 +error: cannot find attribute `ty_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:16:14 | -LL | impl<#[ty_impl_for] N> TrTy for StTy { - | ^^^^^^^^^^^ +LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } + | ^^^^^^^^ -error: cannot find attribute `lt_impl_for` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:29:8 +error: cannot find attribute `lt_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:19:13 | -LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { - | ^^^^^^^^^^^ +LL | type TyLt<#[lt_type] 'd> = &'d u32; + | ^^^^^^^ -error: cannot find attribute `ty_inherent` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:26:8 +error: cannot find attribute `ty_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:21:13 | -LL | impl<#[ty_inherent] M> StTy { } - | ^^^^^^^^^^^ +LL | type TyTy<#[ty_type] L> = (L, ); + | ^^^^^^^ error: cannot find attribute `lt_inherent` in this scope --> $DIR/feature-gate-custom_attribute2.rs:24:8 @@ -52,53 +52,53 @@ error: cannot find attribute `lt_inherent` in this scope LL | impl<#[lt_inherent] 'e> StLt<'e> { } | ^^^^^^^^^^^ -error: cannot find attribute `ty_type` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:21:13 +error: cannot find attribute `ty_inherent` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:26:8 | -LL | type TyTy<#[ty_type] L> = (L, ); - | ^^^^^^^ +LL | impl<#[ty_inherent] M> StTy { } + | ^^^^^^^^^^^ -error: cannot find attribute `lt_type` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:19:13 +error: cannot find attribute `lt_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:29:8 | -LL | type TyLt<#[lt_type] 'd> = &'d u32; - | ^^^^^^^ +LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + | ^^^^^^^^^^^ -error: cannot find attribute `ty_trait` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:16:14 +error: cannot find attribute `ty_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:33:8 | -LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } - | ^^^^^^^^ +LL | impl<#[ty_impl_for] N> TrTy for StTy { + | ^^^^^^^^^^^ -error: cannot find attribute `lt_trait` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:14:14 +error: cannot find attribute `lt_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:38:11 | -LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } - | ^^^^^^^^ +LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } + | ^^^^^ -error: cannot find attribute `ty_enum` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:11:13 +error: cannot find attribute `ty_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:40:11 | -LL | enum EnTy<#[ty_enum] J> { A(J), B } - | ^^^^^^^ +LL | fn f_ty<#[ty_fn] O>(_: O) { } + | ^^^^^ -error: cannot find attribute `lt_enum` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:9:13 +error: cannot find attribute `lt_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:44:15 | -LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } - | ^^^^^^^ +LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + | ^^^^^^^ -error: cannot find attribute `ty_struct` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:6:15 +error: cannot find attribute `ty_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:46:15 | -LL | struct StTy<#[ty_struct] I>(I); - | ^^^^^^^^^ +LL | fn m_ty<#[ty_meth] P>(_: P) { } + | ^^^^^^^ -error: cannot find attribute `lt_struct` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:4:15 +error: cannot find attribute `lt_hof` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:51:21 | -LL | struct StLt<#[lt_struct] 'a>(&'a u32); - | ^^^^^^^^^ +LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 + | ^^^^^^ error: aborting due to 17 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs new file mode 100644 index 0000000000..f19fdb45f1 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs @@ -0,0 +1,8 @@ +#[cfg(FALSE)] +#[attr = multi::segment::path] //~ ERROR arbitrary expressions in key-value attributes are unstable +#[attr = macro_call!()] //~ ERROR arbitrary expressions in key-value attributes are unstable +#[attr = 1 + 2] //~ ERROR arbitrary expressions in key-value attributes are unstable +#[attr = what?] //~ ERROR arbitrary expressions in key-value attributes are unstable +struct S; + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr new file mode 100644 index 0000000000..9887814b90 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr @@ -0,0 +1,39 @@ +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:2:10 + | +LL | #[attr = multi::segment::path] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:3:10 + | +LL | #[attr = macro_call!()] + | ^^^^^^^^^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:4:10 + | +LL | #[attr = 1 + 2] + | ^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:5:10 + | +LL | #[attr = what?] + | ^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.rs b/src/test/ui/feature-gates/feature-gate-naked_functions.rs index 16a51a1e82..06bddc422c 100644 --- a/src/test/ui/feature-gates/feature-gate-naked_functions.rs +++ b/src/test/ui/feature-gates/feature-gate-naked_functions.rs @@ -1,11 +1,15 @@ +#![feature(asm)] + #[naked] //~^ the `#[naked]` attribute is an experimental feature -fn naked() {} +extern "C" fn naked() { + asm!("", options(noreturn)) +} #[naked] //~^ the `#[naked]` attribute is an experimental feature -fn naked_2() -> isize { - 0 +extern "C" fn naked_2() -> isize { + asm!("", options(noreturn)) } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr index e24dde5429..d95561d201 100644 --- a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr @@ -1,5 +1,5 @@ error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:1:1 + --> $DIR/feature-gate-naked_functions.rs:3:1 | LL | #[naked] | ^^^^^^^^ @@ -8,7 +8,7 @@ LL | #[naked] = help: add `#![feature(naked_functions)]` to the crate attributes to enable error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:5:1 + --> $DIR/feature-gate-naked_functions.rs:9:1 | LL | #[naked] | ^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs index 1208552d25..4c77180b76 100644 --- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs +++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs @@ -1,14 +1,17 @@ -#![feature(exclusive_range_pattern)] - -use std::usize::MAX; - fn main() { - match 0usize { //~ERROR non-exhaustive patterns: `_` not covered - 0..=MAX => {} + match 0usize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `usize` + //~| NOTE `usize` does not have a fixed maximum value + 0..=usize::MAX => {} } - match 0isize { //~ERROR non-exhaustive patterns: `_` not covered - 1..=20 => {} - -5..3 => {} + match 0isize { + //~^ ERROR non-exhaustive patterns: `_` not covered + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `isize` + //~| NOTE `isize` does not have a fixed maximum value + isize::MIN..=isize::MAX => {} } } diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index c7a63e5d50..9895646fc2 100644 --- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/feature-gate-precise_pointer_size_matching.rs:6:11 + --> $DIR/feature-gate-precise_pointer_size_matching.rs:2:11 | LL | match 0usize { | ^^^^^^ pattern `_` not covered diff --git a/src/test/ui/fmt/format-args-capture.rs b/src/test/ui/fmt/format-args-capture.rs index 9348bb46df..d5886a1355 100644 --- a/src/test/ui/fmt/format-args-capture.rs +++ b/src/test/ui/fmt/format-args-capture.rs @@ -31,6 +31,7 @@ fn panic_with_single_argument_does_not_get_formatted() { // RFC #2795 suggests that this may need to change so that captured arguments are formatted. // For stability reasons this will need to part of an edition change. + #[allow(non_fmt_panic)] let msg = std::panic::catch_unwind(|| { panic!("{foo}"); }).unwrap_err(); diff --git a/src/test/ui/if/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs similarity index 100% rename from src/test/ui/if/ifmt-bad-arg.rs rename to src/test/ui/fmt/ifmt-bad-arg.rs diff --git a/src/test/ui/if/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr similarity index 100% rename from src/test/ui/if/ifmt-bad-arg.stderr rename to src/test/ui/fmt/ifmt-bad-arg.stderr diff --git a/src/test/ui/if/ifmt-bad-format-args.rs b/src/test/ui/fmt/ifmt-bad-format-args.rs similarity index 100% rename from src/test/ui/if/ifmt-bad-format-args.rs rename to src/test/ui/fmt/ifmt-bad-format-args.rs diff --git a/src/test/ui/if/ifmt-bad-format-args.stderr b/src/test/ui/fmt/ifmt-bad-format-args.stderr similarity index 100% rename from src/test/ui/if/ifmt-bad-format-args.stderr rename to src/test/ui/fmt/ifmt-bad-format-args.stderr diff --git a/src/test/ui/if/ifmt-unimpl.rs b/src/test/ui/fmt/ifmt-unimpl.rs similarity index 100% rename from src/test/ui/if/ifmt-unimpl.rs rename to src/test/ui/fmt/ifmt-unimpl.rs diff --git a/src/test/ui/if/ifmt-unimpl.stderr b/src/test/ui/fmt/ifmt-unimpl.stderr similarity index 100% rename from src/test/ui/if/ifmt-unimpl.stderr rename to src/test/ui/fmt/ifmt-unimpl.stderr diff --git a/src/test/ui/if/ifmt-unknown-trait.rs b/src/test/ui/fmt/ifmt-unknown-trait.rs similarity index 100% rename from src/test/ui/if/ifmt-unknown-trait.rs rename to src/test/ui/fmt/ifmt-unknown-trait.rs diff --git a/src/test/ui/if/ifmt-unknown-trait.stderr b/src/test/ui/fmt/ifmt-unknown-trait.stderr similarity index 100% rename from src/test/ui/if/ifmt-unknown-trait.stderr rename to src/test/ui/fmt/ifmt-unknown-trait.stderr diff --git a/src/test/ui/fn/fn-recover-return-sign.fixed b/src/test/ui/fn/fn-recover-return-sign.fixed new file mode 100644 index 0000000000..076be6a35a --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.fixed @@ -0,0 +1,28 @@ +// run-rustfix +#![allow(unused)] +fn a() -> usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn b()-> usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { + let foo = |a: bool| -> bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(foo(false)); + + let bar = |a: bool|-> bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(bar(false)); +} diff --git a/src/test/ui/fn/fn-recover-return-sign.rs b/src/test/ui/fn/fn-recover-return-sign.rs new file mode 100644 index 0000000000..0656023c0f --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.rs @@ -0,0 +1,28 @@ +// run-rustfix +#![allow(unused)] +fn a() => usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn b(): usize { 0 } +//~^ ERROR return types are denoted using `->` + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { + let foo = |a: bool| => bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(foo(false)); + + let bar = |a: bool|: bool { a }; + //~^ ERROR return types are denoted using `->` + dbg!(bar(false)); +} diff --git a/src/test/ui/fn/fn-recover-return-sign.stderr b/src/test/ui/fn/fn-recover-return-sign.stderr new file mode 100644 index 0000000000..983109730f --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.stderr @@ -0,0 +1,26 @@ +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:3:8 + | +LL | fn a() => usize { 0 } + | ^^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:6:7 + | +LL | fn b(): usize { 0 } + | ^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:21:25 + | +LL | let foo = |a: bool| => bool { a }; + | ^^ help: use `->` instead + +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign.rs:25:24 + | +LL | let bar = |a: bool|: bool { a }; + | ^ help: use `->` instead + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/fn/fn-recover-return-sign2.rs b/src/test/ui/fn/fn-recover-return-sign2.rs new file mode 100644 index 0000000000..b6a6a1ec2a --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.rs @@ -0,0 +1,8 @@ +// Separate test file because `Fn() => bool` isn't getting fixed and rustfix complained that +// even though a fix was applied the code was still incorrect + +fn foo() => impl Fn() => bool { + //~^ ERROR return types are denoted using `->` + //~| ERROR expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>` + unimplemented!() +} diff --git a/src/test/ui/fn/fn-recover-return-sign2.stderr b/src/test/ui/fn/fn-recover-return-sign2.stderr new file mode 100644 index 0000000000..d62cacd4bf --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.stderr @@ -0,0 +1,14 @@ +error: return types are denoted using `->` + --> $DIR/fn-recover-return-sign2.rs:4:10 + | +LL | fn foo() => impl Fn() => bool { + | ^^ help: use `->` instead + +error: expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>` + --> $DIR/fn-recover-return-sign2.rs:4:23 + | +LL | fn foo() => impl Fn() => bool { + | ^^ expected one of `+`, `->`, `::`, `;`, `where`, or `{` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/foreign/foreign-pub-super.rs b/src/test/ui/foreign/foreign-pub-super.rs new file mode 100644 index 0000000000..19f9e4e339 --- /dev/null +++ b/src/test/ui/foreign/foreign-pub-super.rs @@ -0,0 +1,12 @@ +// Test for #79487 +// check-pass + +#![allow(dead_code)] + +mod sha2 { + extern "C" { + pub(super) fn GFp_sha512_block_data_order(); + } +} + +fn main() {} diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs index 1e77d8058a..8f1e4f1b66 100644 --- a/src/test/ui/generator/auto-trait-regions.rs +++ b/src/test/ui/generator/auto-trait-regions.rs @@ -1,5 +1,5 @@ #![feature(generators)] -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] auto trait Foo {} diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr index f23949091d..d590f876b8 100644 --- a/src/test/ui/generator/print/generator-print-verbose-2.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr @@ -8,8 +8,8 @@ LL | assert_send(|| { | ^^^^^^^^^^^ `Cell` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `Cell` - = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell` - = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell) _#17t]` + = note: required because of the requirements on the impl of `Send` for `&'_#4r Cell` + = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#4r Cell) _#17t]` error: generator cannot be shared between threads safely --> $DIR/generator-print-verbose-2.rs:12:5 diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs index c76726414d..5c10a7c781 100644 --- a/src/test/ui/generator/yielding-in-match-guards.rs +++ b/src/test/ui/generator/yielding-in-match-guards.rs @@ -10,6 +10,9 @@ // Thus, `&'_ u8` should be included in type signature // of the underlying generator. +#![feature(if_let_guard)] +#![allow(incomplete_features)] + async fn f() -> u8 { 1 } async fn foo() -> [bool; 10] { [false; 10] } @@ -36,8 +39,16 @@ async fn i(x: u8) { } } +async fn j(x: u8) { + match x { + y if let (1, 42) = (f().await, y) => (), + _ => (), + } +} + fn main() { let _ = g(10); let _ = h(9); let _ = i(8); + let _ = j(7); } diff --git a/src/test/ui/generic-associated-types/issue-74824.rs b/src/test/ui/generic-associated-types/issue-74824.rs new file mode 100644 index 0000000000..00761a97d0 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74824.rs @@ -0,0 +1,27 @@ +#![feature(generic_associated_types)] +#![feature(associated_type_defaults)] +#![allow(incomplete_features)] + +use std::ops::Deref; + +trait UnsafeCopy { + type Copy: Copy = Box; + //~^ ERROR the trait bound `Box: Copy` is not satisfied + //~^^ ERROR the trait bound `T: Clone` is not satisfied + fn copy(x: &Self::Copy) -> Self::Copy { + *x + } +} + +impl UnsafeCopy for T {} + +fn main() { + let b = Box::new(42usize); + let copy = <()>::copy(&b); + + let raw_b = Box::deref(&b) as *const _; + let raw_copy = Box::deref(©) as *const _; + + // assert the addresses. + assert_eq!(raw_b, raw_copy); +} diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr new file mode 100644 index 0000000000..34a2c1932e --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74824.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `Box: Copy` is not satisfied + --> $DIR/issue-74824.rs:8:5 + | +LL | type Copy: Copy = Box; + | ^^^^^^^^^^^^^^----^^^^^^^^^^ + | | | + | | required by this bound in `UnsafeCopy::Copy` + | the trait `Copy` is not implemented for `Box` + +error[E0277]: the trait bound `T: Clone` is not satisfied + --> $DIR/issue-74824.rs:8:5 + | +LL | type Copy: Copy = Box; + | ^^^^^^^^^^^^^^----^^^^^^^^^^ + | | | + | | required by this bound in `UnsafeCopy::Copy` + | the trait `Clone` is not implemented for `T` + | + = note: required because of the requirements on the impl of `Clone` for `Box` +help: consider restricting type parameter `T` + | +LL | type Copy: Copy = Box; + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs new file mode 100644 index 0000000000..b10bfea9fe --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs @@ -0,0 +1,11 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +trait X { + type Y<'a>; +} + +fn f1<'a>(arg : Box>) {} + //~^ ERROR: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr new file mode 100644 index 0000000000..051253cadc --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr @@ -0,0 +1,17 @@ +error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` + --> $DIR/trait-path-expected-token.rs:8:33 + | +LL | fn f1<'a>(arg : Box>) {} + | ^ expected one of 7 possible tokens + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-expected-token.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs new file mode 100644 index 0000000000..de61cfa1cf --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs @@ -0,0 +1,23 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +mod error1 { + trait X { + type Y<'a>; + } + + fn f1<'a>(arg : Box>) {} + //~^ ERROR: expected expression, found `)` +} + +mod error2 { + + trait X { + type Y<'a>; + } + + fn f2<'a>(arg : Box>) {} + //~^ ERROR: only types can be used in associated type constraints +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr new file mode 100644 index 0000000000..a9ba8adcab --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr @@ -0,0 +1,25 @@ +error: expected expression, found `)` + --> $DIR/trait-path-expressions.rs:9:39 + | +LL | fn f1<'a>(arg : Box>) {} + | - ^ expected expression + | | + | while parsing a const generic argument starting here + +error: only types can be used in associated type constraints + --> $DIR/trait-path-expressions.rs:19:30 + | +LL | fn f2<'a>(arg : Box>) {} + | ^^^^^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-expressions.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs new file mode 100644 index 0000000000..94dda17aad --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs @@ -0,0 +1,21 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +trait X { + type Y<'a>; +} + +const _: () = { + fn f1<'a>(arg : Box>) {} + //~^ ERROR: expected one of `>`, a const expression, lifetime, or type, found `:` + //~| ERROR: expected parameter name, found `>` + //~| ERROR: expected one of `!`, `)`, `+`, `,`, or `::`, found `>` + //~| ERROR: constant provided when a type was expected +}; + +const _: () = { + fn f1<'a>(arg : Box>) {} + //~^ ERROR: expected one of `>`, a const expression, lifetime, or type, found `=` +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr new file mode 100644 index 0000000000..8a5e2c29c3 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr @@ -0,0 +1,50 @@ +error: expected one of `>`, a const expression, lifetime, or type, found `:` + --> $DIR/trait-path-missing-gen_arg.rs:9:30 + | +LL | fn f1<'a>(arg : Box>) {} + | ^ expected one of `>`, a const expression, lifetime, or type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | fn f1<'a>(arg : Box<{ dyn X< : 32 } >>) {} + | ^ ^ + +error: expected parameter name, found `>` + --> $DIR/trait-path-missing-gen_arg.rs:9:36 + | +LL | fn f1<'a>(arg : Box>) {} + | ^ expected parameter name + +error: expected one of `!`, `)`, `+`, `,`, or `::`, found `>` + --> $DIR/trait-path-missing-gen_arg.rs:9:36 + | +LL | fn f1<'a>(arg : Box>) {} + | ^ + | | + | expected one of `!`, `)`, `+`, `,`, or `::` + | help: missing `,` + +error: expected one of `>`, a const expression, lifetime, or type, found `=` + --> $DIR/trait-path-missing-gen_arg.rs:17:30 + | +LL | fn f1<'a>(arg : Box>) {} + | ^ expected one of `>`, a const expression, lifetime, or type + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-missing-gen_arg.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0747]: constant provided when a type was expected + --> $DIR/trait-path-missing-gen_arg.rs:9:23 + | +LL | fn f1<'a>(arg : Box>) {} + | ^^^^^^^^^^^ + +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs new file mode 100644 index 0000000000..0bf48b1f41 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs @@ -0,0 +1,35 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +const _: () = { + trait X { + type Y<'a>; + } + + fn f1<'a>(arg : Box>) {} + //~^ ERROR: paths with multiple segments cannot be used in associated type constraints + }; + +const _: () = { + trait X { + type Y<'a>; + } + + trait Z {} + + impl::Y<'a> = &'a u32>> Z for T {} + //~^ ERROR: qualified paths cannot be used in associated type constraints +}; + +const _: () = { + trait X { + type Y<'a>; + } + + trait Z {} + + impl = &'a u32>> Z for T {} + //~^ ERROR: paths with multiple segments cannot be used in associated type constraints +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr new file mode 100644 index 0000000000..4e2b84d018 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr @@ -0,0 +1,31 @@ +error: paths with multiple segments cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:9:31 + | +LL | fn f1<'a>(arg : Box>) {} + | ^^^^ + +error: qualified paths cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:20:16 + | +LL | impl::Y<'a> = &'a u32>> Z for T {} + | ^^^^^^^^^-^^^^^^^^ + | | + | not allowed in associated type constraints + +error: paths with multiple segments cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:31:16 + | +LL | impl = &'a u32>> Z for T {} + | ^^^^^^^^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-segments.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs new file mode 100644 index 0000000000..e203a5e0d2 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs @@ -0,0 +1,10 @@ +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +const _: () = { + fn f2<'a>(arg : Box = &'a ()>>) {} + //~^ ERROR: generic associated types in trait paths are currently not implemented +}; diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr new file mode 100644 index 0000000000..e59a72a99e --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -0,0 +1,8 @@ +error: generic associated types in trait paths are currently not implemented + --> $DIR/trait-path-type-error-once-implemented.rs:8:30 + | +LL | fn f2<'a>(arg : Box = &'a ()>>) {} + | ^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.rs b/src/test/ui/generic-associated-types/parse/trait-path-types.rs new file mode 100644 index 0000000000..6cdb501ec6 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.rs @@ -0,0 +1,23 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +trait X { + type Y<'a>; +} + +const _: () = { + fn f<'a>(arg : Box>) {} + //~^ ERROR: only path types can be used in associated type constraints +}; + +const _: () = { + fn f1<'a>(arg : Box) = &'a ()>>) {} + //~^ ERROR: only path types can be used in associated type constraints +}; + +const _: () = { + fn f1<'a>(arg : Box>) {} + //~^ ERROR: only types can be used in associated type constraints +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr new file mode 100644 index 0000000000..f5be084613 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr @@ -0,0 +1,29 @@ +error: only path types can be used in associated type constraints + --> $DIR/trait-path-types.rs:9:29 + | +LL | fn f<'a>(arg : Box>) {} + | ^^^^^^^ + +error: only path types can be used in associated type constraints + --> $DIR/trait-path-types.rs:14:29 + | +LL | fn f1<'a>(arg : Box) = &'a ()>>) {} + | ^^^^^^^ + +error: only types can be used in associated type constraints + --> $DIR/trait-path-types.rs:19:30 + | +LL | fn f1<'a>(arg : Box>) {} + | ^^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-types.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs new file mode 100644 index 0000000000..02d53d5fae --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs @@ -0,0 +1,17 @@ +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +const _: () = { + fn f1<'a>(arg : Box = &'a ()>>) {} + //~^ ERROR: generic associated types in trait paths are currently not implemented +}; + +const _: () = { + fn f1<'a>(arg : Box>) {} + //~^ ERROR: lifetime in trait object type must be followed by `+` +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr new file mode 100644 index 0000000000..1fba9cebd2 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr @@ -0,0 +1,14 @@ +error: lifetime in trait object type must be followed by `+` + --> $DIR/trait-path-unimplemented.rs:13:31 + | +LL | fn f1<'a>(arg : Box>) {} + | ^^ + +error: generic associated types in trait paths are currently not implemented + --> $DIR/trait-path-unimplemented.rs:8:30 + | +LL | fn f1<'a>(arg : Box = &'a ()>>) {} + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index d51c29080a..95cebbb868 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -20,7 +20,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | trait Shadow<'a> { | -- first declared here LL | type Bar<'a>; - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope --> $DIR/shadowing.rs:14:14 @@ -28,7 +28,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> NoShadow<'a> for &'a u32 { | -- first declared here LL | type Bar<'a> = i32; - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error: aborting due to 4 previous errors diff --git a/src/test/ui/generics/generic-impl-more-params-with-defaults.stderr b/src/test/ui/generics/generic-impl-more-params-with-defaults.stderr index 66950d450a..380e9209e6 100644 --- a/src/test/ui/generics/generic-impl-more-params-with-defaults.stderr +++ b/src/test/ui/generics/generic-impl-more-params-with-defaults.stderr @@ -1,8 +1,8 @@ error[E0107]: wrong number of type arguments: expected at most 2, found 3 - --> $DIR/generic-impl-more-params-with-defaults.rs:13:5 + --> $DIR/generic-impl-more-params-with-defaults.rs:13:24 | LL | Vec::::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type arguments + | ^^^^ unexpected type argument error: aborting due to previous error diff --git a/src/test/ui/generics/generic-type-more-params-with-defaults.stderr b/src/test/ui/generics/generic-type-more-params-with-defaults.stderr index 5031930b1b..cc296b5105 100644 --- a/src/test/ui/generics/generic-type-more-params-with-defaults.stderr +++ b/src/test/ui/generics/generic-type-more-params-with-defaults.stderr @@ -1,8 +1,8 @@ error[E0107]: wrong number of type arguments: expected at most 2, found 3 - --> $DIR/generic-type-more-params-with-defaults.rs:9:12 + --> $DIR/generic-type-more-params-with-defaults.rs:9:29 | LL | let _: Vec; - | ^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type arguments + | ^^^^ unexpected type argument error: aborting due to previous error diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs index b135891d0b..be225359bf 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs @@ -13,8 +13,8 @@ macro_rules! m { } fn floats() { - m!(0f32, core::f32::NEG_INFINITY..); //~ ERROR non-exhaustive patterns: `_` not covered - m!(0f32, ..core::f32::INFINITY); //~ ERROR non-exhaustive patterns: `_` not covered + m!(0f32, f32::NEG_INFINITY..); //~ ERROR non-exhaustive patterns: `_` not covered + m!(0f32, ..f32::INFINITY); //~ ERROR non-exhaustive patterns: `_` not covered } fn khar() { @@ -33,12 +33,12 @@ fn khar() { mod unsigned { fn u8() { - const ALMOST_MAX: u8 = core::u8::MAX - 1; - const ALMOST_MIN: u8 = core::u8::MIN + 1; + const ALMOST_MAX: u8 = u8::MAX - 1; + const ALMOST_MIN: u8 = u8::MIN + 1; const VAL: u8 = 42; const VAL_1: u8 = VAL + 1; const VAL_2: u8 = VAL + 2; - m!(0, ..core::u8::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..u8::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -46,12 +46,12 @@ mod unsigned { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn u16() { - const ALMOST_MAX: u16 = core::u16::MAX - 1; - const ALMOST_MIN: u16 = core::u16::MIN + 1; + const ALMOST_MAX: u16 = u16::MAX - 1; + const ALMOST_MIN: u16 = u16::MIN + 1; const VAL: u16 = 42; const VAL_1: u16 = VAL + 1; const VAL_2: u16 = VAL + 2; - m!(0, ..core::u16::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..u16::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -59,12 +59,12 @@ mod unsigned { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn u32() { - const ALMOST_MAX: u32 = core::u32::MAX - 1; - const ALMOST_MIN: u32 = core::u32::MIN + 1; + const ALMOST_MAX: u32 = u32::MAX - 1; + const ALMOST_MIN: u32 = u32::MIN + 1; const VAL: u32 = 42; const VAL_1: u32 = VAL + 1; const VAL_2: u32 = VAL + 2; - m!(0, ..core::u32::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..u32::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -72,12 +72,12 @@ mod unsigned { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn u64() { - const ALMOST_MAX: u64 = core::u64::MAX - 1; - const ALMOST_MIN: u64 = core::u64::MIN + 1; + const ALMOST_MAX: u64 = u64::MAX - 1; + const ALMOST_MIN: u64 = u64::MIN + 1; const VAL: u64 = 42; const VAL_1: u64 = VAL + 1; const VAL_2: u64 = VAL + 2; - m!(0, ..core::u64::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..u64::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -85,12 +85,12 @@ mod unsigned { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn u128() { - const ALMOST_MAX: u128 = core::u128::MAX - 1; - const ALMOST_MIN: u128 = core::u128::MIN + 1; + const ALMOST_MAX: u128 = u128::MAX - 1; + const ALMOST_MIN: u128 = u128::MIN + 1; const VAL: u128 = 42; const VAL_1: u128 = VAL + 1; const VAL_2: u128 = VAL + 2; - m!(0, ..core::u128::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..u128::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -101,12 +101,12 @@ mod unsigned { mod signed { fn i8() { - const ALMOST_MAX: i8 = core::i8::MAX - 1; - const ALMOST_MIN: i8 = core::i8::MIN + 1; + const ALMOST_MAX: i8 = i8::MAX - 1; + const ALMOST_MIN: i8 = i8::MIN + 1; const VAL: i8 = 42; const VAL_1: i8 = VAL + 1; const VAL_2: i8 = VAL + 2; - m!(0, ..core::i8::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..i8::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -114,12 +114,12 @@ mod signed { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn i16() { - const ALMOST_MAX: i16 = core::i16::MAX - 1; - const ALMOST_MIN: i16 = core::i16::MIN + 1; + const ALMOST_MAX: i16 = i16::MAX - 1; + const ALMOST_MIN: i16 = i16::MIN + 1; const VAL: i16 = 42; const VAL_1: i16 = VAL + 1; const VAL_2: i16 = VAL + 2; - m!(0, ..core::i16::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..i16::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -127,12 +127,12 @@ mod signed { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn i32() { - const ALMOST_MAX: i32 = core::i32::MAX - 1; - const ALMOST_MIN: i32 = core::i32::MIN + 1; + const ALMOST_MAX: i32 = i32::MAX - 1; + const ALMOST_MIN: i32 = i32::MIN + 1; const VAL: i32 = 42; const VAL_1: i32 = VAL + 1; const VAL_2: i32 = VAL + 2; - m!(0, ..core::i32::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..i32::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -140,12 +140,12 @@ mod signed { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn i64() { - const ALMOST_MAX: i64 = core::i64::MAX - 1; - const ALMOST_MIN: i64 = core::i64::MIN + 1; + const ALMOST_MAX: i64 = i64::MAX - 1; + const ALMOST_MIN: i64 = i64::MIN + 1; const VAL: i64 = 42; const VAL_1: i64 = VAL + 1; const VAL_2: i64 = VAL + 2; - m!(0, ..core::i64::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..i64::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns @@ -153,12 +153,12 @@ mod signed { m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns } fn i128() { - const ALMOST_MAX: i128 = core::i128::MAX - 1; - const ALMOST_MIN: i128 = core::i128::MIN + 1; + const ALMOST_MAX: i128 = i128::MAX - 1; + const ALMOST_MIN: i128 = i128::MIN + 1; const VAL: i128 = 42; const VAL_1: i128 = VAL + 1; const VAL_2: i128 = VAL + 2; - m!(0, ..core::i128::MAX); //~ ERROR non-exhaustive patterns + m!(0, ..i128::MAX); //~ ERROR non-exhaustive patterns m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr index 5744232235..14dbca60b7 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr @@ -1,7 +1,7 @@ error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8 | -LL | m!(0f32, core::f32::NEG_INFINITY..); +LL | m!(0f32, f32::NEG_INFINITY..); | ^^^^ pattern `_` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -10,7 +10,7 @@ LL | m!(0f32, core::f32::NEG_INFINITY..); error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:17:8 | -LL | m!(0f32, ..core::f32::INFINITY); +LL | m!(0f32, ..f32::INFINITY); | ^^^^ pattern `_` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -73,7 +73,7 @@ LL | m!('a', ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `u8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12 | -LL | m!(0, ..core::u8::MAX); +LL | m!(0, ..u8::MAX); | ^ pattern `u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -127,7 +127,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `u16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12 | -LL | m!(0, ..core::u16::MAX); +LL | m!(0, ..u16::MAX); | ^ pattern `u16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -181,7 +181,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `u32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12 | -LL | m!(0, ..core::u32::MAX); +LL | m!(0, ..u32::MAX); | ^ pattern `u32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -235,7 +235,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `u64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12 | -LL | m!(0, ..core::u64::MAX); +LL | m!(0, ..u64::MAX); | ^ pattern `u64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -289,7 +289,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `u128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12 | -LL | m!(0, ..core::u128::MAX); +LL | m!(0, ..u128::MAX); | ^ pattern `u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -343,7 +343,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `i8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12 | -LL | m!(0, ..core::i8::MAX); +LL | m!(0, ..i8::MAX); | ^ pattern `i8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -397,7 +397,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `i16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12 | -LL | m!(0, ..core::i16::MAX); +LL | m!(0, ..i16::MAX); | ^ pattern `i16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -451,7 +451,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `i32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12 | -LL | m!(0, ..core::i32::MAX); +LL | m!(0, ..i32::MAX); | ^ pattern `i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -505,7 +505,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `i64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12 | -LL | m!(0, ..core::i64::MAX); +LL | m!(0, ..i64::MAX); | ^ pattern `i64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms @@ -559,7 +559,7 @@ LL | m!(0, ..VAL_1 | VAL_2..); error[E0004]: non-exhaustive patterns: `i128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12 | -LL | m!(0, ..core::i128::MAX); +LL | m!(0, ..i128::MAX); | ^ pattern `i128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs index efac0df2a4..d3a59e4dff 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs @@ -26,19 +26,19 @@ macro_rules! test_int { } fn unsigned_int() { - test_int!(0u8, core::u8::MIN, core::u8::MAX); - test_int!(0u16, core::u16::MIN, core::u16::MAX); - test_int!(0u32, core::u32::MIN, core::u32::MAX); - test_int!(0u64, core::u64::MIN, core::u64::MAX); - test_int!(0u128, core::u128::MIN, core::u128::MAX); + test_int!(0u8, u8::MIN, u8::MAX); + test_int!(0u16, u16::MIN, u16::MAX); + test_int!(0u32, u32::MIN, u32::MAX); + test_int!(0u64, u64::MIN, u64::MAX); + test_int!(0u128, u128::MIN, u128::MAX); } fn signed_int() { - test_int!(0i8, core::i8::MIN, core::i8::MAX); - test_int!(0i16, core::i16::MIN, core::i16::MAX); - test_int!(0i32, core::i32::MIN, core::i32::MAX); - test_int!(0i64, core::i64::MIN, core::i64::MAX); - test_int!(0i128, core::i128::MIN, core::i128::MAX); + test_int!(0i8, i8::MIN, i8::MAX); + test_int!(0i16, i16::MIN, i16::MAX); + test_int!(0i32, i32::MIN, i32::MAX); + test_int!(0i64, i64::MIN, i64::MAX); + test_int!(0i128, i128::MIN, i128::MAX); } fn khar() { diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-semantics.rs index 416c59af3f..ae532d935d 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-semantics.rs +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-semantics.rs @@ -24,15 +24,15 @@ fn range_to_inclusive() { //--------------------------------------- // u8; `..=X` - assert!(yes!(core::u8::MIN, ..=core::u8::MIN)); - assert!(yes!(core::u8::MIN, ..=5)); + assert!(yes!(u8::MIN, ..=u8::MIN)); + assert!(yes!(u8::MIN, ..=5)); assert!(yes!(5u8, ..=5)); assert!(!yes!(6u8, ..=5)); // i16; `..=X` - assert!(yes!(core::i16::MIN, ..=core::i16::MIN)); - assert!(yes!(core::i16::MIN, ..=0)); - assert!(yes!(core::i16::MIN, ..=-5)); + assert!(yes!(i16::MIN, ..=i16::MIN)); + assert!(yes!(i16::MIN, ..=0)); + assert!(yes!(i16::MIN, ..=-5)); assert!(yes!(-5, ..=-5)); assert!(!yes!(-4, ..=-5)); @@ -43,14 +43,14 @@ fn range_to_inclusive() { assert!(!yes!('b', ..='a')); // f32; `..=X` - assert!(yes!(core::f32::NEG_INFINITY, ..=core::f32::NEG_INFINITY)); - assert!(yes!(core::f32::NEG_INFINITY, ..=1.0f32)); + assert!(yes!(f32::NEG_INFINITY, ..=f32::NEG_INFINITY)); + assert!(yes!(f32::NEG_INFINITY, ..=1.0f32)); assert!(yes!(1.5f32, ..=1.5f32)); assert!(!yes!(1.6f32, ..=-1.5f32)); // f64; `..=X` - assert!(yes!(core::f64::NEG_INFINITY, ..=core::f64::NEG_INFINITY)); - assert!(yes!(core::f64::NEG_INFINITY, ..=1.0f64)); + assert!(yes!(f64::NEG_INFINITY, ..=f64::NEG_INFINITY)); + assert!(yes!(f64::NEG_INFINITY, ..=1.0f64)); assert!(yes!(1.5f64, ..=1.5f64)); assert!(!yes!(1.6f64, ..=-1.5f64)); } @@ -66,16 +66,16 @@ fn range_to() { assert!(!yes!(6u8, ..5)); // u8; `..X` - const NU8: u8 = core::u8::MIN + 1; - assert!(yes!(core::u8::MIN, ..NU8)); + const NU8: u8 = u8::MIN + 1; + assert!(yes!(u8::MIN, ..NU8)); assert!(yes!(0u8, ..5)); assert!(!yes!(5u8, ..5)); assert!(!yes!(6u8, ..5)); // i16; `..X` - const NI16: i16 = core::i16::MIN + 1; - assert!(yes!(core::i16::MIN, ..NI16)); - assert!(yes!(core::i16::MIN, ..5)); + const NI16: i16 = i16::MIN + 1; + assert!(yes!(i16::MIN, ..NI16)); + assert!(yes!(i16::MIN, ..5)); assert!(yes!(-6, ..-5)); assert!(!yes!(-5, ..-5)); @@ -87,16 +87,16 @@ fn range_to() { assert!(!yes!('b', ..'a')); // f32; `..X` - assert!(yes!(core::f32::NEG_INFINITY, ..1.0f32)); + assert!(yes!(f32::NEG_INFINITY, ..1.0f32)); assert!(!yes!(1.5f32, ..1.5f32)); - const E32: f32 = 1.5f32 + core::f32::EPSILON; + const E32: f32 = 1.5f32 + f32::EPSILON; assert!(yes!(1.5f32, ..E32)); assert!(!yes!(1.6f32, ..1.5f32)); // f64; `..X` - assert!(yes!(core::f64::NEG_INFINITY, ..1.0f64)); + assert!(yes!(f64::NEG_INFINITY, ..1.0f64)); assert!(!yes!(1.5f64, ..1.5f64)); - const E64: f64 = 1.5f64 + core::f64::EPSILON; + const E64: f64 = 1.5f64 + f64::EPSILON; assert!(yes!(1.5f64, ..E64)); assert!(!yes!(1.6f64, ..1.5f64)); } @@ -106,23 +106,23 @@ fn range_from() { //-------------------------------- // u8; `X..` - assert!(yes!(core::u8::MIN, core::u8::MIN..)); - assert!(yes!(core::u8::MAX, core::u8::MIN..)); - assert!(!yes!(core::u8::MIN, 1..)); + assert!(yes!(u8::MIN, u8::MIN..)); + assert!(yes!(u8::MAX, u8::MIN..)); + assert!(!yes!(u8::MIN, 1..)); assert!(!yes!(4, 5..)); assert!(yes!(5, 5..)); assert!(yes!(6, 5..)); - assert!(yes!(core::u8::MAX, core::u8::MAX..)); + assert!(yes!(u8::MAX, u8::MAX..)); // i16; `X..` - assert!(yes!(core::i16::MIN, core::i16::MIN..)); - assert!(yes!(core::i16::MAX, core::i16::MIN..)); - const NI16: i16 = core::i16::MIN + 1; - assert!(!yes!(core::i16::MIN, NI16..)); + assert!(yes!(i16::MIN, i16::MIN..)); + assert!(yes!(i16::MAX, i16::MIN..)); + const NI16: i16 = i16::MIN + 1; + assert!(!yes!(i16::MIN, NI16..)); assert!(!yes!(-4, 5..)); assert!(yes!(-4, -4..)); assert!(yes!(-3, -4..)); - assert!(yes!(core::i16::MAX, core::i16::MAX..)); + assert!(yes!(i16::MAX, i16::MAX..)); // char; `X..` assert!(yes!('\u{0}', '\u{0}'..)); @@ -133,24 +133,24 @@ fn range_from() { assert!(yes!(core::char::MAX, core::char::MAX..)); // f32; `X..` - assert!(yes!(core::f32::NEG_INFINITY, core::f32::NEG_INFINITY..)); - assert!(yes!(core::f32::INFINITY, core::f32::NEG_INFINITY..)); - assert!(!yes!(core::f32::NEG_INFINITY, 1.0f32..)); - assert!(yes!(core::f32::INFINITY, 1.0f32..)); - assert!(!yes!(1.0f32 - core::f32::EPSILON, 1.0f32..)); + assert!(yes!(f32::NEG_INFINITY, f32::NEG_INFINITY..)); + assert!(yes!(f32::INFINITY, f32::NEG_INFINITY..)); + assert!(!yes!(f32::NEG_INFINITY, 1.0f32..)); + assert!(yes!(f32::INFINITY, 1.0f32..)); + assert!(!yes!(1.0f32 - f32::EPSILON, 1.0f32..)); assert!(yes!(1.0f32, 1.0f32..)); - assert!(yes!(core::f32::INFINITY, 1.0f32..)); - assert!(yes!(core::f32::INFINITY, core::f32::INFINITY..)); + assert!(yes!(f32::INFINITY, 1.0f32..)); + assert!(yes!(f32::INFINITY, f32::INFINITY..)); // f64; `X..` - assert!(yes!(core::f64::NEG_INFINITY, core::f64::NEG_INFINITY..)); - assert!(yes!(core::f64::INFINITY, core::f64::NEG_INFINITY..)); - assert!(!yes!(core::f64::NEG_INFINITY, 1.0f64..)); - assert!(yes!(core::f64::INFINITY, 1.0f64..)); - assert!(!yes!(1.0f64 - core::f64::EPSILON, 1.0f64..)); + assert!(yes!(f64::NEG_INFINITY, f64::NEG_INFINITY..)); + assert!(yes!(f64::INFINITY, f64::NEG_INFINITY..)); + assert!(!yes!(f64::NEG_INFINITY, 1.0f64..)); + assert!(yes!(f64::INFINITY, 1.0f64..)); + assert!(!yes!(1.0f64 - f64::EPSILON, 1.0f64..)); assert!(yes!(1.0f64, 1.0f64..)); - assert!(yes!(core::f64::INFINITY, 1.0f64..)); - assert!(yes!(core::f64::INFINITY, core::f64::INFINITY..)); + assert!(yes!(f64::INFINITY, 1.0f64..)); + assert!(yes!(f64::INFINITY, f64::INFINITY..)); } fn main() { diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs index 904efda903..2c8e554b22 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs @@ -9,42 +9,42 @@ macro_rules! m { } fn main() { - m!(0, ..core::u8::MIN); + m!(0, ..u8::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::u16::MIN); + m!(0, ..u16::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::u32::MIN); + m!(0, ..u32::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::u64::MIN); + m!(0, ..u64::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::u128::MIN); + m!(0, ..u128::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::i8::MIN); + m!(0, ..i8::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::i16::MIN); + m!(0, ..i16::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::i32::MIN); + m!(0, ..i32::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::i64::MIN); + m!(0, ..i64::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0, ..core::i128::MIN); + m!(0, ..i128::MIN); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0f32, ..core::f32::NEG_INFINITY); + m!(0f32, ..f32::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper - m!(0f64, ..core::f64::NEG_INFINITY); + m!(0f64, ..f64::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper //~| ERROR lower range bound must be less than upper diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr index 12ad864296..4931ddfac7 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr @@ -1,74 +1,74 @@ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:12:11 | -LL | m!(0, ..core::u8::MIN); - | ^^^^^^^^^^^^^^^ +LL | m!(0, ..u8::MIN); + | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11 | -LL | m!(0, ..core::u16::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..u16::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:18:11 | -LL | m!(0, ..core::u32::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..u32::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:21:11 | -LL | m!(0, ..core::u64::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..u64::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11 | -LL | m!(0, ..core::u128::MIN); - | ^^^^^^^^^^^^^^^^^ +LL | m!(0, ..u128::MIN); + | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11 | -LL | m!(0, ..core::i8::MIN); - | ^^^^^^^^^^^^^^^ +LL | m!(0, ..i8::MIN); + | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:31:11 | -LL | m!(0, ..core::i16::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..i16::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:34:11 | -LL | m!(0, ..core::i32::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..i32::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:37:11 | -LL | m!(0, ..core::i64::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..i64::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:40:11 | -LL | m!(0, ..core::i128::MIN); - | ^^^^^^^^^^^^^^^^^ +LL | m!(0, ..i128::MIN); + | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:44:14 | -LL | m!(0f32, ..core::f32::NEG_INFINITY); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | m!(0f32, ..f32::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:47:14 | -LL | m!(0f64, ..core::f64::NEG_INFINITY); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | m!(0f64, ..f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:51:13 @@ -79,74 +79,74 @@ LL | m!('a', ..'\u{0}'); error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:12:11 | -LL | m!(0, ..core::u8::MIN); - | ^^^^^^^^^^^^^^^ +LL | m!(0, ..u8::MIN); + | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11 | -LL | m!(0, ..core::u16::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..u16::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:18:11 | -LL | m!(0, ..core::u32::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..u32::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:21:11 | -LL | m!(0, ..core::u64::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..u64::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11 | -LL | m!(0, ..core::u128::MIN); - | ^^^^^^^^^^^^^^^^^ +LL | m!(0, ..u128::MIN); + | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11 | -LL | m!(0, ..core::i8::MIN); - | ^^^^^^^^^^^^^^^ +LL | m!(0, ..i8::MIN); + | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:31:11 | -LL | m!(0, ..core::i16::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..i16::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:34:11 | -LL | m!(0, ..core::i32::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..i32::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:37:11 | -LL | m!(0, ..core::i64::MIN); - | ^^^^^^^^^^^^^^^^ +LL | m!(0, ..i64::MIN); + | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:40:11 | -LL | m!(0, ..core::i128::MIN); - | ^^^^^^^^^^^^^^^^^ +LL | m!(0, ..i128::MIN); + | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:44:14 | -LL | m!(0f32, ..core::f32::NEG_INFINITY); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | m!(0f32, ..f32::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:47:14 | -LL | m!(0f64, ..core::f64::NEG_INFINITY); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | m!(0f64, ..f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:51:13 diff --git a/src/test/ui/hashmap/hashmap-capacity-overflow.rs b/src/test/ui/hashmap/hashmap-capacity-overflow.rs index 5f88683f4a..2988af0655 100644 --- a/src/test/ui/hashmap/hashmap-capacity-overflow.rs +++ b/src/test/ui/hashmap/hashmap-capacity-overflow.rs @@ -3,7 +3,6 @@ // ignore-emscripten no processes use std::collections::hash_map::HashMap; -use std::usize; use std::mem::size_of; fn main() { diff --git a/src/test/ui/hidden-rt-injection.rs b/src/test/ui/hidden-rt-injection.rs deleted file mode 100644 index 3ca04f9349..0000000000 --- a/src/test/ui/hidden-rt-injection.rs +++ /dev/null @@ -1,8 +0,0 @@ -// This is testing that users can't access the runtime crate. - -mod m { - // The rt has been called both 'native' and 'rt' - use native; //~ ERROR unresolved import -} - -fn main() { } diff --git a/src/test/ui/hidden-rt-injection.stderr b/src/test/ui/hidden-rt-injection.stderr deleted file mode 100644 index 3e288b72ec..0000000000 --- a/src/test/ui/hidden-rt-injection.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0432]: unresolved import `native` - --> $DIR/hidden-rt-injection.rs:5:9 - | -LL | use native; - | ^^^^^^ no `native` in the root - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/hidden-rt-injection2.rs b/src/test/ui/hidden-rt-injection2.rs deleted file mode 100644 index 2af113c05e..0000000000 --- a/src/test/ui/hidden-rt-injection2.rs +++ /dev/null @@ -1,8 +0,0 @@ -// This is testing that users can't access the runtime crate. - -mod m { - // The rt has been called both 'native' and 'rt' - use rt; //~ ERROR unresolved import -} - -fn main() { } diff --git a/src/test/ui/hidden-rt-injection2.stderr b/src/test/ui/hidden-rt-injection2.stderr deleted file mode 100644 index 73f89b5856..0000000000 --- a/src/test/ui/hidden-rt-injection2.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0432]: unresolved import `rt` - --> $DIR/hidden-rt-injection2.rs:5:9 - | -LL | use rt; - | ^^ no `rt` in the root - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/huge-array-simple-32.stderr b/src/test/ui/huge-array-simple-32.stderr index d734a9689e..31e120df62 100644 --- a/src/test/ui/huge-array-simple-32.stderr +++ b/src/test/ui/huge-array-simple-32.stderr @@ -1,4 +1,4 @@ -error: the type `[u8; 2147516416]` is too big for the current architecture +error: values of the type `[u8; 2147516416]` are too big for the current architecture --> $DIR/huge-array-simple-32.rs:10:9 | LL | let _fat: [u8; (1<<31)+(1<<15)] = diff --git a/src/test/ui/huge-array-simple-64.stderr b/src/test/ui/huge-array-simple-64.stderr index 791baa8468..c5d3fe85d0 100644 --- a/src/test/ui/huge-array-simple-64.stderr +++ b/src/test/ui/huge-array-simple-64.stderr @@ -1,4 +1,4 @@ -error: the type `[u8; 2305843011361177600]` is too big for the current architecture +error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture --> $DIR/huge-array-simple-64.rs:10:9 | LL | let _fat: [u8; (1<<61)+(1<<31)] = diff --git a/src/test/ui/huge-array.rs b/src/test/ui/huge-array.rs index 846380586a..3070801f86 100644 --- a/src/test/ui/huge-array.rs +++ b/src/test/ui/huge-array.rs @@ -6,7 +6,7 @@ fn generic(t: T) { let s: [T; 1518600000] = [t; 1518600000]; - //~^ ERROR the type `[[u8; 1518599999]; 1518600000]` is too big for the current architecture + //~^ ERROR values of the type `[[u8; 1518599999]; 1518600000]` are too big } fn main() { diff --git a/src/test/ui/huge-array.stderr b/src/test/ui/huge-array.stderr index 23d9e87ae0..817458b73e 100644 --- a/src/test/ui/huge-array.stderr +++ b/src/test/ui/huge-array.stderr @@ -1,4 +1,4 @@ -error: the type `[[u8; 1518599999]; 1518600000]` is too big for the current architecture +error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the current architecture --> $DIR/huge-array.rs:8:9 | LL | let s: [T; 1518600000] = [t; 1518600000]; diff --git a/src/test/ui/huge-enum.rs b/src/test/ui/huge-enum.rs index 8a713c3a26..39ea6e11b1 100644 --- a/src/test/ui/huge-enum.rs +++ b/src/test/ui/huge-enum.rs @@ -14,5 +14,5 @@ type BIG = Option<[u32; (1<<45)-1]>; fn main() { let big: BIG = None; - //~^ ERROR is too big for the current architecture + //~^ ERROR are too big for the current architecture } diff --git a/src/test/ui/huge-enum.stderr b/src/test/ui/huge-enum.stderr index a069c37b80..a1456e1a8a 100644 --- a/src/test/ui/huge-enum.stderr +++ b/src/test/ui/huge-enum.stderr @@ -1,4 +1,4 @@ -error: the type `Option` is too big for the current architecture +error: values of the type `Option` are too big for the current architecture --> $DIR/huge-enum.rs:16:9 | LL | let big: BIG = None; diff --git a/src/test/ui/huge-struct.rs b/src/test/ui/huge-struct.rs index 71169a1104..02f38d860b 100644 --- a/src/test/ui/huge-struct.rs +++ b/src/test/ui/huge-struct.rs @@ -48,6 +48,6 @@ struct S1M { val: S1k> } fn main() { let fat: Option>>> = None; - //~^ ERROR is too big for the current architecture + //~^ ERROR are too big for the current architecture } diff --git a/src/test/ui/huge-struct.stderr b/src/test/ui/huge-struct.stderr index 72e32a8593..f0ee88e595 100644 --- a/src/test/ui/huge-struct.stderr +++ b/src/test/ui/huge-struct.stderr @@ -1,4 +1,4 @@ -error: the type `SXX>>` is too big for the current architecture +error: values of the type `SXX>>` are too big for the current architecture --> $DIR/huge-struct.rs:50:9 | LL | let fat: Option>>> = None; diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.stderr b/src/test/ui/hygiene/hygienic-labels-in-let.stderr index 3ff45a8a56..9e7811b807 100644 --- a/src/test/ui/hygiene/hygienic-labels-in-let.stderr +++ b/src/test/ui/hygiene/hygienic-labels-in-let.stderr @@ -2,7 +2,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -19,7 +19,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:64:9 @@ -28,13 +28,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -51,7 +51,7 @@ LL | 'x: loop { $e } | ^^ | | | first declared here - | lifetime 'x already in scope + | label `'x` already in scope ... LL | loop_x!(break 'x); | ------------------ in this macro invocation @@ -62,7 +62,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -79,7 +79,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -88,7 +88,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -97,7 +97,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -106,13 +106,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -129,7 +129,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_true!(break 'x); | ---------------------- in this macro invocation @@ -140,7 +140,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -157,7 +157,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_true!(break 'x); | ---------------------- in this macro invocation @@ -168,7 +168,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -185,7 +185,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -194,7 +194,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -203,7 +203,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -212,7 +212,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -221,7 +221,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -230,13 +230,13 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -253,7 +253,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -264,7 +264,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -281,7 +281,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -292,7 +292,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -309,7 +309,7 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -320,7 +320,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here diff --git a/src/test/ui/hygiene/hygienic-labels.stderr b/src/test/ui/hygiene/hygienic-labels.stderr index 25098c25c8..275478d292 100644 --- a/src/test/ui/hygiene/hygienic-labels.stderr +++ b/src/test/ui/hygiene/hygienic-labels.stderr @@ -2,7 +2,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -19,7 +19,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: loop { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:54:5 @@ -28,13 +28,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: loop { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -51,7 +51,7 @@ LL | 'x: loop { $e } | ^^ | | | first declared here - | lifetime 'x already in scope + | label `'x` already in scope ... LL | loop_x!(break 'x); | ------------------ in this macro invocation @@ -62,7 +62,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -79,7 +79,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -88,7 +88,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -97,7 +97,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -106,13 +106,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -129,7 +129,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_x!(break 'x); | ------------------- in this macro invocation @@ -140,7 +140,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -157,7 +157,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_x!(break 'x); | ------------------- in this macro invocation @@ -168,7 +168,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { | -- first declared here @@ -185,7 +185,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -194,7 +194,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -203,7 +203,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -212,7 +212,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -221,7 +221,7 @@ LL | 'x: while 1 + 1 == 2 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -230,13 +230,13 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -253,7 +253,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -264,7 +264,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -281,7 +281,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -292,7 +292,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { | -- first declared here @@ -306,7 +306,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here @@ -320,7 +320,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here diff --git a/src/test/ui/hygiene/no_implicit_prelude.rs b/src/test/ui/hygiene/no_implicit_prelude.rs index 204e7b2487..e23826e9d4 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.rs +++ b/src/test/ui/hygiene/no_implicit_prelude.rs @@ -1,7 +1,7 @@ #![feature(decl_macro)] mod foo { - pub macro m() { Vec::new(); ().clone() } + pub macro m() { Vec::::new(); ().clone() } fn f() { ::bar::m!(); } } @@ -13,7 +13,7 @@ mod bar { } fn f() { ::foo::m!(); - assert_eq!(0, 0); //~ ERROR cannot find macro `panic` in this scope + assert!(true); } } diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 843dee2478..835ecce94b 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -1,14 +1,3 @@ -error: cannot find macro `panic` in this scope - --> $DIR/no_implicit_prelude.rs:16:9 - | -LL | assert_eq!(0, 0); - | ^^^^^^^^^^^^^^^^^ - | - = note: consider importing one of these items: - core::panic - std::panic - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0433]: failed to resolve: use of undeclared type `Vec` --> $DIR/no_implicit_prelude.rs:11:9 | @@ -38,7 +27,7 @@ LL | ().clone() `use std::clone::Clone;` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0433, E0599. For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/hygiene/panic-location.run.stderr b/src/test/ui/hygiene/panic-location.run.stderr index a437a7b501..216b31586d 100644 --- a/src/test/ui/hygiene/panic-location.run.stderr +++ b/src/test/ui/hygiene/panic-location.run.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'capacity overflow', $SRC_DIR/alloc/src/collections/vec_deque.rs:LL:COL +thread 'main' panicked at 'capacity overflow', $SRC_DIR/alloc/src/collections/vec_deque/mod.rs:LL:COL note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/src/test/ui/impl-trait/issues/issue-78721.rs b/src/test/ui/impl-trait/issues/issue-78721.rs new file mode 100644 index 0000000000..f7dbef9e3f --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-78721.rs @@ -0,0 +1,15 @@ +// edition:2018 + +#![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete + +struct Bug { + V1: [(); { + let f: impl core::future::Future = async { 1 }; + //~^ ERROR `async` blocks are not allowed in constants + //~| ERROR destructors cannot be evaluated at compile-time + 1 + }], +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issues/issue-78721.stderr b/src/test/ui/impl-trait/issues/issue-78721.stderr new file mode 100644 index 0000000000..353e882b1a --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-78721.stderr @@ -0,0 +1,27 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-78721.rs:3:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #63065 for more information + +error: `async` blocks are not allowed in constants + --> $DIR/issue-78721.rs:8:57 + | +LL | let f: impl core::future::Future = async { 1 }; + | ^^^^^^^^^^^ + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/issue-78721.rs:8:13 + | +LL | let f: impl core::future::Future = async { 1 }; + | ^ constants cannot evaluate destructors +... +LL | }], + | - value is dropped here + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs new file mode 100644 index 0000000000..58734d3a44 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-78722.rs @@ -0,0 +1,21 @@ +// edition:2018 + +#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete + +type F = impl core::future::Future; + +struct Bug { + V1: [(); { + fn concrete_use() -> F { + async {} + } + let f: F = async { 1 }; + //~^ ERROR `async` blocks are not allowed in constants + //~| ERROR destructors cannot be evaluated at compile-time + 1 + }], +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr new file mode 100644 index 0000000000..0e1e92b912 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -0,0 +1,27 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-78722.rs:4:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #63065 for more information + +error: `async` blocks are not allowed in constants + --> $DIR/issue-78722.rs:14:20 + | +LL | let f: F = async { 1 }; + | ^^^^^^^^^^^ + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/issue-78722.rs:14:13 + | +LL | let f: F = async { 1 }; + | ^ constants cannot evaluate destructors +... +LL | }], + | - value is dropped here + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/import.rs b/src/test/ui/import.rs deleted file mode 100644 index 3170dd2fae..0000000000 --- a/src/test/ui/import.rs +++ /dev/null @@ -1,17 +0,0 @@ -use zed::bar; -use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] - //~| no `baz` in `zed` - //~| HELP a similar name exists in the module - //~| SUGGESTION bar - - -mod zed { - pub fn bar() { println!("bar"); } - use foo; //~ ERROR unresolved import `foo` [E0432] - //~^ no `foo` in the root -} - -fn main() { - zed::foo(); //~ ERROR `foo` is private - bar(); -} diff --git a/src/test/ui/import2.rs b/src/test/ui/import2.rs deleted file mode 100644 index 036d6bc07e..0000000000 --- a/src/test/ui/import2.rs +++ /dev/null @@ -1,10 +0,0 @@ -use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432] - //~^ could not find `zed` in `baz` - -mod baz {} -mod zed { - pub fn bar() { println!("bar3"); } -} -fn main() { - bar(); -} diff --git a/src/test/ui/import3.rs b/src/test/ui/import3.rs deleted file mode 100644 index 2c6ac9a00e..0000000000 --- a/src/test/ui/import3.rs +++ /dev/null @@ -1,4 +0,0 @@ -// error-pattern: unresolved -use main::bar; - -fn main() { println!("foo"); } diff --git a/src/test/ui/import4.rs b/src/test/ui/import4.rs deleted file mode 100644 index ba3b7fbf53..0000000000 --- a/src/test/ui/import4.rs +++ /dev/null @@ -1,7 +0,0 @@ -// error-pattern: import - - -mod a { pub use b::foo; } -mod b { pub use a::foo; } - -fn main() { println!("loop"); } diff --git a/src/test/ui/issues/auxiliary/issue-36881-aux.rs b/src/test/ui/imports/auxiliary/issue-36881-aux.rs similarity index 100% rename from src/test/ui/issues/auxiliary/issue-36881-aux.rs rename to src/test/ui/imports/auxiliary/issue-36881-aux.rs diff --git a/src/test/ui/issues/auxiliary/issue-52891.rs b/src/test/ui/imports/auxiliary/issue-52891.rs similarity index 100% rename from src/test/ui/issues/auxiliary/issue-52891.rs rename to src/test/ui/imports/auxiliary/issue-52891.rs diff --git a/src/test/ui/issues/auxiliary/issue-59764.rs b/src/test/ui/imports/auxiliary/issue-59764.rs similarity index 100% rename from src/test/ui/issues/auxiliary/issue-59764.rs rename to src/test/ui/imports/auxiliary/issue-59764.rs diff --git a/src/test/ui/double-import.rs b/src/test/ui/imports/double-import.rs similarity index 100% rename from src/test/ui/double-import.rs rename to src/test/ui/imports/double-import.rs diff --git a/src/test/ui/double-import.stderr b/src/test/ui/imports/double-import.stderr similarity index 100% rename from src/test/ui/double-import.stderr rename to src/test/ui/imports/double-import.stderr diff --git a/src/test/ui/export-glob-imports-target.rs b/src/test/ui/imports/export-glob-imports-target.rs similarity index 100% rename from src/test/ui/export-glob-imports-target.rs rename to src/test/ui/imports/export-glob-imports-target.rs diff --git a/src/test/ui/glob-resolve1.rs b/src/test/ui/imports/glob-resolve1.rs similarity index 100% rename from src/test/ui/glob-resolve1.rs rename to src/test/ui/imports/glob-resolve1.rs diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/imports/glob-resolve1.stderr similarity index 100% rename from src/test/ui/glob-resolve1.stderr rename to src/test/ui/imports/glob-resolve1.stderr diff --git a/src/test/ui/imports/import-rpass.rs b/src/test/ui/imports/import-rpass.rs new file mode 100644 index 0000000000..de8bf62611 --- /dev/null +++ b/src/test/ui/imports/import-rpass.rs @@ -0,0 +1,12 @@ +// run-pass +mod foo { + pub fn x(y: isize) { println!("{}", y); } +} + +mod bar { + use foo::x; + use foo::x as z; + pub fn thing() { x(10); z(10); } +} + +pub fn main() { bar::thing(); } diff --git a/src/test/ui/imports/import.rs b/src/test/ui/imports/import.rs index de8bf62611..3170dd2fae 100644 --- a/src/test/ui/imports/import.rs +++ b/src/test/ui/imports/import.rs @@ -1,12 +1,17 @@ -// run-pass -mod foo { - pub fn x(y: isize) { println!("{}", y); } -} +use zed::bar; +use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] + //~| no `baz` in `zed` + //~| HELP a similar name exists in the module + //~| SUGGESTION bar + -mod bar { - use foo::x; - use foo::x as z; - pub fn thing() { x(10); z(10); } +mod zed { + pub fn bar() { println!("bar"); } + use foo; //~ ERROR unresolved import `foo` [E0432] + //~^ no `foo` in the root } -pub fn main() { bar::thing(); } +fn main() { + zed::foo(); //~ ERROR `foo` is private + bar(); +} diff --git a/src/test/ui/import.stderr b/src/test/ui/imports/import.stderr similarity index 100% rename from src/test/ui/import.stderr rename to src/test/ui/imports/import.stderr diff --git a/src/test/ui/imports/import2-rpass.rs b/src/test/ui/imports/import2-rpass.rs new file mode 100644 index 0000000000..7b70f799eb --- /dev/null +++ b/src/test/ui/imports/import2-rpass.rs @@ -0,0 +1,9 @@ +// run-pass + +use zed::bar; + +mod zed { + pub fn bar() { println!("bar"); } +} + +pub fn main() { bar(); } diff --git a/src/test/ui/imports/import2.rs b/src/test/ui/imports/import2.rs index 7b70f799eb..036d6bc07e 100644 --- a/src/test/ui/imports/import2.rs +++ b/src/test/ui/imports/import2.rs @@ -1,9 +1,10 @@ -// run-pass - -use zed::bar; +use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432] + //~^ could not find `zed` in `baz` +mod baz {} mod zed { - pub fn bar() { println!("bar"); } + pub fn bar() { println!("bar3"); } +} +fn main() { + bar(); } - -pub fn main() { bar(); } diff --git a/src/test/ui/import2.stderr b/src/test/ui/imports/import2.stderr similarity index 100% rename from src/test/ui/import2.stderr rename to src/test/ui/imports/import2.stderr diff --git a/src/test/ui/imports/import3-rpass.rs b/src/test/ui/imports/import3-rpass.rs new file mode 100644 index 0000000000..17797aed35 --- /dev/null +++ b/src/test/ui/imports/import3-rpass.rs @@ -0,0 +1,13 @@ +// run-pass +#![allow(unused_imports)] + +use baz::zed; +use baz::zed::bar; + +mod baz { + pub mod zed { + pub fn bar() { println!("bar2"); } + } +} + +pub fn main() { bar(); } diff --git a/src/test/ui/imports/import3.rs b/src/test/ui/imports/import3.rs index 17797aed35..2c6ac9a00e 100644 --- a/src/test/ui/imports/import3.rs +++ b/src/test/ui/imports/import3.rs @@ -1,13 +1,4 @@ -// run-pass -#![allow(unused_imports)] +// error-pattern: unresolved +use main::bar; -use baz::zed; -use baz::zed::bar; - -mod baz { - pub mod zed { - pub fn bar() { println!("bar2"); } - } -} - -pub fn main() { bar(); } +fn main() { println!("foo"); } diff --git a/src/test/ui/import3.stderr b/src/test/ui/imports/import3.stderr similarity index 100% rename from src/test/ui/import3.stderr rename to src/test/ui/imports/import3.stderr diff --git a/src/test/ui/imports/import4-rpass.rs b/src/test/ui/imports/import4-rpass.rs new file mode 100644 index 0000000000..4fda538611 --- /dev/null +++ b/src/test/ui/imports/import4-rpass.rs @@ -0,0 +1,9 @@ +// run-pass + +use zed::bar; + +mod zed { + pub fn bar() { println!("bar"); } +} + +pub fn main() { let _zed = 42; bar(); } diff --git a/src/test/ui/imports/import4.rs b/src/test/ui/imports/import4.rs index 4fda538611..ba3b7fbf53 100644 --- a/src/test/ui/imports/import4.rs +++ b/src/test/ui/imports/import4.rs @@ -1,9 +1,7 @@ -// run-pass +// error-pattern: import -use zed::bar; -mod zed { - pub fn bar() { println!("bar"); } -} +mod a { pub use b::foo; } +mod b { pub use a::foo; } -pub fn main() { let _zed = 42; bar(); } +fn main() { println!("loop"); } diff --git a/src/test/ui/import4.stderr b/src/test/ui/imports/import4.stderr similarity index 100% rename from src/test/ui/import4.stderr rename to src/test/ui/imports/import4.stderr diff --git a/src/test/ui/issues/issue-13404.rs b/src/test/ui/imports/issue-13404.rs similarity index 100% rename from src/test/ui/issues/issue-13404.rs rename to src/test/ui/imports/issue-13404.rs diff --git a/src/test/ui/issues/issue-13404.stderr b/src/test/ui/imports/issue-13404.stderr similarity index 100% rename from src/test/ui/issues/issue-13404.stderr rename to src/test/ui/imports/issue-13404.stderr diff --git a/src/test/ui/issues/issue-1697.rs b/src/test/ui/imports/issue-1697.rs similarity index 100% rename from src/test/ui/issues/issue-1697.rs rename to src/test/ui/imports/issue-1697.rs diff --git a/src/test/ui/issues/issue-1697.stderr b/src/test/ui/imports/issue-1697.stderr similarity index 100% rename from src/test/ui/issues/issue-1697.stderr rename to src/test/ui/imports/issue-1697.stderr diff --git a/src/test/ui/issues/issue-18083.rs b/src/test/ui/imports/issue-18083.rs similarity index 100% rename from src/test/ui/issues/issue-18083.rs rename to src/test/ui/imports/issue-18083.rs diff --git a/src/test/ui/issues/issue-19498.rs b/src/test/ui/imports/issue-19498.rs similarity index 100% rename from src/test/ui/issues/issue-19498.rs rename to src/test/ui/imports/issue-19498.rs diff --git a/src/test/ui/issues/issue-19498.stderr b/src/test/ui/imports/issue-19498.stderr similarity index 100% rename from src/test/ui/issues/issue-19498.stderr rename to src/test/ui/imports/issue-19498.stderr diff --git a/src/test/ui/issues/issue-24081.rs b/src/test/ui/imports/issue-24081.rs similarity index 100% rename from src/test/ui/issues/issue-24081.rs rename to src/test/ui/imports/issue-24081.rs diff --git a/src/test/ui/issues/issue-24081.stderr b/src/test/ui/imports/issue-24081.stderr similarity index 100% rename from src/test/ui/issues/issue-24081.stderr rename to src/test/ui/imports/issue-24081.stderr diff --git a/src/test/ui/issues/issue-25396.rs b/src/test/ui/imports/issue-25396.rs similarity index 100% rename from src/test/ui/issues/issue-25396.rs rename to src/test/ui/imports/issue-25396.rs diff --git a/src/test/ui/issues/issue-25396.stderr b/src/test/ui/imports/issue-25396.stderr similarity index 100% rename from src/test/ui/issues/issue-25396.stderr rename to src/test/ui/imports/issue-25396.stderr diff --git a/src/test/ui/issues/issue-26886.rs b/src/test/ui/imports/issue-26886.rs similarity index 100% rename from src/test/ui/issues/issue-26886.rs rename to src/test/ui/imports/issue-26886.rs diff --git a/src/test/ui/issues/issue-26886.stderr b/src/test/ui/imports/issue-26886.stderr similarity index 100% rename from src/test/ui/issues/issue-26886.stderr rename to src/test/ui/imports/issue-26886.stderr diff --git a/src/test/ui/issues/issue-28134.rs b/src/test/ui/imports/issue-28134.rs similarity index 80% rename from src/test/ui/issues/issue-28134.rs rename to src/test/ui/imports/issue-28134.rs index fa692db4bf..1ed2d330b5 100644 --- a/src/test/ui/issues/issue-28134.rs +++ b/src/test/ui/imports/issue-28134.rs @@ -1,3 +1,4 @@ // compile-flags: --test +#![allow(soft_unstable)] #![test] //~ ERROR cannot determine resolution for the attribute macro `test` diff --git a/src/test/ui/issues/issue-28134.stderr b/src/test/ui/imports/issue-28134.stderr similarity index 87% rename from src/test/ui/issues/issue-28134.stderr rename to src/test/ui/imports/issue-28134.stderr index 5f8d27dd04..8ed4d015f3 100644 --- a/src/test/ui/issues/issue-28134.stderr +++ b/src/test/ui/imports/issue-28134.stderr @@ -1,5 +1,5 @@ error: cannot determine resolution for the attribute macro `test` - --> $DIR/issue-28134.rs:3:4 + --> $DIR/issue-28134.rs:4:4 | LL | #![test] | ^^^^ diff --git a/src/test/ui/issues/issue-28388-1.rs b/src/test/ui/imports/issue-28388-1.rs similarity index 100% rename from src/test/ui/issues/issue-28388-1.rs rename to src/test/ui/imports/issue-28388-1.rs diff --git a/src/test/ui/issues/issue-28388-1.stderr b/src/test/ui/imports/issue-28388-1.stderr similarity index 100% rename from src/test/ui/issues/issue-28388-1.stderr rename to src/test/ui/imports/issue-28388-1.stderr diff --git a/src/test/ui/issues/issue-28388-2.rs b/src/test/ui/imports/issue-28388-2.rs similarity index 100% rename from src/test/ui/issues/issue-28388-2.rs rename to src/test/ui/imports/issue-28388-2.rs diff --git a/src/test/ui/issues/issue-28388-2.stderr b/src/test/ui/imports/issue-28388-2.stderr similarity index 100% rename from src/test/ui/issues/issue-28388-2.stderr rename to src/test/ui/imports/issue-28388-2.stderr diff --git a/src/test/ui/issues/issue-2937.rs b/src/test/ui/imports/issue-2937.rs similarity index 100% rename from src/test/ui/issues/issue-2937.rs rename to src/test/ui/imports/issue-2937.rs diff --git a/src/test/ui/issues/issue-2937.stderr b/src/test/ui/imports/issue-2937.stderr similarity index 100% rename from src/test/ui/issues/issue-2937.stderr rename to src/test/ui/imports/issue-2937.stderr diff --git a/src/test/ui/issues/issue-30560.rs b/src/test/ui/imports/issue-30560.rs similarity index 100% rename from src/test/ui/issues/issue-30560.rs rename to src/test/ui/imports/issue-30560.rs diff --git a/src/test/ui/issues/issue-30560.stderr b/src/test/ui/imports/issue-30560.stderr similarity index 100% rename from src/test/ui/issues/issue-30560.stderr rename to src/test/ui/imports/issue-30560.stderr diff --git a/src/test/ui/issues/issue-31212.rs b/src/test/ui/imports/issue-31212.rs similarity index 100% rename from src/test/ui/issues/issue-31212.rs rename to src/test/ui/imports/issue-31212.rs diff --git a/src/test/ui/issues/issue-31212.stderr b/src/test/ui/imports/issue-31212.stderr similarity index 100% rename from src/test/ui/issues/issue-31212.stderr rename to src/test/ui/imports/issue-31212.stderr diff --git a/src/test/ui/issues/issue-32354-suggest-import-rename.fixed b/src/test/ui/imports/issue-32354-suggest-import-rename.fixed similarity index 100% rename from src/test/ui/issues/issue-32354-suggest-import-rename.fixed rename to src/test/ui/imports/issue-32354-suggest-import-rename.fixed diff --git a/src/test/ui/issues/issue-32354-suggest-import-rename.rs b/src/test/ui/imports/issue-32354-suggest-import-rename.rs similarity index 100% rename from src/test/ui/issues/issue-32354-suggest-import-rename.rs rename to src/test/ui/imports/issue-32354-suggest-import-rename.rs diff --git a/src/test/ui/issues/issue-32354-suggest-import-rename.stderr b/src/test/ui/imports/issue-32354-suggest-import-rename.stderr similarity index 100% rename from src/test/ui/issues/issue-32354-suggest-import-rename.stderr rename to src/test/ui/imports/issue-32354-suggest-import-rename.stderr diff --git a/src/test/ui/issues/issue-32833.rs b/src/test/ui/imports/issue-32833.rs similarity index 100% rename from src/test/ui/issues/issue-32833.rs rename to src/test/ui/imports/issue-32833.rs diff --git a/src/test/ui/issues/issue-32833.stderr b/src/test/ui/imports/issue-32833.stderr similarity index 100% rename from src/test/ui/issues/issue-32833.stderr rename to src/test/ui/imports/issue-32833.stderr diff --git a/src/test/ui/issues/issue-33464.rs b/src/test/ui/imports/issue-33464.rs similarity index 100% rename from src/test/ui/issues/issue-33464.rs rename to src/test/ui/imports/issue-33464.rs diff --git a/src/test/ui/issues/issue-33464.stderr b/src/test/ui/imports/issue-33464.stderr similarity index 100% rename from src/test/ui/issues/issue-33464.stderr rename to src/test/ui/imports/issue-33464.stderr diff --git a/src/test/ui/issues/issue-36881.rs b/src/test/ui/imports/issue-36881.rs similarity index 100% rename from src/test/ui/issues/issue-36881.rs rename to src/test/ui/imports/issue-36881.rs diff --git a/src/test/ui/issues/issue-36881.stderr b/src/test/ui/imports/issue-36881.stderr similarity index 100% rename from src/test/ui/issues/issue-36881.stderr rename to src/test/ui/imports/issue-36881.stderr diff --git a/src/test/ui/issues/issue-37887.rs b/src/test/ui/imports/issue-37887.rs similarity index 100% rename from src/test/ui/issues/issue-37887.rs rename to src/test/ui/imports/issue-37887.rs diff --git a/src/test/ui/issues/issue-37887.stderr b/src/test/ui/imports/issue-37887.stderr similarity index 100% rename from src/test/ui/issues/issue-37887.stderr rename to src/test/ui/imports/issue-37887.stderr diff --git a/src/test/ui/issues/issue-38293.rs b/src/test/ui/imports/issue-38293.rs similarity index 100% rename from src/test/ui/issues/issue-38293.rs rename to src/test/ui/imports/issue-38293.rs diff --git a/src/test/ui/issues/issue-38293.stderr b/src/test/ui/imports/issue-38293.stderr similarity index 100% rename from src/test/ui/issues/issue-38293.stderr rename to src/test/ui/imports/issue-38293.stderr diff --git a/src/test/ui/issues/issue-4366-2.rs b/src/test/ui/imports/issue-4366-2.rs similarity index 100% rename from src/test/ui/issues/issue-4366-2.rs rename to src/test/ui/imports/issue-4366-2.rs diff --git a/src/test/ui/issues/issue-4366-2.stderr b/src/test/ui/imports/issue-4366-2.stderr similarity index 100% rename from src/test/ui/issues/issue-4366-2.stderr rename to src/test/ui/imports/issue-4366-2.stderr diff --git a/src/test/ui/issues/issue-4366.rs b/src/test/ui/imports/issue-4366.rs similarity index 100% rename from src/test/ui/issues/issue-4366.rs rename to src/test/ui/imports/issue-4366.rs diff --git a/src/test/ui/issues/issue-4366.stderr b/src/test/ui/imports/issue-4366.stderr similarity index 100% rename from src/test/ui/issues/issue-4366.stderr rename to src/test/ui/imports/issue-4366.stderr diff --git a/src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed b/src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed similarity index 100% rename from src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed rename to src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed diff --git a/src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs b/src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs similarity index 100% rename from src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs rename to src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs diff --git a/src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr b/src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr similarity index 100% rename from src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr rename to src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr diff --git a/src/test/ui/issues/issue-45829/auxiliary/issue-45829-a.rs b/src/test/ui/imports/issue-45829/auxiliary/issue-45829-a.rs similarity index 100% rename from src/test/ui/issues/issue-45829/auxiliary/issue-45829-a.rs rename to src/test/ui/imports/issue-45829/auxiliary/issue-45829-a.rs diff --git a/src/test/ui/issues/issue-45829/auxiliary/issue-45829-b.rs b/src/test/ui/imports/issue-45829/auxiliary/issue-45829-b.rs similarity index 100% rename from src/test/ui/issues/issue-45829/auxiliary/issue-45829-b.rs rename to src/test/ui/imports/issue-45829/auxiliary/issue-45829-b.rs diff --git a/src/test/ui/issues/issue-45829/import-self.rs b/src/test/ui/imports/issue-45829/import-self.rs similarity index 100% rename from src/test/ui/issues/issue-45829/import-self.rs rename to src/test/ui/imports/issue-45829/import-self.rs diff --git a/src/test/ui/issues/issue-45829/import-self.stderr b/src/test/ui/imports/issue-45829/import-self.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/import-self.stderr rename to src/test/ui/imports/issue-45829/import-self.stderr diff --git a/src/test/ui/issues/issue-45829/import-twice.rs b/src/test/ui/imports/issue-45829/import-twice.rs similarity index 100% rename from src/test/ui/issues/issue-45829/import-twice.rs rename to src/test/ui/imports/issue-45829/import-twice.rs diff --git a/src/test/ui/issues/issue-45829/import-twice.stderr b/src/test/ui/imports/issue-45829/import-twice.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/import-twice.stderr rename to src/test/ui/imports/issue-45829/import-twice.stderr diff --git a/src/test/ui/issues/issue-45829/issue-45829.rs b/src/test/ui/imports/issue-45829/issue-45829.rs similarity index 100% rename from src/test/ui/issues/issue-45829/issue-45829.rs rename to src/test/ui/imports/issue-45829/issue-45829.rs diff --git a/src/test/ui/issues/issue-45829/issue-45829.stderr b/src/test/ui/imports/issue-45829/issue-45829.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/issue-45829.stderr rename to src/test/ui/imports/issue-45829/issue-45829.stderr diff --git a/src/test/ui/issues/issue-45829/rename-extern-vs-use.rs b/src/test/ui/imports/issue-45829/rename-extern-vs-use.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-vs-use.rs rename to src/test/ui/imports/issue-45829/rename-extern-vs-use.rs diff --git a/src/test/ui/issues/issue-45829/rename-extern-vs-use.stderr b/src/test/ui/imports/issue-45829/rename-extern-vs-use.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-vs-use.stderr rename to src/test/ui/imports/issue-45829/rename-extern-vs-use.stderr diff --git a/src/test/ui/issues/issue-45829/rename-extern-with-tab.rs b/src/test/ui/imports/issue-45829/rename-extern-with-tab.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-with-tab.rs rename to src/test/ui/imports/issue-45829/rename-extern-with-tab.rs diff --git a/src/test/ui/issues/issue-45829/rename-extern-with-tab.stderr b/src/test/ui/imports/issue-45829/rename-extern-with-tab.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-with-tab.stderr rename to src/test/ui/imports/issue-45829/rename-extern-with-tab.stderr diff --git a/src/test/ui/issues/issue-45829/rename-extern.rs b/src/test/ui/imports/issue-45829/rename-extern.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern.rs rename to src/test/ui/imports/issue-45829/rename-extern.rs diff --git a/src/test/ui/issues/issue-45829/rename-extern.stderr b/src/test/ui/imports/issue-45829/rename-extern.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern.stderr rename to src/test/ui/imports/issue-45829/rename-extern.stderr diff --git a/src/test/ui/issues/issue-45829/rename-use-vs-extern.rs b/src/test/ui/imports/issue-45829/rename-use-vs-extern.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-vs-extern.rs rename to src/test/ui/imports/issue-45829/rename-use-vs-extern.rs diff --git a/src/test/ui/issues/issue-45829/rename-use-vs-extern.stderr b/src/test/ui/imports/issue-45829/rename-use-vs-extern.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-vs-extern.stderr rename to src/test/ui/imports/issue-45829/rename-use-vs-extern.stderr diff --git a/src/test/ui/issues/issue-45829/rename-use-with-tabs.rs b/src/test/ui/imports/issue-45829/rename-use-with-tabs.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-with-tabs.rs rename to src/test/ui/imports/issue-45829/rename-use-with-tabs.rs diff --git a/src/test/ui/issues/issue-45829/rename-use-with-tabs.stderr b/src/test/ui/imports/issue-45829/rename-use-with-tabs.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-with-tabs.stderr rename to src/test/ui/imports/issue-45829/rename-use-with-tabs.stderr diff --git a/src/test/ui/issues/issue-45829/rename-with-path.rs b/src/test/ui/imports/issue-45829/rename-with-path.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-with-path.rs rename to src/test/ui/imports/issue-45829/rename-with-path.rs diff --git a/src/test/ui/issues/issue-45829/rename-with-path.stderr b/src/test/ui/imports/issue-45829/rename-with-path.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-with-path.stderr rename to src/test/ui/imports/issue-45829/rename-with-path.stderr diff --git a/src/test/ui/issues/issue-45829/rename.rs b/src/test/ui/imports/issue-45829/rename.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename.rs rename to src/test/ui/imports/issue-45829/rename.rs diff --git a/src/test/ui/issues/issue-45829/rename.stderr b/src/test/ui/imports/issue-45829/rename.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename.stderr rename to src/test/ui/imports/issue-45829/rename.stderr diff --git a/src/test/ui/issues/issue-47623.rs b/src/test/ui/imports/issue-47623.rs similarity index 100% rename from src/test/ui/issues/issue-47623.rs rename to src/test/ui/imports/issue-47623.rs diff --git a/src/test/ui/issues/issue-47623.stderr b/src/test/ui/imports/issue-47623.stderr similarity index 100% rename from src/test/ui/issues/issue-47623.stderr rename to src/test/ui/imports/issue-47623.stderr diff --git a/src/test/ui/issues/issue-4865-1.rs b/src/test/ui/imports/issue-4865-1.rs similarity index 100% rename from src/test/ui/issues/issue-4865-1.rs rename to src/test/ui/imports/issue-4865-1.rs diff --git a/src/test/ui/issues/issue-4865-2.rs b/src/test/ui/imports/issue-4865-2.rs similarity index 100% rename from src/test/ui/issues/issue-4865-2.rs rename to src/test/ui/imports/issue-4865-2.rs diff --git a/src/test/ui/issues/issue-4865-3.rs b/src/test/ui/imports/issue-4865-3.rs similarity index 100% rename from src/test/ui/issues/issue-4865-3.rs rename to src/test/ui/imports/issue-4865-3.rs diff --git a/src/test/ui/issues/issue-52891.fixed b/src/test/ui/imports/issue-52891.fixed similarity index 100% rename from src/test/ui/issues/issue-52891.fixed rename to src/test/ui/imports/issue-52891.fixed diff --git a/src/test/ui/issues/issue-52891.rs b/src/test/ui/imports/issue-52891.rs similarity index 100% rename from src/test/ui/issues/issue-52891.rs rename to src/test/ui/imports/issue-52891.rs diff --git a/src/test/ui/issues/issue-52891.stderr b/src/test/ui/imports/issue-52891.stderr similarity index 100% rename from src/test/ui/issues/issue-52891.stderr rename to src/test/ui/imports/issue-52891.stderr diff --git a/src/test/ui/issues/issue-53565.rs b/src/test/ui/imports/issue-53565.rs similarity index 100% rename from src/test/ui/issues/issue-53565.rs rename to src/test/ui/imports/issue-53565.rs diff --git a/src/test/ui/issues/issue-53565.stderr b/src/test/ui/imports/issue-53565.stderr similarity index 100% rename from src/test/ui/issues/issue-53565.stderr rename to src/test/ui/imports/issue-53565.stderr diff --git a/src/test/ui/issues/issue-59764.rs b/src/test/ui/imports/issue-59764.rs similarity index 100% rename from src/test/ui/issues/issue-59764.rs rename to src/test/ui/imports/issue-59764.rs diff --git a/src/test/ui/issues/issue-59764.stderr b/src/test/ui/imports/issue-59764.stderr similarity index 100% rename from src/test/ui/issues/issue-59764.stderr rename to src/test/ui/imports/issue-59764.stderr diff --git a/src/test/ui/issues/issue-8208.rs b/src/test/ui/imports/issue-8208.rs similarity index 100% rename from src/test/ui/issues/issue-8208.rs rename to src/test/ui/imports/issue-8208.rs diff --git a/src/test/ui/issues/issue-8208.stderr b/src/test/ui/imports/issue-8208.stderr similarity index 100% rename from src/test/ui/issues/issue-8208.stderr rename to src/test/ui/imports/issue-8208.stderr diff --git a/src/test/ui/issues/issue-8640.rs b/src/test/ui/imports/issue-8640.rs similarity index 100% rename from src/test/ui/issues/issue-8640.rs rename to src/test/ui/imports/issue-8640.rs diff --git a/src/test/ui/issues/issue-8640.stderr b/src/test/ui/imports/issue-8640.stderr similarity index 100% rename from src/test/ui/issues/issue-8640.stderr rename to src/test/ui/imports/issue-8640.stderr diff --git a/src/test/ui/resolve_self_super_hint.rs b/src/test/ui/imports/resolve_self_super_hint.rs similarity index 100% rename from src/test/ui/resolve_self_super_hint.rs rename to src/test/ui/imports/resolve_self_super_hint.rs diff --git a/src/test/ui/resolve_self_super_hint.stderr b/src/test/ui/imports/resolve_self_super_hint.stderr similarity index 100% rename from src/test/ui/resolve_self_super_hint.stderr rename to src/test/ui/imports/resolve_self_super_hint.stderr diff --git a/src/test/ui/in-band-lifetimes/shadow.stderr b/src/test/ui/in-band-lifetimes/shadow.stderr index a0a15d3aa8..c7a6f3ac3a 100644 --- a/src/test/ui/in-band-lifetimes/shadow.stderr +++ b/src/test/ui/in-band-lifetimes/shadow.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scop LL | impl Foo<&'s u8> { | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} - | ^^ lifetime 's already in scope + | ^^ lifetime `'s` already in scope error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope --> $DIR/shadow.rs:8:19 @@ -13,7 +13,7 @@ LL | impl Foo<&'s u8> { | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} LL | fn baz(x: for<'s> fn(&'s u32)) {} - | ^^ lifetime 's already in scope + | ^^ lifetime `'s` already in scope error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 3458040792..4209153116 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -1,8 +1,7 @@ //https://github.com/rust-lang/rust/issues/31364 const fn a() -> usize { - //~^ ERROR cycle detected when const-evaluating + checking `a` [E0391] - b() + b() //~ ERROR evaluation of constant value failed [E0080] } const fn b() -> usize { a() diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index 7ccc7cc987..620c9e110f 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,21 +1,145 @@ -error[E0391]: cycle detected when const-evaluating + checking `a` - --> $DIR/infinite-recursion-const-fn.rs:3:1 - | -LL | const fn a() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `b`... - --> $DIR/infinite-recursion-const-fn.rs:7:1 - | -LL | const fn b() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `a`, completing the cycle -note: cycle used when const-evaluating + checking `ARR::{constant#0}` - --> $DIR/infinite-recursion-const-fn.rs:10:18 +error[E0080]: evaluation of constant value failed + --> $DIR/infinite-recursion-const-fn.rs:4:5 | +LL | b() + | ^^^ + | | + | reached the configured maximum number of stack frames + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 +... +LL | a() + | --- + | | + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 +LL | } LL | const ARR: [i32; a()] = [5; 6]; - | ^^^ + | --- inside `ARR::{constant#0}` at $DIR/infinite-recursion-const-fn.rs:9:18 error: aborting due to previous error -For more information about this error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/infinite/infinite-struct.rs b/src/test/ui/infinite/infinite-struct.rs new file mode 100644 index 0000000000..70a203ea6e --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.rs @@ -0,0 +1,10 @@ +struct Take(Take); +//~^ ERROR has infinite size +//~| ERROR cycle detected + +// check that we don't hang trying to find the tail of a recursive struct (#79437) +fn foo() -> Take { + Take(loop {}) +} + +fn main() {} diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr new file mode 100644 index 0000000000..d180670e38 --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -0,0 +1,27 @@ +error[E0072]: recursive type `Take` has infinite size + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^----^^ + | | | + | | recursive without indirection + | recursive type has infinite size + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` representable + | +LL | struct Take(Box); + | ^^^^ ^ + +error[E0391]: cycle detected when computing drop-check constraints for `Take` + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing drop-check constraints for `Take`, completing the cycle + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`. diff --git a/src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs b/src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs new file mode 100644 index 0000000000..42ed5d19de --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/auxiliary/repeat.rs @@ -0,0 +1,54 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::{Ident, Group, TokenStream, TokenTree as Tt}; + +// This constant has to be above the ALLOCATING_ALGO_THRESHOLD +// constant in inherent_impls_overlap.rs +const REPEAT_COUNT: u32 = 501; + +#[proc_macro] +/// Repeats the input many times, while replacing idents +/// named "IDENT" with "id_$v", where v is a counter. +pub fn repeat_with_idents(input: TokenStream) -> TokenStream { + let mut res = Vec::new(); + fn visit_stream(res: &mut Vec, stream :TokenStream, v: u32) { + let mut stream_iter = stream.into_iter(); + while let Some(tt) = stream_iter.next() { + match tt { + Tt::Group(group) => { + let tt = Tt::Group(visit_group(group, v)); + res.push(tt); + }, + Tt::Ident(id) => { + let id = if &id.to_string() == "IDENT" { + Ident::new(&format!("id_{}", v), id.span()) + } else { + id + }; + res.push(Tt::Ident(id)); + }, + Tt::Punct(p) => { + res.push(Tt::Punct(p)); + }, + Tt::Literal(lit) => { + res.push(Tt::Literal(lit)); + }, + } + } + } + fn visit_group(group :Group, v: u32) -> Group { + let mut res = Vec::new(); + visit_stream(&mut res, group.stream(), v); + let stream = res.into_iter().collect(); + let delim = group.delimiter(); + Group::new(delim, stream) + } + for v in 0 .. REPEAT_COUNT { + visit_stream(&mut res, input.clone(), v) + } + res.into_iter().collect() +} diff --git a/src/test/ui/inherent-impls-overlap-check/no-overlap.rs b/src/test/ui/inherent-impls-overlap-check/no-overlap.rs new file mode 100644 index 0000000000..341bfc7b60 --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/no-overlap.rs @@ -0,0 +1,34 @@ +// run-pass +// aux-build:repeat.rs + +// This tests the allocating algo branch of the +// inherent impls overlap checker. +// This branch was added by PR: +// https://github.com/rust-lang/rust/pull/78317 +// In this test, we repeat many impl blocks +// to trigger the allocating branch. + +#![allow(unused)] + +extern crate repeat; + +// Simple case where each impl block is distinct + +struct Foo {} + +repeat::repeat_with_idents!(impl Foo { fn IDENT() {} }); + +// There are overlapping impl blocks but due to generics, +// they may overlap. + +struct Bar(T); + +struct A; +struct B; + +repeat::repeat_with_idents!(impl Bar { fn IDENT() {} }); + +impl Bar { fn foo() {} } +impl Bar { fn foo() {} } + +fn main() {} diff --git a/src/test/ui/inherent-impls-overlap-check/overlap.rs b/src/test/ui/inherent-impls-overlap-check/overlap.rs new file mode 100644 index 0000000000..6f2801197e --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/overlap.rs @@ -0,0 +1,71 @@ +// aux-build:repeat.rs + +#![allow(unused)] + +// This tests the allocating algo branch of the +// inherent impls overlap checker. +// This branch was added by PR: +// https://github.com/rust-lang/rust/pull/78317 +// In this test, we repeat many impl blocks +// to trigger the allocating branch. + +// Simple overlap + +extern crate repeat; + +struct Foo {} + +repeat::repeat_with_idents!(impl Foo { fn IDENT() {} }); + +impl Foo { fn hello() {} } //~ERROR duplicate definitions with name `hello` +impl Foo { fn hello() {} } + +// Transitive overlap + +struct Foo2 {} + +repeat::repeat_with_idents!(impl Foo2 { fn IDENT() {} }); + +impl Foo2 { + fn bar() {} + fn hello2() {} //~ERROR duplicate definitions with name `hello2` +} + +impl Foo2 { + fn baz() {} + fn hello2() {} +} + +// Slightly stronger transitive overlap + +struct Foo3 {} + +repeat::repeat_with_idents!(impl Foo3 { fn IDENT() {} }); + +impl Foo3 { + fn bar() {} //~ERROR duplicate definitions with name `bar` + fn hello3() {} //~ERROR duplicate definitions with name `hello3` +} + +impl Foo3 { + fn bar() {} + fn hello3() {} +} + +// Generic overlap + +struct Bar(T); + +struct A; +struct B; + +repeat::repeat_with_idents!(impl Bar { fn IDENT() {} }); + +impl Bar { fn foo() {} fn bar2() {} } +impl Bar { + fn foo() {} + fn bar2() {} //~ERROR duplicate definitions with name `bar2` +} +impl Bar { fn bar2() {} } + +fn main() {} diff --git a/src/test/ui/inherent-impls-overlap-check/overlap.stderr b/src/test/ui/inherent-impls-overlap-check/overlap.stderr new file mode 100644 index 0000000000..3dd2793712 --- /dev/null +++ b/src/test/ui/inherent-impls-overlap-check/overlap.stderr @@ -0,0 +1,47 @@ +error[E0592]: duplicate definitions with name `hello` + --> $DIR/overlap.rs:20:12 + | +LL | impl Foo { fn hello() {} } + | ^^^^^^^^^^ duplicate definitions for `hello` +LL | impl Foo { fn hello() {} } + | ---------- other definition for `hello` + +error[E0592]: duplicate definitions with name `hello2` + --> $DIR/overlap.rs:31:5 + | +LL | fn hello2() {} + | ^^^^^^^^^^^ duplicate definitions for `hello2` +... +LL | fn hello2() {} + | ----------- other definition for `hello2` + +error[E0592]: duplicate definitions with name `bar` + --> $DIR/overlap.rs:46:5 + | +LL | fn bar() {} + | ^^^^^^^^ duplicate definitions for `bar` +... +LL | fn bar() {} + | -------- other definition for `bar` + +error[E0592]: duplicate definitions with name `hello3` + --> $DIR/overlap.rs:47:5 + | +LL | fn hello3() {} + | ^^^^^^^^^^^ duplicate definitions for `hello3` +... +LL | fn hello3() {} + | ----------- other definition for `hello3` + +error[E0592]: duplicate definitions with name `bar2` + --> $DIR/overlap.rs:67:5 + | +LL | fn bar2() {} + | ^^^^^^^^^ duplicate definitions for `bar2` +LL | } +LL | impl Bar { fn bar2() {} } + | --------- other definition for `bar2` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0592`. diff --git a/src/test/ui/intrinsics/intrinsic-alignment.rs b/src/test/ui/intrinsics/intrinsic-alignment.rs index 896651361b..2bf40db5ad 100644 --- a/src/test/ui/intrinsics/intrinsic-alignment.rs +++ b/src/test/ui/intrinsics/intrinsic-alignment.rs @@ -11,7 +11,6 @@ mod rusti { } #[cfg(any(target_os = "android", - target_os = "cloudabi", target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.rs b/src/test/ui/invalid-rustc_args_required_const-arguments.rs index 76c01c2130..99508baeb0 100644 --- a/src/test/ui/invalid-rustc_args_required_const-arguments.rs +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.rs @@ -23,4 +23,10 @@ extern { fn foo7(_: u8); } +#[rustc_args_required_const] //~ ERROR malformed `rustc_args_required_const` attribute +fn bar1() {} + +#[rustc_args_required_const = 1] //~ ERROR malformed `rustc_args_required_const` attribute +fn bar2() {} + fn main() {} diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr index 39d0462616..932344f0a3 100644 --- a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr @@ -6,6 +6,18 @@ LL | #[rustc_args_required_const(0usize)] | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) +error: malformed `rustc_args_required_const` attribute input + --> $DIR/invalid-rustc_args_required_const-arguments.rs:26:1 + | +LL | #[rustc_args_required_const] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_args_required_const(N)]` + +error: malformed `rustc_args_required_const` attribute input + --> $DIR/invalid-rustc_args_required_const-arguments.rs:29:1 + | +LL | #[rustc_args_required_const = 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_args_required_const(N)]` + error: index exceeds number of arguments --> $DIR/invalid-rustc_args_required_const-arguments.rs:3:29 | @@ -44,5 +56,5 @@ error: index exceeds number of arguments LL | #[rustc_args_required_const(1)] | ^ there is only 1 argument -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/issues/issue-10626.rs b/src/test/ui/issues/issue-10626.rs index 78fa8b7c6f..696a2dd165 100644 --- a/src/test/ui/issues/issue-10626.rs +++ b/src/test/ui/issues/issue-10626.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-10767.rs b/src/test/ui/issues/issue-10767.rs index fa10f073b4..f40815fdbd 100644 --- a/src/test/ui/issues/issue-10767.rs +++ b/src/test/ui/issues/issue-10767.rs @@ -5,6 +5,6 @@ pub fn main() { fn f() { - }; + } let _: Box = box (f as fn()); } diff --git a/src/test/ui/issues/issue-12133-3.rs b/src/test/ui/issues/issue-12133-3.rs index c8aa9bf464..e6b16e2da1 100644 --- a/src/test/ui/issues/issue-12133-3.rs +++ b/src/test/ui/issues/issue-12133-3.rs @@ -2,7 +2,6 @@ // aux-build:issue-12133-rlib.rs // aux-build:issue-12133-dylib.rs // aux-build:issue-12133-dylib2.rs -// ignore-cloudabi no dylib support // ignore-emscripten no dylib support // ignore-musl // ignore-sgx no dylib support diff --git a/src/test/ui/issues/issue-13304.rs b/src/test/ui/issues/issue-13304.rs index 5698536ab5..b10f6d5725 100644 --- a/src/test/ui/issues/issue-13304.rs +++ b/src/test/ui/issues/issue-13304.rs @@ -1,6 +1,5 @@ // run-pass #![allow(unused_mut)] -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-14456.rs b/src/test/ui/issues/issue-14456.rs index 164d7ef8af..52a56eb77f 100644 --- a/src/test/ui/issues/issue-14456.rs +++ b/src/test/ui/issues/issue-14456.rs @@ -1,6 +1,5 @@ // run-pass #![allow(unused_mut)] -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-14940.rs b/src/test/ui/issues/issue-14940.rs index 785ad6a2c4..98a4af0c46 100644 --- a/src/test/ui/issues/issue-14940.rs +++ b/src/test/ui/issues/issue-14940.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-15129.rs b/src/test/ui/issues/issue-15129.rs deleted file mode 100644 index ed134c175e..0000000000 --- a/src/test/ui/issues/issue-15129.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub enum T { - T1(()), - T2(()) -} - -pub enum V { - V1(isize), - V2(bool) -} - -fn main() { - match (T::T1(()), V::V2(true)) { - //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered - (T::T1(()), V::V1(i)) => (), - (T::T2(()), V::V2(b)) => () - } -} diff --git a/src/test/ui/issues/issue-15919-32.stderr b/src/test/ui/issues/issue-15919-32.stderr index 8411313fc8..133637f9a0 100644 --- a/src/test/ui/issues/issue-15919-32.stderr +++ b/src/test/ui/issues/issue-15919-32.stderr @@ -1,4 +1,4 @@ -error: the type `[usize; 4294967295]` is too big for the current architecture +error: values of the type `[usize; 4294967295]` are too big for the current architecture --> $DIR/issue-15919-32.rs:9:9 | LL | let x = [0usize; 0xffff_ffff]; diff --git a/src/test/ui/issues/issue-15919-64.stderr b/src/test/ui/issues/issue-15919-64.stderr index f624c96ce8..193b823035 100644 --- a/src/test/ui/issues/issue-15919-64.stderr +++ b/src/test/ui/issues/issue-15919-64.stderr @@ -1,4 +1,4 @@ -error: the type `[usize; 18446744073709551615]` is too big for the current architecture +error: values of the type `[usize; 18446744073709551615]` are too big for the current architecture --> $DIR/issue-15919-64.rs:9:9 | LL | let x = [0usize; 0xffff_ffff_ffff_ffff]; diff --git a/src/test/ui/issues/issue-16272.rs b/src/test/ui/issues/issue-16272.rs index 3ba2483f43..5cf3fd9492 100644 --- a/src/test/ui/issues/issue-16272.rs +++ b/src/test/ui/issues/issue-16272.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-17121.rs b/src/test/ui/issues/issue-17121.rs index 34b1e2099b..1e7b9f015b 100644 --- a/src/test/ui/issues/issue-17121.rs +++ b/src/test/ui/issues/issue-17121.rs @@ -1,7 +1,6 @@ // check-pass #![allow(dead_code)] // pretty-expanded FIXME #23616 -// ignore-cloudabi no std::fs use std::fs::File; use std::io::{self, BufReader, Read}; diff --git a/src/test/ui/issues/issue-17913.stderr b/src/test/ui/issues/issue-17913.stderr index ae388c4d49..9a6431d447 100644 --- a/src/test/ui/issues/issue-17913.stderr +++ b/src/test/ui/issues/issue-17913.stderr @@ -1,4 +1,4 @@ -error: the type `[&usize; N]` is too big for the current architecture +error: values of the type `[&usize; N]` are too big for the current architecture error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index 35fa5fde0a..3bd9c656e8 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -6,133 +6,7 @@ LL | 0.contains(bits); | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_18400`) = note: required because of the requirements on the impl of `Set<&[_]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[_]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[_]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[_]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[_]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[_]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[_]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[_]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[_]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` - = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: 128 redundant requirements hidden = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20091.rs b/src/test/ui/issues/issue-20091.rs index 90db44fa02..86cc79d6b4 100644 --- a/src/test/ui/issues/issue-20091.rs +++ b/src/test/ui/issues/issue-20091.rs @@ -1,7 +1,6 @@ // run-pass #![allow(stable_features)] -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-20413.rs b/src/test/ui/issues/issue-20413.rs index 19ef52af65..a4345ccdfb 100644 --- a/src/test/ui/issues/issue-20413.rs +++ b/src/test/ui/issues/issue-20413.rs @@ -13,4 +13,32 @@ impl Foo for T where NoData: Foo { } } +trait Bar { + fn answer(self); +} + +trait Baz { + fn answer(self); +} + +struct AlmostNoData(Option); + +struct EvenLessData(Option); + +impl Bar for T where EvenLessData: Baz { +//~^ ERROR: overflow evaluating the requirement +//~| ERROR: overflow evaluating the requirement + fn answer(self) { + let val: EvenLessData = EvenLessData(None); + } +} + +impl Baz for T where AlmostNoData: Bar { +//~^ ERROR: overflow evaluating the requirement +//~| ERROR: overflow evaluating the requirement + fn answer(self) { + let val: NoData = AlmostNoData(None); + } +} + fn main() {} diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index 3f96f0bfcd..b167bb77b5 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -17,134 +17,39 @@ LL | impl Foo for T where NoData: Foo { | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>` + = note: 127 redundant requirements hidden = note: required because of the requirements on the impl of `Foo` for `NoData` +error[E0275]: overflow evaluating the requirement `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz` + --> $DIR/issue-20413.rs:28:42 + | +LL | trait Baz { + | --------- required by this bound in `Baz` +... +LL | impl Bar for T where EvenLessData: Baz { + | ^^^ + | + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: 126 redundant requirements hidden + = note: required because of the requirements on the impl of `Baz` for `EvenLessData` + +error[E0275]: overflow evaluating the requirement `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar` + --> $DIR/issue-20413.rs:36:42 + | +LL | trait Bar { + | --------- required by this bound in `Bar` +... +LL | impl Baz for T where AlmostNoData: Bar { + | ^^^ + | + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: 126 redundant requirements hidden + = note: required because of the requirements on the impl of `Bar` for `AlmostNoData` + error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:36 | @@ -156,135 +61,40 @@ LL | impl Foo for T where NoData: Foo { | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>` + = note: 127 redundant requirements hidden = note: required because of the requirements on the impl of `Foo` for `NoData` -error: aborting due to 3 previous errors +error[E0275]: overflow evaluating the requirement `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz` + --> $DIR/issue-20413.rs:28:42 + | +LL | trait Baz { + | --------- required by this bound in `Baz` +... +LL | impl Bar for T where EvenLessData: Baz { + | ^^^ + | + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: 126 redundant requirements hidden + = note: required because of the requirements on the impl of `Baz` for `EvenLessData` + +error[E0275]: overflow evaluating the requirement `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar` + --> $DIR/issue-20413.rs:36:42 + | +LL | trait Bar { + | --------- required by this bound in `Bar` +... +LL | impl Baz for T where AlmostNoData: Bar { + | ^^^ + | + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: 126 redundant requirements hidden + = note: required because of the requirements on the impl of `Bar` for `AlmostNoData` + +error: aborting due to 7 previous errors Some errors have detailed explanations: E0275, E0392. For more information about an error, try `rustc --explain E0275`. diff --git a/src/test/ui/issues/issue-20427.rs b/src/test/ui/issues/issue-20427.rs index fa2ea6cf59..41922c6229 100644 --- a/src/test/ui/issues/issue-20427.rs +++ b/src/test/ui/issues/issue-20427.rs @@ -4,6 +4,7 @@ #![allow(unused_imports)] #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] +#![allow(deprecated, deprecated_in_future)] // aux-build:i8.rs // ignore-pretty issue #37201 diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index 3c14226b73..3f7226c79b 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -6,7 +6,7 @@ LL | fn iceman(c: Vec<[i32]>) {} | ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | -LL | pub struct Vec { +LL | pub struct Vec { | - required by this bound in `Vec` | = help: the trait `Sized` is not implemented for `[i32]` diff --git a/src/test/ui/issues/issue-20616-2.rs b/src/test/ui/issues/issue-20616-2.rs index 2f2c6903a9..f108ae5de1 100644 --- a/src/test/ui/issues/issue-20616-2.rs +++ b/src/test/ui/issues/issue-20616-2.rs @@ -9,7 +9,7 @@ type Type_1_<'a, T> = &'a T; //type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T` -type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(` +type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,`, `:`, `=`, or `>`, found `(` //type Type_3 = Box; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-2.stderr b/src/test/ui/issues/issue-20616-2.stderr index 50ec7a304c..01e3d3dd7c 100644 --- a/src/test/ui/issues/issue-20616-2.stderr +++ b/src/test/ui/issues/issue-20616-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `>`, found `(` +error: expected one of `,`, `:`, `=`, or `>`, found `(` --> $DIR/issue-20616-2.rs:12:31 | LL | type Type_2 = Type_1_<'static ()>; - | ^ expected one of `,` or `>` + | ^ expected one of `,`, `:`, `=`, or `>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-3.rs b/src/test/ui/issues/issue-20616-3.rs index 9bfd5bf231..b2371051c7 100644 --- a/src/test/ui/issues/issue-20616-3.rs +++ b/src/test/ui/issues/issue-20616-3.rs @@ -11,7 +11,7 @@ type Type_1_<'a, T> = &'a T; type Type_3 = Box; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_4 = Type_1_<'static,, T>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-3.stderr b/src/test/ui/issues/issue-20616-3.stderr index cc4d79484e..b535c7a326 100644 --- a/src/test/ui/issues/issue-20616-3.stderr +++ b/src/test/ui/issues/issue-20616-3.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-3.rs:13:24 | LL | type Type_3 = Box; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-4.rs b/src/test/ui/issues/issue-20616-4.rs index e9a34a0466..a71f47ca4b 100644 --- a/src/test/ui/issues/issue-20616-4.rs +++ b/src/test/ui/issues/issue-20616-4.rs @@ -14,7 +14,7 @@ type Type_1_<'a, T> = &'a T; type Type_4 = Type_1_<'static,, T>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` type Type_5_<'a> = Type_1_<'a, ()>; diff --git a/src/test/ui/issues/issue-20616-4.stderr b/src/test/ui/issues/issue-20616-4.stderr index 254e4d6a34..2b3b75f311 100644 --- a/src/test/ui/issues/issue-20616-4.stderr +++ b/src/test/ui/issues/issue-20616-4.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-4.rs:16:34 | LL | type Type_4 = Type_1_<'static,, T>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-5.rs b/src/test/ui/issues/issue-20616-5.rs index 23862516d2..b96d09d59a 100644 --- a/src/test/ui/issues/issue-20616-5.rs +++ b/src/test/ui/issues/issue-20616-5.rs @@ -20,7 +20,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_5<'a> = Type_1_<'a, (),,>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-5.stderr b/src/test/ui/issues/issue-20616-5.stderr index aee8bf01a4..1ec1dbde69 100644 --- a/src/test/ui/issues/issue-20616-5.stderr +++ b/src/test/ui/issues/issue-20616-5.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-5.rs:22:34 | LL | type Type_5<'a> = Type_1_<'a, (),,>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-6.rs b/src/test/ui/issues/issue-20616-6.rs index dc327f3f78..a2c45ecec7 100644 --- a/src/test/ui/issues/issue-20616-6.rs +++ b/src/test/ui/issues/issue-20616-6.rs @@ -23,7 +23,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_6 = Type_5_<'a,,>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_7 = Box<(),,>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-6.stderr b/src/test/ui/issues/issue-20616-6.stderr index 7192a87bc1..7401abdd09 100644 --- a/src/test/ui/issues/issue-20616-6.stderr +++ b/src/test/ui/issues/issue-20616-6.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-6.rs:25:26 | LL | type Type_6 = Type_5_<'a,,>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-7.rs b/src/test/ui/issues/issue-20616-7.rs index ffd1620c1d..67209c02ad 100644 --- a/src/test/ui/issues/issue-20616-7.rs +++ b/src/test/ui/issues/issue-20616-7.rs @@ -26,7 +26,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_7 = Box<(),,>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_8<'a,,> = &'a (); // error: expected ident, found `,` diff --git a/src/test/ui/issues/issue-20616-7.stderr b/src/test/ui/issues/issue-20616-7.stderr index 123dc1e2b7..e2c3efe844 100644 --- a/src/test/ui/issues/issue-20616-7.stderr +++ b/src/test/ui/issues/issue-20616-7.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-7.rs:28:22 | LL | type Type_7 = Box<(),,>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20644.rs b/src/test/ui/issues/issue-20644.rs index 36eac38249..71c6746e0e 100644 --- a/src/test/ui/issues/issue-20644.rs +++ b/src/test/ui/issues/issue-20644.rs @@ -7,7 +7,6 @@ // had to do with codegen ignoring binders. // pretty-expanded FIXME #23616 -// ignore-cloudabi no std::fs #![feature(os)] diff --git a/src/test/ui/issues/issue-2074.rs b/src/test/ui/issues/issue-2074.rs index bd5f015cca..a6bea38580 100644 --- a/src/test/ui/issues/issue-2074.rs +++ b/src/test/ui/issues/issue-2074.rs @@ -5,11 +5,11 @@ pub fn main() { let one = || { - enum r { a }; + enum r { a } r::a as usize }; let two = || { - enum r { a }; + enum r { a } r::a as usize }; one(); two(); diff --git a/src/test/ui/issues/issue-20797.rs b/src/test/ui/issues/issue-20797.rs index 5d82592e5e..ef0e72571e 100644 --- a/src/test/ui/issues/issue-20797.rs +++ b/src/test/ui/issues/issue-20797.rs @@ -1,5 +1,4 @@ // build-pass -// ignore-cloudabi no std::fs // Regression test for #20797. diff --git a/src/test/ui/issues/issue-2111.rs b/src/test/ui/issues/issue-2111.rs deleted file mode 100644 index 7e5835e869..0000000000 --- a/src/test/ui/issues/issue-2111.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn foo(a: Option, b: Option) { - match (a,b) { - //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered - (Some(a), Some(b)) if a == b => { } - (Some(_), None) | - (None, Some(_)) => { } - } -} - -fn main() { - foo(None, None); -} diff --git a/src/test/ui/issues/issue-21475.rs b/src/test/ui/issues/issue-21475.rs index ab0a188696..b028fcae07 100644 --- a/src/test/ui/issues/issue-21475.rs +++ b/src/test/ui/issues/issue-21475.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(unused_imports, overlapping_patterns)] +#![allow(unused_imports, overlapping_range_endpoints)] // pretty-expanded FIXME #23616 use m::{START, END}; diff --git a/src/test/ui/issues/issue-2214.rs b/src/test/ui/issues/issue-2214.rs index 9b7c448541..52ab29f423 100644 --- a/src/test/ui/issues/issue-2214.rs +++ b/src/test/ui/issues/issue-2214.rs @@ -24,7 +24,7 @@ mod m { use libc::{c_double, c_int}; extern { - #[cfg(any(all(unix, not(target_os = "vxworks")), target_os = "cloudabi"))] + #[cfg(all(unix, not(target_os = "vxworks")))] #[link_name="lgamma_r"] pub fn lgamma(n: c_double, sign: &mut c_int) -> c_double; #[cfg(windows)] diff --git a/src/test/ui/issues/issue-22577.rs b/src/test/ui/issues/issue-22577.rs index 24f4f60aa2..8aca21bf10 100644 --- a/src/test/ui/issues/issue-22577.rs +++ b/src/test/ui/issues/issue-22577.rs @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] // pretty-expanded FIXME #23616 -// ignore-cloudabi no std::fs use std::{fs, net}; diff --git a/src/test/ui/issues/issue-23036.rs b/src/test/ui/issues/issue-23036.rs index a307e7eed9..d67f184720 100644 --- a/src/test/ui/issues/issue-23036.rs +++ b/src/test/ui/issues/issue-23036.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no std::path use std::collections::HashMap; use std::path::Path; diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index ff7e884ea6..ce3bffe602 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,10 +1,11 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23649-2.rs b/src/test/ui/issues/issue-23649-2.rs index f5fb8b6502..ce7d8e3a75 100644 --- a/src/test/ui/issues/issue-23649-2.rs +++ b/src/test/ui/issues/issue-23649-2.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no std::path use std::collections::HashMap; use std::path::{Path, PathBuf}; diff --git a/src/test/ui/issues/issue-23833.rs b/src/test/ui/issues/issue-23833.rs index 77dc5c50d7..d4128fa54e 100644 --- a/src/test/ui/issues/issue-23833.rs +++ b/src/test/ui/issues/issue-23833.rs @@ -1,8 +1,6 @@ // run-pass #![allow(unused_imports)] use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 - 1i8) as usize] diff --git a/src/test/ui/issues/issue-24313.rs b/src/test/ui/issues/issue-24313.rs index 2c420dc056..c28b4ca960 100644 --- a/src/test/ui/issues/issue-24313.rs +++ b/src/test/ui/issues/issue-24313.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no threads // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-26251.rs b/src/test/ui/issues/issue-26251.rs index edb06fea8a..a3e26a4123 100644 --- a/src/test/ui/issues/issue-26251.rs +++ b/src/test/ui/issues/issue-26251.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(overlapping_patterns)] +#![allow(overlapping_range_endpoints)] fn main() { let x = 'a'; diff --git a/src/test/ui/issues/issue-27859.rs b/src/test/ui/issues/issue-27859.rs index 259d706fa2..233670681f 100644 --- a/src/test/ui/issues/issue-27859.rs +++ b/src/test/ui/issues/issue-27859.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no std::env // ignore-wasm32 issue 42629 #[inline(never)] diff --git a/src/test/ui/issues/issue-29516.rs b/src/test/ui/issues/issue-29516.rs index 035f904b15..6779d508dd 100644 --- a/src/test/ui/issues/issue-29516.rs +++ b/src/test/ui/issues/issue-29516.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] auto trait NotSame {} diff --git a/src/test/ui/issues/issue-30490.rs b/src/test/ui/issues/issue-30490.rs index 76e7224688..47c17e362a 100644 --- a/src/test/ui/issues/issue-30490.rs +++ b/src/test/ui/issues/issue-30490.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 818e004ffc..d371703e29 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -13,11 +13,13 @@ error[E0599]: no method named `collect` found for struct `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` | - ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL + ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL | LL | pub struct Cloned { | -------------------- doesn't satisfy `_: Iterator` -... + | + ::: $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL + | LL | pub struct TakeWhile { | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_` | diff --git a/src/test/ui/issues/issue-33770.rs b/src/test/ui/issues/issue-33770.rs index 39ae009c99..f3c99015b6 100644 --- a/src/test/ui/issues/issue-33770.rs +++ b/src/test/ui/issues/issue-33770.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index bf2d091a01..b45c00f694 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -1,6 +1,6 @@ fn main () { let sr: Vec<(u32, _, _) = vec![]; - //~^ ERROR expected one of `,` or `>`, found `=` + //~^ ERROR only path types can be used in associated type constraints let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index c10a414430..a9b9bf06d7 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `>`, found `=` - --> $DIR/issue-34334.rs:2:29 +error: only path types can be used in associated type constraints + --> $DIR/issue-34334.rs:2:17 | LL | let sr: Vec<(u32, _, _) = vec![]; - | -- ^ expected one of `,` or `>` + | -- ^^^^^^^^^^^ | | | while parsing the type for `sr` diff --git a/src/test/ui/issues/issue-37665.rs b/src/test/ui/issues/issue-37665.rs index c20782a7eb..81ff478aab 100644 --- a/src/test/ui/issues/issue-37665.rs +++ b/src/test/ui/issues/issue-37665.rs @@ -1,5 +1,4 @@ // compile-flags: -Z unpretty=mir -// ignore-cloudabi no std::path use std::path::MAIN_SEPARATOR; diff --git a/src/test/ui/issues/issue-37665.stderr b/src/test/ui/issues/issue-37665.stderr index 1e191a620a..1e1f451b45 100644 --- a/src/test/ui/issues/issue-37665.stderr +++ b/src/test/ui/issues/issue-37665.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-37665.rs:10:17 + --> $DIR/issue-37665.rs:9:17 | LL | let x: () = 0; | -- ^ expected `()`, found integer diff --git a/src/test/ui/issues/issue-37686.rs b/src/test/ui/issues/issue-37686.rs index 8c37625144..ba58e9e9d8 100644 --- a/src/test/ui/issues/issue-37686.rs +++ b/src/test/ui/issues/issue-37686.rs @@ -1,7 +1,7 @@ // run-pass fn main() { match (0, 0) { - (std::usize::MIN, std::usize::MAX) => {} + (usize::MIN, usize::MAX) => {} _ => {} } } diff --git a/src/test/ui/issues/issue-39175.rs b/src/test/ui/issues/issue-39175.rs index 3ba2a9d40b..3866e0651c 100644 --- a/src/test/ui/issues/issue-39175.rs +++ b/src/test/ui/issues/issue-39175.rs @@ -4,7 +4,6 @@ // these platforms also. // ignore-windows -// ignore-cloudabi // ignore-emscripten // ignore-sgx no processes diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr index dbb334e7b9..afceae82e6 100644 --- a/src/test/ui/issues/issue-39175.stderr +++ b/src/test/ui/issues/issue-39175.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `exec` found for mutable reference `&mut Command` in the current scope - --> $DIR/issue-39175.rs:15:39 + --> $DIR/issue-39175.rs:14:39 | LL | Command::new("echo").arg("hello").exec(); | ^^^^ method not found in `&mut Command` diff --git a/src/test/ui/issues/issue-39559-2.rs b/src/test/ui/issues/issue-39559-2.rs index 3a52e4d621..07d3a82b1e 100644 --- a/src/test/ui/issues/issue-39559-2.rs +++ b/src/test/ui/issues/issue-39559-2.rs @@ -13,8 +13,6 @@ impl Dim for Dim3 { fn main() { let array: [usize; Dim3::dim()] //~^ ERROR E0015 - //~| ERROR E0080 = [0; Dim3::dim()]; //~^ ERROR E0015 - //~| ERROR E0080 } diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index 586debbbe5..3d765daa7c 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -4,25 +4,12 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | let array: [usize; Dim3::dim()] | ^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/issue-39559-2.rs:14:24 - | -LL | let array: [usize; Dim3::dim()] - | ^^^^^^^^^^^ calling non-const function `::dim` - error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-39559-2.rs:17:15 + --> $DIR/issue-39559-2.rs:16:15 | LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/issue-39559-2.rs:17:15 - | -LL | = [0; Dim3::dim()]; - | ^^^^^^^^^^^ calling non-const function `::dim` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr index f673fbae8b..4e2bde06a5 100644 --- a/src/test/ui/issues/issue-40000.nll.stderr +++ b/src/test/ui/issues/issue-40000.nll.stderr @@ -4,5 +4,11 @@ error: higher-ranked subtype error LL | foo(bar); | ^^^ -error: aborting due to previous error +error: higher-ranked subtype error + --> $DIR/issue-40000.rs:6:9 + | +LL | foo(bar); + | ^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-40845.stderr b/src/test/ui/issues/issue-40845.stderr index 2744330a4e..66bf053204 100644 --- a/src/test/ui/issues/issue-40845.stderr +++ b/src/test/ui/issues/issue-40845.stderr @@ -1,14 +1,14 @@ -error: cannot find macro `m` in this scope - --> $DIR/issue-40845.rs:4:10 - | -LL | impl S { m!(); } - | ^ - error: cannot find macro `m` in this scope --> $DIR/issue-40845.rs:1:11 | LL | trait T { m!(); } | ^ +error: cannot find macro `m` in this scope + --> $DIR/issue-40845.rs:4:10 + | +LL | impl S { m!(); } + | ^ + error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-41880.rs b/src/test/ui/issues/issue-41880.rs index 10cde21abd..977c43b71f 100644 --- a/src/test/ui/issues/issue-41880.rs +++ b/src/test/ui/issues/issue-41880.rs @@ -19,7 +19,7 @@ impl Iterator for Iterate where F: Fn(&T) -> T { Some(self.state.clone()) } #[inline] - fn size_hint(&self) -> (usize, Option) { (std::usize::MAX, None) } + fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } } fn main() { diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index cc4b3707dd..cde285f73d 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -6,7 +6,7 @@ LL | impl Drop for T where T: A { | = note: conflicting implementation in crate `alloc`: - impl Drop for Box - where A: AllocRef, T: ?Sized; + where A: Allocator, T: ?Sized; = note: downstream crates may implement trait `A` for type `std::boxed::Box<_, _>` error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions diff --git a/src/test/ui/issues/issue-43105.rs b/src/test/ui/issues/issue-43105.rs index 231af76fc9..cc6a485085 100644 --- a/src/test/ui/issues/issue-43105.rs +++ b/src/test/ui/issues/issue-43105.rs @@ -2,7 +2,6 @@ fn xyz() -> u8 { 42 } const NUM: u8 = xyz(); //~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants -//~| ERROR any use of this value will cause an error [const_err] fn main() { match 1 { diff --git a/src/test/ui/issues/issue-43105.stderr b/src/test/ui/issues/issue-43105.stderr index 1a7b67b563..e508cbdd1d 100644 --- a/src/test/ui/issues/issue-43105.stderr +++ b/src/test/ui/issues/issue-43105.stderr @@ -4,28 +4,18 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | const NUM: u8 = xyz(); | ^^^^^ -error: any use of this value will cause an error - --> $DIR/issue-43105.rs:3:17 - | -LL | const NUM: u8 = xyz(); - | ----------------^^^^^- - | | - | calling non-const function `xyz` - | - = note: `#[deny(const_err)]` on by default - error: could not evaluate constant pattern - --> $DIR/issue-43105.rs:9:9 + --> $DIR/issue-43105.rs:8:9 | LL | NUM => unimplemented!(), | ^^^ error: could not evaluate constant pattern - --> $DIR/issue-43105.rs:9:9 + --> $DIR/issue-43105.rs:8:9 | LL | NUM => unimplemented!(), | ^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-4541.rs b/src/test/ui/issues/issue-4541.rs index 1f871fcf61..e7f26d0215 100644 --- a/src/test/ui/issues/issue-4541.rs +++ b/src/test/ui/issues/issue-4541.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no std::env fn parse_args() -> String { let args: Vec<_> = ::std::env::args().collect(); diff --git a/src/test/ui/issues/issue-4542.rs b/src/test/ui/issues/issue-4542.rs index 24752114e9..2386561c39 100644 --- a/src/test/ui/issues/issue-4542.rs +++ b/src/test/ui/issues/issue-4542.rs @@ -1,6 +1,5 @@ // run-pass // pretty-expanded FIXME #23616 -// ignore-cloudabi no std::env use std::env; diff --git a/src/test/ui/issues/issue-48006.rs b/src/test/ui/issues/issue-48006.rs index 3a862ace55..cfef270e5a 100644 --- a/src/test/ui/issues/issue-48006.rs +++ b/src/test/ui/issues/issue-48006.rs @@ -6,10 +6,10 @@ use std::iter::Step; #[cfg(target_pointer_width = "16")] fn main() { - assert!(Step::steps_between(&0u32, &::std::u32::MAX).is_none()); + assert!(Step::steps_between(&0u32, &u32::MAX).is_none()); } #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] fn main() { - assert!(Step::steps_between(&0u32, &::std::u32::MAX).is_some()); + assert!(Step::steps_between(&0u32, &u32::MAX).is_some()); } diff --git a/src/test/ui/issues/issue-49934-errors.rs b/src/test/ui/issues/issue-49934-errors.rs index 6fa5f01ffd..bf95f8fa7e 100644 --- a/src/test/ui/issues/issue-49934-errors.rs +++ b/src/test/ui/issues/issue-49934-errors.rs @@ -1,10 +1,8 @@ fn foo<#[derive(Debug)] T>() { //~^ ERROR `derive` may only be applied to structs, enums and unions -//~| ERROR expected an inert attribute, found a derive macro match 0 { #[derive(Debug)] //~^ ERROR `derive` may only be applied to structs, enums and unions - //~| ERROR expected an inert attribute, found a derive macro _ => (), } } diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr index 3befb38a20..71cd2d3034 100644 --- a/src/test/ui/issues/issue-49934-errors.stderr +++ b/src/test/ui/issues/issue-49934-errors.stderr @@ -4,24 +4,12 @@ error[E0774]: `derive` may only be applied to structs, enums and unions LL | fn foo<#[derive(Debug)] T>() { | ^^^^^^^^^^^^^^^^ -error: expected an inert attribute, found a derive macro - --> $DIR/issue-49934-errors.rs:1:17 - | -LL | fn foo<#[derive(Debug)] T>() { - | ^^^^^ - error[E0774]: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-49934-errors.rs:5:9 + --> $DIR/issue-49934-errors.rs:4:9 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: expected an inert attribute, found a derive macro - --> $DIR/issue-49934-errors.rs:5:18 - | -LL | #[derive(Debug)] - | ^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-49955-2.rs b/src/test/ui/issues/issue-49955-2.rs deleted file mode 100644 index 267ed74632..0000000000 --- a/src/test/ui/issues/issue-49955-2.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// compile-flags: -Z borrowck=mir - -use std::cell::Cell; - -const FIVE: Cell = Cell::new(5); - -#[inline(never)] -fn tuple_field() -> &'static u32 { - // This test is MIR-borrowck-only because the old borrowck - // doesn't agree that borrows of "frozen" (i.e., without any - // interior mutability) fields of non-frozen temporaries, - // should be promoted, while MIR promotion does promote them. - &(FIVE, 42).1 -} - -fn main() { - assert_eq!(tuple_field().to_string(), "42"); -} diff --git a/src/test/ui/issues/issue-50811.rs b/src/test/ui/issues/issue-50811.rs index 63d87e03c4..683c856049 100644 --- a/src/test/ui/issues/issue-50811.rs +++ b/src/test/ui/issues/issue-50811.rs @@ -3,7 +3,6 @@ extern crate test; -use std::f64::{NAN, NEG_INFINITY, INFINITY, MAX}; use std::mem::size_of; use test::black_box; @@ -12,7 +11,7 @@ use test::black_box; macro_rules! compare { ($op:tt) => { compare!( - [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN], + [f64::NEG_INFINITY, -f64::MAX, -1.0, -0.0, 0.0, 1.0, f64::MAX, f64::INFINITY, f64::NAN], $op ); }; @@ -20,7 +19,7 @@ macro_rules! compare { $(compare!( $lhs, $op, - [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN] + [f64::NEG_INFINITY, -f64::MAX, -1.0, -0.0, 0.0, 1.0, f64::MAX, f64::INFINITY, f64::NAN] );)+ }; ($lhs:expr, $op:tt, [$($rhs:expr),+]) => { @@ -44,8 +43,8 @@ macro_rules! compare { fn main() { assert_eq!(0.0/0.0 < 0.0/0.0, false); assert_eq!(0.0/0.0 > 0.0/0.0, false); - assert_eq!(NAN < NAN, false); - assert_eq!(NAN > NAN, false); + assert_eq!(f64::NAN < f64::NAN, false); + assert_eq!(f64::NAN > f64::NAN, false); compare!(==); compare!(!=); diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.rs b/src/test/ui/issues/issue-52023-array-size-pointer-cast.rs index d12b483ba4..cc756ce815 100644 --- a/src/test/ui/issues/issue-52023-array-size-pointer-cast.rs +++ b/src/test/ui/issues/issue-52023-array-size-pointer-cast.rs @@ -1,4 +1,3 @@ fn main() { let _ = [0; (&0 as *const i32) as usize]; //~ ERROR casting pointers to integers in constants - //~^ ERROR evaluation of constant value failed } diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr index 0108a37e8f..68b5cbd9bd 100644 --- a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr +++ b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr @@ -7,13 +7,6 @@ LL | let _ = [0; (&0 as *const i32) as usize]; = note: see issue #51910 for more information = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0080]: evaluation of constant value failed - --> $DIR/issue-52023-array-size-pointer-cast.rs:2:17 - | -LL | let _ = [0; (&0 as *const i32) as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0080, E0658. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-52060.rs b/src/test/ui/issues/issue-52060.rs index fed08902c8..13b914c033 100644 --- a/src/test/ui/issues/issue-52060.rs +++ b/src/test/ui/issues/issue-52060.rs @@ -3,6 +3,5 @@ static A: &'static [u32] = &[1]; static B: [u32; 1] = [0; A.len()]; //~^ ERROR [E0013] -//~| ERROR evaluation of constant value failed fn main() {} diff --git a/src/test/ui/issues/issue-52060.stderr b/src/test/ui/issues/issue-52060.stderr index 502825e976..95e5f2a828 100644 --- a/src/test/ui/issues/issue-52060.stderr +++ b/src/test/ui/issues/issue-52060.stderr @@ -6,13 +6,6 @@ LL | static B: [u32; 1] = [0; A.len()]; | = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0080]: evaluation of constant value failed - --> $DIR/issue-52060.rs:4:26 - | -LL | static B: [u32; 1] = [0; A.len()]; - | ^ constant accesses static - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0013, E0080. -For more information about an error, try `rustc --explain E0013`. +For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/issues/issue-56762.rs b/src/test/ui/issues/issue-56762.rs index 5ba5b9847d..fb0a270f18 100644 --- a/src/test/ui/issues/issue-56762.rs +++ b/src/test/ui/issues/issue-56762.rs @@ -17,8 +17,8 @@ impl TooBigArray { } static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); -//~^ ERROR the type `[u8; 2305843009213693951]` is too big for the current architecture +//~^ ERROR values of the type `[u8; 2305843009213693951]` are too big static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; -//~^ ERROR the type `[u8; 2305843009213693951]` is too big for the current architecture +//~^ ERROR values of the type `[u8; 2305843009213693951]` are too big fn main() { } diff --git a/src/test/ui/issues/issue-56762.stderr b/src/test/ui/issues/issue-56762.stderr index 69626d4bc7..f26ef280b2 100644 --- a/src/test/ui/issues/issue-56762.stderr +++ b/src/test/ui/issues/issue-56762.stderr @@ -1,10 +1,10 @@ -error[E0080]: the type `[u8; 2305843009213693951]` is too big for the current architecture +error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the current architecture --> $DIR/issue-56762.rs:19:1 | LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: the type `[u8; 2305843009213693951]` is too big for the current architecture +error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the current architecture --> $DIR/issue-56762.rs:21:1 | LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; diff --git a/src/test/ui/issues/issue-68010-large-zst-consts.rs b/src/test/ui/issues/issue-68010-large-zst-consts.rs index 4f1bd45e90..3277df69c0 100644 --- a/src/test/ui/issues/issue-68010-large-zst-consts.rs +++ b/src/test/ui/issues/issue-68010-large-zst-consts.rs @@ -1,5 +1,5 @@ // build-pass fn main() { - println!("{}", [(); std::usize::MAX].len()); + println!("{}", [(); usize::MAX].len()); } diff --git a/src/test/ui/issues/issue-6804.rs b/src/test/ui/issues/issue-6804.rs index 325137327b..6d950c424e 100644 --- a/src/test/ui/issues/issue-6804.rs +++ b/src/test/ui/issues/issue-6804.rs @@ -3,7 +3,7 @@ #![allow(unused)] #![deny(illegal_floating_point_literal_pattern)] -use std::f64::NAN; +const NAN: f64 = f64::NAN; fn main() { let x = NAN; diff --git a/src/test/ui/issues/issue-73899.rs b/src/test/ui/issues/issue-73899.rs new file mode 100644 index 0000000000..2a3a5ab2a3 --- /dev/null +++ b/src/test/ui/issues/issue-73899.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(const_evaluatable_checked)] +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Foo {} + +impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} + +trait FooImpl {} + +impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {} + +impl FooImpl<{ 0u8 != 0u8 }> for [(); N] {} + +fn foo(_v: T) {} + +fn main() { + foo([]); + foo([()]); +} diff --git a/src/test/ui/issues/issue-75763.rs b/src/test/ui/issues/issue-75763.rs index 2fd9f9a60d..c311de05a1 100644 --- a/src/test/ui/issues/issue-75763.rs +++ b/src/test/ui/issues/issue-75763.rs @@ -1,4 +1,5 @@ -// build-pass +// ignore-test +// FIXME(const_generics): This test causes an ICE after reverting #76030. #![allow(incomplete_features)] #![feature(const_generics)] diff --git a/src/test/ui/issues/issue-76042.rs b/src/test/ui/issues/issue-76042.rs new file mode 100644 index 0000000000..34d5293799 --- /dev/null +++ b/src/test/ui/issues/issue-76042.rs @@ -0,0 +1,16 @@ +// run-pass +// compile-flags: -Coverflow-checks=off -Ccodegen-units=1 -Copt-level=0 + +fn foo(a: i128, b: i128, s: u32) -> (i128, i128) { + if s == 128 { + (0, 0) + } else { + (b >> s, a >> s) + } +} +fn main() { + let r = foo(0, 8, 1); + if r.0 != 4 { + panic!(); + } +} diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs index 9b04d5ee00..966d76d148 100644 --- a/src/test/ui/issues/issue-77919.rs +++ b/src/test/ui/issues/issue-77919.rs @@ -1,8 +1,8 @@ fn main() { - [1; >::VAL]; //~ ERROR evaluation of constant value failed + [1; >::VAL]; } trait TypeVal { - const VAL: T; //~ ERROR any use of this value will cause an error + const VAL: T; } struct Five; struct Multiply { diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index 129af00644..97bd5ab36b 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -26,21 +26,7 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: any use of this value will cause an error - --> $DIR/issue-77919.rs:5:5 - | -LL | const VAL: T; - | ^^^^^^^^^^^^^ no MIR body is available for DefId(0:7 ~ issue_77919[317d]::TypeVal::VAL) - | - = note: `#[deny(const_err)]` on by default - -error[E0080]: evaluation of constant value failed - --> $DIR/issue-77919.rs:2:9 - | -LL | [1; >::VAL]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0046, E0080, E0412. +Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/issues/issue-78720.rs b/src/test/ui/issues/issue-78720.rs new file mode 100644 index 0000000000..57615d1a20 --- /dev/null +++ b/src/test/ui/issues/issue-78720.rs @@ -0,0 +1,19 @@ +fn server() -> impl { +//~^ ERROR at least one trait must be specified + ().map2(|| "") +} + +trait FilterBase2 { + fn map2(self, F) -> Map2 {} + //~^ ERROR mismatched types + //~^^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +struct Map2 { + _func: F, + //~^ ERROR cannot find type `F` in this scope +} + +impl FilterBase2 for F {} + +fn main() {} diff --git a/src/test/ui/issues/issue-78720.stderr b/src/test/ui/issues/issue-78720.stderr new file mode 100644 index 0000000000..a3a14e34ac --- /dev/null +++ b/src/test/ui/issues/issue-78720.stderr @@ -0,0 +1,55 @@ +error: at least one trait must be specified + --> $DIR/issue-78720.rs:1:16 + | +LL | fn server() -> impl { + | ^^^^ + +error[E0412]: cannot find type `F` in this scope + --> $DIR/issue-78720.rs:13:12 + | +LL | _func: F, + | ^ + | + ::: $SRC_DIR/core/src/ops/function.rs:LL:COL + | +LL | pub trait Fn: FnMut { + | ------------------------------- similarly named trait `Fn` defined here + | +help: a trait with a similar name exists + | +LL | _func: Fn, + | ^^ +help: you might be missing a type parameter + | +LL | struct Map2 { + | ^^^ + +error[E0308]: mismatched types + --> $DIR/issue-78720.rs:7:36 + | +LL | fn map2(self, F) -> Map2 {} + | ^^ expected struct `Map2`, found `()` + | + = note: expected struct `Map2` + found unit type `()` + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-78720.rs:7:16 + | +LL | fn map2(self, F) -> Map2 {} + | ^^^^ doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider further restricting `Self` + | +LL | fn map2(self, F) -> Map2 where Self: Sized {} + | ^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn map2(&self, F) -> Map2 {} + | ^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0308, E0412. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-78957.rs b/src/test/ui/issues/issue-78957.rs new file mode 100644 index 0000000000..263c69bbc0 --- /dev/null +++ b/src/test/ui/issues/issue-78957.rs @@ -0,0 +1,30 @@ +#![deny(unused_attributes)] +#![feature(min_const_generics)] + +use std::marker::PhantomData; + +pub struct Foo<#[inline] const N: usize>; +//~^ ERROR attribute should be applied to function or closure +pub struct Bar<#[cold] const N: usize>; +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted +pub struct Baz<#[repr(C)] const N: usize>; +//~^ ERROR attribute should be applied to a struct, enum, or union +// +pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); +//~^ ERROR attribute should be applied to function or closure +pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted +pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>); +//~^ ERROR attribute should be applied to a struct, enum, or union +// +pub struct Foo3<#[inline] T>(PhantomData); +//~^ ERROR attribute should be applied to function or closure +pub struct Bar3<#[cold] T>(PhantomData); +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted +pub struct Baz3<#[repr(C)] T>(PhantomData); +//~^ ERROR attribute should be applied to a struct, enum, or union + +fn main() {} diff --git a/src/test/ui/issues/issue-78957.stderr b/src/test/ui/issues/issue-78957.stderr new file mode 100644 index 0000000000..26437ee4be --- /dev/null +++ b/src/test/ui/issues/issue-78957.stderr @@ -0,0 +1,69 @@ +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-78957.rs:6:16 + | +LL | pub struct Foo<#[inline] const N: usize>; + | ^^^^^^^^^ - not a function or closure + +error: attribute should be applied to a function + --> $DIR/issue-78957.rs:8:16 + | +LL | pub struct Bar<#[cold] const N: usize>; + | ^^^^^^^ - not a function + | +note: the lint level is defined here + --> $DIR/issue-78957.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:11:23 + | +LL | pub struct Baz<#[repr(C)] const N: usize>; + | ^ - not a struct, enum, or union + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-78957.rs:14:17 + | +LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); + | ^^^^^^^^^ -- not a function or closure + +error: attribute should be applied to a function + --> $DIR/issue-78957.rs:16:17 + | +LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); + | ^^^^^^^ -- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:19:24 + | +LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>); + | ^ -- not a struct, enum, or union + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-78957.rs:22:17 + | +LL | pub struct Foo3<#[inline] T>(PhantomData); + | ^^^^^^^^^ - not a function or closure + +error: attribute should be applied to a function + --> $DIR/issue-78957.rs:24:17 + | +LL | pub struct Bar3<#[cold] T>(PhantomData); + | ^^^^^^^ - not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:27:24 + | +LL | pub struct Baz3<#[repr(C)] T>(PhantomData); + | ^ - not a struct, enum, or union + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0517, E0518. +For more information about an error, try `rustc --explain E0517`. diff --git a/src/test/ui/issues/issue-79593.rs b/src/test/ui/issues/issue-79593.rs new file mode 100644 index 0000000000..fb54b36940 --- /dev/null +++ b/src/test/ui/issues/issue-79593.rs @@ -0,0 +1,29 @@ +mod foo { + pub struct Pub { private: () } + + pub enum Enum { + Variant { x: (), y: () }, + Other + } + + fn correct() { + Pub {}; + //~^ ERROR missing field `private` in initializer of `Pub` + Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + } +} + +fn correct() { + foo::Pub {}; + //~^ ERROR cannot construct `Pub` with struct literal syntax due to inaccessible fields +} + +fn wrong() { + foo::Enum::Variant { x: () }; + //~^ ERROR missing field `y` in initializer of `Enum` + foo::Enum::Variant { }; + //~^ ERROR missing fields `x`, `y` in initializer of `Enum` +} + +fn main() {} diff --git a/src/test/ui/issues/issue-79593.stderr b/src/test/ui/issues/issue-79593.stderr new file mode 100644 index 0000000000..33dbd85032 --- /dev/null +++ b/src/test/ui/issues/issue-79593.stderr @@ -0,0 +1,33 @@ +error[E0063]: missing field `private` in initializer of `Pub` + --> $DIR/issue-79593.rs:10:9 + | +LL | Pub {}; + | ^^^ missing `private` + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:12:9 + | +LL | Enum::Variant { x: () }; + | ^^^^^^^^^^^^^ missing `y` + +error: cannot construct `Pub` with struct literal syntax due to inaccessible fields + --> $DIR/issue-79593.rs:18:5 + | +LL | foo::Pub {}; + | ^^^^^^^^ + +error[E0063]: missing field `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:23:5 + | +LL | foo::Enum::Variant { x: () }; + | ^^^^^^^^^^^^^^^^^^ missing `y` + +error[E0063]: missing fields `x`, `y` in initializer of `Enum` + --> $DIR/issue-79593.rs:25:5 + | +LL | foo::Enum::Variant { }; + | ^^^^^^^^^^^^^^^^^^ missing `x`, `y` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0063`. diff --git a/src/test/ui/issues/issue-8460-const.noopt.stderr b/src/test/ui/issues/issue-8460-const.noopt.stderr index 739b546874..d94c7742de 100644 --- a/src/test/ui/issues/issue-8460-const.noopt.stderr +++ b/src/test/ui/issues/issue-8460-const.noopt.stderr @@ -1,5 +1,5 @@ error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:14:36 + --> $DIR/issue-8460-const.rs:13:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow @@ -7,37 +7,37 @@ LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); = note: `#[deny(arithmetic_overflow)]` on by default error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:16:36 + --> $DIR/issue-8460-const.rs:15:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:18:36 + --> $DIR/issue-8460-const.rs:17:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:20:36 + --> $DIR/issue-8460-const.rs:19:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:22:36 + --> $DIR/issue-8460-const.rs:21:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:24:36 + --> $DIR/issue-8460-const.rs:23:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:26:36 + --> $DIR/issue-8460-const.rs:25:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); | ^^^^^^^^^^ attempt to divide `1_isize` by zero @@ -45,103 +45,103 @@ LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); = note: `#[deny(unconditional_panic)]` on by default error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:28:36 + --> $DIR/issue-8460-const.rs:27:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:30:36 + --> $DIR/issue-8460-const.rs:29:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:32:36 + --> $DIR/issue-8460-const.rs:31:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:34:36 + --> $DIR/issue-8460-const.rs:33:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:36:36 + --> $DIR/issue-8460-const.rs:35:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:38:36 + --> $DIR/issue-8460-const.rs:37:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:40:36 + --> $DIR/issue-8460-const.rs:39:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:42:36 + --> $DIR/issue-8460-const.rs:41:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:44:36 + --> $DIR/issue-8460-const.rs:43:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:46:36 + --> $DIR/issue-8460-const.rs:45:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:48:36 + --> $DIR/issue-8460-const.rs:47:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:50:36 + --> $DIR/issue-8460-const.rs:49:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:52:36 + --> $DIR/issue-8460-const.rs:51:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:54:36 + --> $DIR/issue-8460-const.rs:53:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:56:36 + --> $DIR/issue-8460-const.rs:55:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:58:36 + --> $DIR/issue-8460-const.rs:57:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:60:36 + --> $DIR/issue-8460-const.rs:59:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero diff --git a/src/test/ui/issues/issue-8460-const.opt.stderr b/src/test/ui/issues/issue-8460-const.opt.stderr index 739b546874..d94c7742de 100644 --- a/src/test/ui/issues/issue-8460-const.opt.stderr +++ b/src/test/ui/issues/issue-8460-const.opt.stderr @@ -1,5 +1,5 @@ error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:14:36 + --> $DIR/issue-8460-const.rs:13:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow @@ -7,37 +7,37 @@ LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); = note: `#[deny(arithmetic_overflow)]` on by default error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:16:36 + --> $DIR/issue-8460-const.rs:15:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:18:36 + --> $DIR/issue-8460-const.rs:17:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:20:36 + --> $DIR/issue-8460-const.rs:19:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:22:36 + --> $DIR/issue-8460-const.rs:21:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:24:36 + --> $DIR/issue-8460-const.rs:23:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:26:36 + --> $DIR/issue-8460-const.rs:25:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); | ^^^^^^^^^^ attempt to divide `1_isize` by zero @@ -45,103 +45,103 @@ LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); = note: `#[deny(unconditional_panic)]` on by default error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:28:36 + --> $DIR/issue-8460-const.rs:27:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:30:36 + --> $DIR/issue-8460-const.rs:29:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:32:36 + --> $DIR/issue-8460-const.rs:31:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:34:36 + --> $DIR/issue-8460-const.rs:33:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:36:36 + --> $DIR/issue-8460-const.rs:35:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:38:36 + --> $DIR/issue-8460-const.rs:37:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:40:36 + --> $DIR/issue-8460-const.rs:39:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:42:36 + --> $DIR/issue-8460-const.rs:41:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:44:36 + --> $DIR/issue-8460-const.rs:43:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:46:36 + --> $DIR/issue-8460-const.rs:45:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:48:36 + --> $DIR/issue-8460-const.rs:47:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:50:36 + --> $DIR/issue-8460-const.rs:49:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:52:36 + --> $DIR/issue-8460-const.rs:51:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:54:36 + --> $DIR/issue-8460-const.rs:53:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:56:36 + --> $DIR/issue-8460-const.rs:55:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:58:36 + --> $DIR/issue-8460-const.rs:57:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:60:36 + --> $DIR/issue-8460-const.rs:59:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero diff --git a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr index 739b546874..d94c7742de 100644 --- a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr +++ b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr @@ -1,5 +1,5 @@ error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:14:36 + --> $DIR/issue-8460-const.rs:13:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow @@ -7,37 +7,37 @@ LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); = note: `#[deny(arithmetic_overflow)]` on by default error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:16:36 + --> $DIR/issue-8460-const.rs:15:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:18:36 + --> $DIR/issue-8460-const.rs:17:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:20:36 + --> $DIR/issue-8460-const.rs:19:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:22:36 + --> $DIR/issue-8460-const.rs:21:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:24:36 + --> $DIR/issue-8460-const.rs:23:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:26:36 + --> $DIR/issue-8460-const.rs:25:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); | ^^^^^^^^^^ attempt to divide `1_isize` by zero @@ -45,103 +45,103 @@ LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); = note: `#[deny(unconditional_panic)]` on by default error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:28:36 + --> $DIR/issue-8460-const.rs:27:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:30:36 + --> $DIR/issue-8460-const.rs:29:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:32:36 + --> $DIR/issue-8460-const.rs:31:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:34:36 + --> $DIR/issue-8460-const.rs:33:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:36:36 + --> $DIR/issue-8460-const.rs:35:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:38:36 + --> $DIR/issue-8460-const.rs:37:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:40:36 + --> $DIR/issue-8460-const.rs:39:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:42:36 + --> $DIR/issue-8460-const.rs:41:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:44:36 + --> $DIR/issue-8460-const.rs:43:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:46:36 + --> $DIR/issue-8460-const.rs:45:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow - --> $DIR/issue-8460-const.rs:48:36 + --> $DIR/issue-8460-const.rs:47:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:50:36 + --> $DIR/issue-8460-const.rs:49:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:52:36 + --> $DIR/issue-8460-const.rs:51:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:54:36 + --> $DIR/issue-8460-const.rs:53:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:56:36 + --> $DIR/issue-8460-const.rs:55:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:58:36 + --> $DIR/issue-8460-const.rs:57:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime - --> $DIR/issue-8460-const.rs:60:36 + --> $DIR/issue-8460-const.rs:59:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero diff --git a/src/test/ui/issues/issue-8460-const.rs b/src/test/ui/issues/issue-8460-const.rs index 53005e46d2..dc754666c8 100644 --- a/src/test/ui/issues/issue-8460-const.rs +++ b/src/test/ui/issues/issue-8460-const.rs @@ -7,7 +7,6 @@ #![deny(const_err)] -use std::{isize, i8, i16, i32, i64, i128}; use std::thread; fn main() { diff --git a/src/test/ui/iterators/iter-count-overflow-debug.rs b/src/test/ui/iterators/iter-count-overflow-debug.rs index d661203575..5a0394ae76 100644 --- a/src/test/ui/iterators/iter-count-overflow-debug.rs +++ b/src/test/ui/iterators/iter-count-overflow-debug.rs @@ -4,13 +4,12 @@ // compile-flags: -C debug_assertions=yes -C opt-level=3 use std::panic; -use std::usize::MAX; fn main() { - assert_eq!((0..MAX).by_ref().count(), MAX); + assert_eq!((0..usize::MAX).by_ref().count(), usize::MAX); let r = panic::catch_unwind(|| { - (0..=MAX).by_ref().count() + (0..=usize::MAX).by_ref().count() }); assert!(r.is_err()); } diff --git a/src/test/ui/iterators/iter-count-overflow-ndebug.rs b/src/test/ui/iterators/iter-count-overflow-ndebug.rs index b755bb554f..dcaaff671b 100644 --- a/src/test/ui/iterators/iter-count-overflow-ndebug.rs +++ b/src/test/ui/iterators/iter-count-overflow-ndebug.rs @@ -2,10 +2,7 @@ // only-32bit too impatient for 2⁶⁴ items // compile-flags: -C debug_assertions=no -C opt-level=3 -use std::panic; -use std::usize::MAX; - fn main() { - assert_eq!((0..MAX).by_ref().count(), MAX); - assert_eq!((0..=MAX).by_ref().count(), 0); + assert_eq!((0..usize::MAX).by_ref().count(), usize::MAX); + assert_eq!((0..=usize::MAX).by_ref().count(), 0); } diff --git a/src/test/ui/iterators/iter-position-overflow-debug.rs b/src/test/ui/iterators/iter-position-overflow-debug.rs index f1eded3170..733ee0c46c 100644 --- a/src/test/ui/iterators/iter-position-overflow-debug.rs +++ b/src/test/ui/iterators/iter-position-overflow-debug.rs @@ -4,11 +4,10 @@ // compile-flags: -C debug_assertions=yes -C opt-level=3 use std::panic; -use std::usize::MAX; fn main() { - let n = MAX as u64; - assert_eq!((0..).by_ref().position(|i| i >= n), Some(MAX)); + let n = usize::MAX as u64; + assert_eq!((0..).by_ref().position(|i| i >= n), Some(usize::MAX)); let r = panic::catch_unwind(|| { (0..).by_ref().position(|i| i > n) diff --git a/src/test/ui/iterators/iter-position-overflow-ndebug.rs b/src/test/ui/iterators/iter-position-overflow-ndebug.rs index 368f9c0c02..e610c35599 100644 --- a/src/test/ui/iterators/iter-position-overflow-ndebug.rs +++ b/src/test/ui/iterators/iter-position-overflow-ndebug.rs @@ -2,12 +2,9 @@ // only-32bit too impatient for 2⁶⁴ items // compile-flags: -C debug_assertions=no -C opt-level=3 -use std::panic; -use std::usize::MAX; - fn main() { - let n = MAX as u64; - assert_eq!((0..).by_ref().position(|i| i >= n), Some(MAX)); + let n = usize::MAX as u64; + assert_eq!((0..).by_ref().position(|i| i >= n), Some(usize::MAX)); assert_eq!((0..).by_ref().position(|i| i > n), Some(0)); assert_eq!((0..=n + 1).by_ref().position(|_| false), None); } diff --git a/src/test/ui/kinds-of-primitive-impl.rs b/src/test/ui/kinds-of-primitive-impl.rs new file mode 100644 index 0000000000..cbd4d7ae90 --- /dev/null +++ b/src/test/ui/kinds-of-primitive-impl.rs @@ -0,0 +1,23 @@ +// ignore-tidy-linelength + + +impl u8 { +//~^ error: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive + pub const B: u8 = 0; +} + +impl str { +//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive + fn foo() {} + fn bar(self) {} +} + +impl char { +//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive + pub const B: u8 = 0; + pub const C: u8 = 0; + fn foo() {} + fn bar(self) {} +} + +fn main() {} diff --git a/src/test/ui/kinds-of-primitive-impl.stderr b/src/test/ui/kinds-of-primitive-impl.stderr new file mode 100644 index 0000000000..d19c85b17f --- /dev/null +++ b/src/test/ui/kinds-of-primitive-impl.stderr @@ -0,0 +1,40 @@ +error[E0390]: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive + --> $DIR/kinds-of-primitive-impl.rs:4:1 + | +LL | / impl u8 { +LL | | +LL | | pub const B: u8 = 0; +LL | | } + | |_^ + | + = help: consider using a trait to implement this constant + +error[E0390]: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive + --> $DIR/kinds-of-primitive-impl.rs:9:1 + | +LL | / impl str { +LL | | +LL | | fn foo() {} +LL | | fn bar(self) {} +LL | | } + | |_^ + | + = help: consider using a trait to implement these methods + +error[E0390]: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive + --> $DIR/kinds-of-primitive-impl.rs:15:1 + | +LL | / impl char { +LL | | +LL | | pub const B: u8 = 0; +LL | | pub const C: u8 = 0; +LL | | fn foo() {} +LL | | fn bar(self) {} +LL | | } + | |_^ + | + = help: consider using a trait to implement these associated items + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0390`. diff --git a/src/test/ui/label/label_misspelled.rs b/src/test/ui/label/label_misspelled.rs new file mode 100644 index 0000000000..ebfd5642c9 --- /dev/null +++ b/src/test/ui/label/label_misspelled.rs @@ -0,0 +1,18 @@ +fn main() { + 'LOOP: loop { + LOOP; + //~^ ERROR cannot find value `LOOP` in this scope + }; + 'while_loop: while true { //~ WARN denote infinite loops with + while_loop; + //~^ ERROR cannot find value `while_loop` in this scope + }; + 'while_let: while let Some(_) = Some(()) { + while_let; + //~^ ERROR cannot find value `while_let` in this scope + } + 'for_loop: for _ in 0..3 { + for_loop; + //~^ ERROR cannot find value `for_loop` in this scope + }; +} diff --git a/src/test/ui/label/label_misspelled.stderr b/src/test/ui/label/label_misspelled.stderr new file mode 100644 index 0000000000..1368ca4126 --- /dev/null +++ b/src/test/ui/label/label_misspelled.stderr @@ -0,0 +1,47 @@ +error[E0425]: cannot find value `LOOP` in this scope + --> $DIR/label_misspelled.rs:3:9 + | +LL | LOOP; + | ^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'LOOP` + +error[E0425]: cannot find value `while_loop` in this scope + --> $DIR/label_misspelled.rs:7:9 + | +LL | while_loop; + | ^^^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'while_loop` + +error[E0425]: cannot find value `while_let` in this scope + --> $DIR/label_misspelled.rs:11:9 + | +LL | while_let; + | ^^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'while_let` + +error[E0425]: cannot find value `for_loop` in this scope + --> $DIR/label_misspelled.rs:15:9 + | +LL | for_loop; + | ^^^^^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'for_loop` + +warning: denote infinite loops with `loop { ... }` + --> $DIR/label_misspelled.rs:6:5 + | +LL | 'while_loop: while true { + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` + | + = note: `#[warn(while_true)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/layout/big-type-no-err.rs b/src/test/ui/layout/big-type-no-err.rs new file mode 100644 index 0000000000..af8191a9cb --- /dev/null +++ b/src/test/ui/layout/big-type-no-err.rs @@ -0,0 +1,13 @@ +// Enormous types are allowed if they are never actually instantiated. +// run-pass +trait Foo { + type Assoc; +} + +impl Foo for [u16; usize::MAX] { + type Assoc = u32; +} + +fn main() { + let _a: Option<<[u16; usize::MAX] as Foo>::Assoc> = None; +} diff --git a/src/test/ui/lint/dead-code/type-in-foreign.rs b/src/test/ui/lint/dead-code/type-in-foreign.rs new file mode 100644 index 0000000000..b6c593f316 --- /dev/null +++ b/src/test/ui/lint/dead-code/type-in-foreign.rs @@ -0,0 +1,19 @@ +// Verify that we do not warn on types that are used by foreign functions. +// check-pass +#![deny(dead_code)] + +#[repr(C)] +struct Type(u8); + +#[repr(C)] +struct Param(u8); + +extern "C" { + #[allow(dead_code)] + fn hey(t: Param); + + #[allow(dead_code)] + static much: Type; +} + +fn main() {} diff --git a/src/test/ui/lint/expansion-time.rs b/src/test/ui/lint/expansion-time.rs index 6e420c51f0..f23c7cb0dc 100644 --- a/src/test/ui/lint/expansion-time.rs +++ b/src/test/ui/lint/expansion-time.rs @@ -16,6 +16,16 @@ mod benches { fn foo() {} } +#[deprecated = "reason"] +macro_rules! deprecated { + () => {} +} + +#[allow(deprecated)] +mod deprecated { + deprecated!(); // No warning +} + #[warn(incomplete_include)] fn main() { // WARN see in the stderr file, the warning points to the included file. diff --git a/src/test/ui/lint/expansion-time.stderr b/src/test/ui/lint/expansion-time.stderr index e6b5cf67e3..b0fc1f8e5e 100644 --- a/src/test/ui/lint/expansion-time.stderr +++ b/src/test/ui/lint/expansion-time.stderr @@ -47,7 +47,7 @@ LL | 2 | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:19:8 + --> $DIR/expansion-time.rs:29:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/forbid-error-capped.rs b/src/test/ui/lint/forbid-error-capped.rs new file mode 100644 index 0000000000..b56471a756 --- /dev/null +++ b/src/test/ui/lint/forbid-error-capped.rs @@ -0,0 +1,15 @@ +// check-pass +// compile-args: --cap-lints=warn -Fwarnings + +// This checks that the forbid attribute checking is ignored when the forbidden +// lint is capped. + +#![forbid(warnings)] +#![allow(unused)] + +#[allow(unused)] +mod bar { + fn bar() {} +} + +fn main() {} diff --git a/src/test/ui/lint/forbid-group-group-1.rs b/src/test/ui/lint/forbid-group-group-1.rs new file mode 100644 index 0000000000..80f7db4e56 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-1.rs @@ -0,0 +1,13 @@ +// Check what happens when we forbid a smaller group but +// then allow a superset of that group. + +#![forbid(nonstandard_style)] + +// FIXME: Arguably this should be an error, but the WARNINGS group is +// treated in a very special (and rather ad-hoc) way and +// it fails to trigger. +#[allow(warnings)] +fn main() { + let A: (); + //~^ ERROR should have a snake case name +} diff --git a/src/test/ui/lint/forbid-group-group-1.stderr b/src/test/ui/lint/forbid-group-group-1.stderr new file mode 100644 index 0000000000..fd425e5f74 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-1.stderr @@ -0,0 +1,15 @@ +error: variable `A` should have a snake case name + --> $DIR/forbid-group-group-1.rs:11:9 + | +LL | let A: (); + | ^ help: convert the identifier to snake case: `a` + | +note: the lint level is defined here + --> $DIR/forbid-group-group-1.rs:4:11 + | +LL | #![forbid(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: `#[forbid(non_snake_case)]` implied by `#[forbid(nonstandard_style)]` + +error: aborting due to previous error + diff --git a/src/test/ui/lint/forbid-group-group-2.rs b/src/test/ui/lint/forbid-group-group-2.rs new file mode 100644 index 0000000000..b12fd72da7 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-2.rs @@ -0,0 +1,26 @@ +// Check what happens when we forbid a bigger group but +// then deny a subset of that group. + +#![forbid(warnings)] +#![deny(forbidden_lint_groups)] + +#[allow(nonstandard_style)] +//~^ ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +fn main() {} diff --git a/src/test/ui/lint/forbid-group-group-2.stderr b/src/test/ui/lint/forbid-group-group-2.stderr new file mode 100644 index 0000000000..214e949c11 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-2.stderr @@ -0,0 +1,115 @@ +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/forbid-group-group-2.rs:5:9 + | +LL | #![deny(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/lint/forbid-group-member.rs b/src/test/ui/lint/forbid-group-member.rs new file mode 100644 index 0000000000..6f1b2e9f66 --- /dev/null +++ b/src/test/ui/lint/forbid-group-member.rs @@ -0,0 +1,19 @@ +// Check what happens when we forbid a group but +// then allow a member of that group. +// +// check-pass + +#![forbid(unused)] + +#[allow(unused_variables)] +//~^ WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +fn main() { + let a: (); +} diff --git a/src/test/ui/lint/forbid-group-member.stderr b/src/test/ui/lint/forbid-group-member.stderr new file mode 100644 index 0000000000..c818d7ff60 --- /dev/null +++ b/src/test/ui/lint/forbid-group-member.stderr @@ -0,0 +1,51 @@ +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = note: `#[warn(forbidden_lint_groups)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/forbid-member-group.rs b/src/test/ui/lint/forbid-member-group.rs new file mode 100644 index 0000000000..3279029a9c --- /dev/null +++ b/src/test/ui/lint/forbid-member-group.rs @@ -0,0 +1,12 @@ +// Check what happens when we forbid a member of +// a group but then allow the group. + +#![forbid(unused_variables)] + +#[allow(unused)] +//~^ ERROR incompatible with previous forbid +//~| ERROR incompatible with previous forbid +//~| ERROR incompatible with previous forbid +fn main() { + let a: (); +} diff --git a/src/test/ui/lint/forbid-member-group.stderr b/src/test/ui/lint/forbid-member-group.stderr new file mode 100644 index 0000000000..1d8ab4d5ed --- /dev/null +++ b/src/test/ui/lint/forbid-member-group.stderr @@ -0,0 +1,30 @@ +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/inline-trait-and-foreign-items.stderr b/src/test/ui/lint/inline-trait-and-foreign-items.stderr index ae04612a4d..6ac884c12c 100644 --- a/src/test/ui/lint/inline-trait-and-foreign-items.stderr +++ b/src/test/ui/lint/inline-trait-and-foreign-items.stderr @@ -1,19 +1,3 @@ -error[E0518]: attribute should be applied to function or closure - --> $DIR/inline-trait-and-foreign-items.rs:30:5 - | -LL | #[inline] - | ^^^^^^^^^ -LL | static X: u32; - | -------------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/inline-trait-and-foreign-items.rs:33:5 - | -LL | #[inline] - | ^^^^^^^^^ -LL | type T; - | ------- not a function or closure - warning: `#[inline]` is ignored on constants --> $DIR/inline-trait-and-foreign-items.rs:7:5 | @@ -61,6 +45,22 @@ LL | #[inline] LL | type U = impl Trait; | -------------------- not a function or closure +error[E0518]: attribute should be applied to function or closure + --> $DIR/inline-trait-and-foreign-items.rs:30:5 + | +LL | #[inline] + | ^^^^^^^^^ +LL | static X: u32; + | -------------- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/inline-trait-and-foreign-items.rs:33:5 + | +LL | #[inline] + | ^^^^^^^^^ +LL | type T; + | ------- not a function or closure + error: could not find defining uses --> $DIR/inline-trait-and-foreign-items.rs:26:14 | diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs index 0895f4c18e..2560ffe168 100644 --- a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs @@ -3,7 +3,7 @@ // compile-flags: -Zmir-opt-level=0 fn main() { - Bug::V([0; !0]); //~ ERROR is too big for the current + Bug::V([0; !0]); //~ ERROR are too big for the current } enum Bug { diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr index 51eac95afb..c229458da4 100644 --- a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr @@ -1,4 +1,4 @@ -error: the type `[u8; 18446744073709551615]` is too big for the current architecture +error: values of the type `[u8; 18446744073709551615]` are too big for the current architecture --> $DIR/issue-69485-var-size-diffs-too-large.rs:6:12 | LL | Bug::V([0; !0]); diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs new file mode 100644 index 0000000000..05d7d924c8 --- /dev/null +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs @@ -0,0 +1,52 @@ +// This test is checking that you cannot override a `forbid` by adding in other +// attributes later in the same scope. (We already ensure that you cannot +// override it in nested scopes). + +// If you turn off deduplicate diagnostics (which rustc turns on by default but +// compiletest turns off when it runs ui tests), then the errors are +// (unfortunately) repeated here because the checking is done as we read in the +// errors, and curretly that happens two or three different times, depending on +// compiler flags. +// +// I decided avoiding the redundant output was not worth the time in engineering +// effort for bug like this, which 1. end users are unlikely to run into in the +// first place, and 2. they won't see the redundant output anyway. + +// compile-flags: -Z deduplicate-diagnostics=yes + +#![forbid(forbidden_lint_groups)] + +fn forbid_first(num: i32) -> i32 { + #![forbid(unused)] + #![deny(unused)] + //~^ ERROR: deny(unused) incompatible with previous forbid + //~| WARNING being phased out + //~| ERROR: deny(unused) incompatible with previous forbid + //~| WARNING being phased out + #![warn(unused)] + #![allow(unused)] + + num * num +} + +fn forbid_last(num: i32) -> i32 { + #![deny(unused)] + #![warn(unused)] + #![allow(unused)] + #![forbid(unused)] + + num * num +} + +fn forbid_multiple(num: i32) -> i32 { + #![forbid(unused)] + #![forbid(unused)] + + num * num +} + +fn main() { + forbid_first(10); + forbid_last(10); + forbid_multiple(10); +} diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr new file mode 100644 index 0000000000..475410cecf --- /dev/null +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr @@ -0,0 +1,29 @@ +error: deny(unused) incompatible with previous forbid + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | #![deny(unused)] + | ^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:17:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: deny(unused) incompatible with previous forbid + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | #![deny(unused)] + | ^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint/issue-80988.rs b/src/test/ui/lint/issue-80988.rs new file mode 100644 index 0000000000..16a041928d --- /dev/null +++ b/src/test/ui/lint/issue-80988.rs @@ -0,0 +1,16 @@ +// Regression test for #80988 +// +// check-pass + +#![forbid(warnings)] + +#[deny(warnings)] +//~^ WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +fn main() {} diff --git a/src/test/ui/lint/issue-80988.stderr b/src/test/ui/lint/issue-80988.stderr new file mode 100644 index 0000000000..4cae11f97c --- /dev/null +++ b/src/test/ui/lint/issue-80988.stderr @@ -0,0 +1,51 @@ +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = note: `#[warn(forbidden_lint_groups)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/issue-81218.rs b/src/test/ui/lint/issue-81218.rs new file mode 100644 index 0000000000..f02aa9040e --- /dev/null +++ b/src/test/ui/lint/issue-81218.rs @@ -0,0 +1,14 @@ +// Regression test for #81218 +// +// check-pass + +#![forbid(warnings)] + +#[allow(unused_variables)] +fn main() { + // We want to ensure that you don't get an error + // here. The idea is that a derive might generate + // code that would otherwise trigger the "unused variables" + // lint, but it is meant to be suppressed. + let x: (); +} diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs index ef55f31593..4bf5e0a9e2 100644 --- a/src/test/ui/lint/lint-const-item-mutation.rs +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -30,6 +30,8 @@ const MUTABLE: Mutable = Mutable { msg: "" }; const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; const VEC: Vec = Vec::new(); const PTR: *mut () = 1 as *mut _; +const PTR_TO_ARRAY: *mut [u32; 4] = 0x12345678 as _; +const ARRAY_OF_PTR: [*mut u32; 1] = [1 as *mut _]; fn main() { ARRAY[0] = 5; //~ WARN attempting to modify @@ -55,4 +57,10 @@ fn main() { // Test that we don't warn when converting a raw pointer // into a mutable reference unsafe { &mut *PTR }; + + // Test that we don't warn when there's a dereference involved. + // If we ever 'leave' the const via a deference, we're going + // to end up modifying something other than the temporary + unsafe { (*PTR_TO_ARRAY)[0] = 1 }; + unsafe { *ARRAY_OF_PTR[0] = 25; } } diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index ae95abc72f..74505eeb98 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -1,5 +1,5 @@ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:35:5 + --> $DIR/lint-const-item-mutation.rs:37:5 | LL | ARRAY[0] = 5; | ^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | const ARRAY: [u8; 1] = [25]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:36:5 + --> $DIR/lint-const-item-mutation.rs:38:5 | LL | MY_STRUCT.field = false; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:37:5 + --> $DIR/lint-const-item-mutation.rs:39:5 | LL | MY_STRUCT.inner_array[0] = 'b'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:38:5 + --> $DIR/lint-const-item-mutation.rs:40:5 | LL | MY_STRUCT.use_mut(); | ^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:39:5 + --> $DIR/lint-const-item-mutation.rs:41:5 | LL | &mut MY_STRUCT; | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:40:5 + --> $DIR/lint-const-item-mutation.rs:42:5 | LL | (&mut MY_STRUCT).use_mut(); | ^^^^^^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:52:5 + --> $DIR/lint-const-item-mutation.rs:54:5 | LL | MUTABLE2.msg = "wow"; | ^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:53:5 + --> $DIR/lint-const-item-mutation.rs:55:5 | LL | VEC.push(0); | ^^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-forbid-attr.rs b/src/test/ui/lint/lint-forbid-attr.rs index 13b28e8830..13ebb6dccd 100644 --- a/src/test/ui/lint/lint-forbid-attr.rs +++ b/src/test/ui/lint/lint-forbid-attr.rs @@ -1,8 +1,8 @@ #![forbid(deprecated)] #[allow(deprecated)] -//~^ ERROR allow(deprecated) overruled by outer forbid(deprecated) -//~| ERROR allow(deprecated) overruled by outer forbid(deprecated) -//~| ERROR allow(deprecated) overruled by outer forbid(deprecated) +//~^ ERROR allow(deprecated) incompatible +//~| ERROR allow(deprecated) incompatible +//~| ERROR allow(deprecated) incompatible fn main() { } diff --git a/src/test/ui/lint/lint-forbid-attr.stderr b/src/test/ui/lint/lint-forbid-attr.stderr index bf138c317e..cb0b25d111 100644 --- a/src/test/ui/lint/lint-forbid-attr.stderr +++ b/src/test/ui/lint/lint-forbid-attr.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-attr.rs:3:9 | LL | #![forbid(deprecated)] @@ -7,7 +7,7 @@ LL | LL | #[allow(deprecated)] | ^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-attr.rs:3:9 | LL | #![forbid(deprecated)] @@ -16,7 +16,7 @@ LL | LL | #[allow(deprecated)] | ^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-attr.rs:3:9 | LL | #![forbid(deprecated)] diff --git a/src/test/ui/lint/lint-forbid-cmdline.rs b/src/test/ui/lint/lint-forbid-cmdline.rs index 821470c868..38bb8d29d3 100644 --- a/src/test/ui/lint/lint-forbid-cmdline.rs +++ b/src/test/ui/lint/lint-forbid-cmdline.rs @@ -1,7 +1,7 @@ // compile-flags: -F deprecated -#[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated) - //~| ERROR allow(deprecated) overruled by outer forbid(deprecated) - //~| ERROR allow(deprecated) overruled by outer forbid(deprecated) +#[allow(deprecated)] //~ ERROR allow(deprecated) incompatible + //~| ERROR allow(deprecated) incompatible + //~| ERROR allow(deprecated) incompatible fn main() { } diff --git a/src/test/ui/lint/lint-forbid-cmdline.stderr b/src/test/ui/lint/lint-forbid-cmdline.stderr index 89a4445d80..5b1b015c4d 100644 --- a/src/test/ui/lint/lint-forbid-cmdline.stderr +++ b/src/test/ui/lint/lint-forbid-cmdline.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-cmdline.rs:3:9 | LL | #[allow(deprecated)] @@ -6,7 +6,7 @@ LL | #[allow(deprecated)] | = note: `forbid` lint level was set on command line -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-cmdline.rs:3:9 | LL | #[allow(deprecated)] @@ -14,7 +14,7 @@ LL | #[allow(deprecated)] | = note: `forbid` lint level was set on command line -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-cmdline.rs:3:9 | LL | #[allow(deprecated)] diff --git a/src/test/ui/lint/outer-forbid.rs b/src/test/ui/lint/outer-forbid.rs index 2a38565f60..486ec3c468 100644 --- a/src/test/ui/lint/outer-forbid.rs +++ b/src/test/ui/lint/outer-forbid.rs @@ -4,21 +4,30 @@ // subsequent allowance of a lint group containing it (here, `nonstandard_style`). See // Issue #42873. +// If you turn off deduplicate diagnostics (which rustc turns on by default but +// compiletest turns off when it runs ui tests), then the errors are +// (unfortunately) repeated here because the checking is done as we read in the +// errors, and currently that happens two or three different times, depending on +// compiler flags. +// +// The test is much cleaner if we deduplicate, though. + +// compile-flags: -Z deduplicate-diagnostics=yes + #![forbid(unused, non_snake_case)] +#![forbid(forbidden_lint_groups)] -#[allow(unused_variables)] //~ ERROR overruled - //~| ERROR overruled - //~| ERROR overruled +#[allow(unused_variables)] //~ ERROR incompatible with previous +//~^ ERROR incompatible with previous +//~| WARNING this was previously accepted by the compiler +//~| WARNING this was previously accepted by the compiler fn foo() {} -#[allow(unused)] //~ ERROR overruled - //~| ERROR overruled - //~| ERROR overruled +#[allow(unused)] //~ ERROR incompatible with previous +//~^ WARNING this was previously accepted by the compiler fn bar() {} -#[allow(nonstandard_style)] //~ ERROR overruled - //~| ERROR overruled - //~| ERROR overruled +#[allow(nonstandard_style)] //~ ERROR incompatible with previous fn main() { println!("hello forbidden world") } diff --git a/src/test/ui/lint/outer-forbid.stderr b/src/test/ui/lint/outer-forbid.stderr index b2e638e7af..d69157a8bb 100644 --- a/src/test/ui/lint/outer-forbid.stderr +++ b/src/test/ui/lint/outer-forbid.stderr @@ -1,50 +1,34 @@ -error[E0453]: allow(unused_variables) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:9:9 +error: allow(unused_variables) incompatible with previous forbid + --> $DIR/outer-forbid.rs:20:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here -LL | +... LL | #[allow(unused_variables)] | ^^^^^^^^^^^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:14:9 | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -... -LL | #[allow(unused)] - | ^^^^^^ overruled by previous forbid - -error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) - --> $DIR/outer-forbid.rs:19:9 +note: the lint level is defined here + --> $DIR/outer-forbid.rs:18:11 | -LL | #![forbid(unused, non_snake_case)] - | -------------- `forbid` level set here -... -LL | #[allow(nonstandard_style)] - | ^^^^^^^^^^^^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused_variables) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:9:9 - | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -LL | -LL | #[allow(unused_variables)] - | ^^^^^^^^^^^^^^^^ overruled by previous forbid +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error[E0453]: allow(unused) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:14:9 +error: allow(unused) incompatible with previous forbid + --> $DIR/outer-forbid.rs:26:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here ... LL | #[allow(unused)] | ^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) - --> $DIR/outer-forbid.rs:19:9 +error[E0453]: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/outer-forbid.rs:30:9 | LL | #![forbid(unused, non_snake_case)] | -------------- `forbid` level set here @@ -52,33 +36,18 @@ LL | #![forbid(unused, non_snake_case)] LL | #[allow(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(unused_variables) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:9:9 +error: allow(unused_variables) incompatible with previous forbid + --> $DIR/outer-forbid.rs:20:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here -LL | +... LL | #[allow(unused_variables)] | ^^^^^^^^^^^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:14:9 | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -... -LL | #[allow(unused)] - | ^^^^^^ overruled by previous forbid - -error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) - --> $DIR/outer-forbid.rs:19:9 - | -LL | #![forbid(unused, non_snake_case)] - | -------------- `forbid` level set here -... -LL | #[allow(nonstandard_style)] - | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error: aborting due to 9 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/reasons-forbidden.rs b/src/test/ui/lint/reasons-forbidden.rs index 5f6764c789..9c2edec4d5 100644 --- a/src/test/ui/lint/reasons-forbidden.rs +++ b/src/test/ui/lint/reasons-forbidden.rs @@ -1,13 +1,19 @@ #![feature(lint_reasons)] +// If you turn off deduplicate diagnostics (which rustc turns on by default but +// compiletest turns off when it runs ui tests), then the errors are +// (unfortunately) repeated here because the checking is done as we read in the +// errors, and currently that happens two or three different times, depending on +// compiler flags. +// +// The test is much cleaner if we deduplicate, though. + +// compile-flags: -Z deduplicate-diagnostics=yes + #![forbid( unsafe_code, //~^ NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here + //~| NOTE the lint level is defined here reason = "our errors & omissions insurance policy doesn't cover unsafe Rust" )] @@ -17,25 +23,12 @@ fn main() { let a_billion_dollar_mistake = ptr::null(); #[allow(unsafe_code)] - //~^ ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~^ ERROR allow(unsafe_code) incompatible with previous forbid //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~| NOTE overruled by previous forbid unsafe { + //~^ ERROR usage of an `unsafe` block + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust *a_billion_dollar_mistake } } diff --git a/src/test/ui/lint/reasons-forbidden.stderr b/src/test/ui/lint/reasons-forbidden.stderr index eed9c8d566..ab6f19a019 100644 --- a/src/test/ui/lint/reasons-forbidden.stderr +++ b/src/test/ui/lint/reasons-forbidden.stderr @@ -1,5 +1,5 @@ -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 +error[E0453]: allow(unsafe_code) incompatible with previous forbid + --> $DIR/reasons-forbidden.rs:25:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -9,61 +9,23 @@ LL | #[allow(unsafe_code)] | = note: our errors & omissions insurance policy doesn't cover unsafe Rust -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 +error: usage of an `unsafe` block + --> $DIR/reasons-forbidden.rs:29:5 | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 - | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid +LL | / unsafe { +LL | | +LL | | +LL | | *a_billion_dollar_mistake +LL | | } + | |_____^ | = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 +note: the lint level is defined here + --> $DIR/reasons-forbidden.rs:14:5 | LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 - | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 - | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust + | ^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs b/src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs new file mode 100644 index 0000000000..4592bc31a3 --- /dev/null +++ b/src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs @@ -0,0 +1,10 @@ +// check-pass +// This test should stop compiling +// we decide to enable this lint for item statements. + +#![deny(redundant_semicolons)] + +fn main() { + fn inner() {}; + struct Bar {}; +} diff --git a/src/test/ui/lint/special-upper-lower-cases.rs b/src/test/ui/lint/special-upper-lower-cases.rs new file mode 100644 index 0000000000..71ebf05dd3 --- /dev/null +++ b/src/test/ui/lint/special-upper-lower-cases.rs @@ -0,0 +1,24 @@ +// (#77273) These characters are in the general categories of +// "Uppercase/Lowercase Letter". +// The diagnostics don't provide meaningful suggestions for them +// as we cannot convert them properly. + +// check-pass + +#![feature(non_ascii_idents)] +#![allow(uncommon_codepoints, unused)] + +struct 𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝; +//~^ WARN: type `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name + +// FIXME: How we should handle this? +struct 𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝; +//~^ WARN: type `𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name + +static 𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲: i32 = 1; +//~^ WARN: static variable `𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲` should have an upper case name + +fn main() { + let 𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢 = 1; + //~^ WARN: variable `𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢` should have a snake case name +} diff --git a/src/test/ui/lint/special-upper-lower-cases.stderr b/src/test/ui/lint/special-upper-lower-cases.stderr new file mode 100644 index 0000000000..f32193a2e4 --- /dev/null +++ b/src/test/ui/lint/special-upper-lower-cases.stderr @@ -0,0 +1,32 @@ +warning: type `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name + --> $DIR/special-upper-lower-cases.rs:11:8 + | +LL | struct 𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝; + | ^^^^^^^^^ + | + = note: `#[warn(non_camel_case_types)]` on by default + +warning: type `𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name + --> $DIR/special-upper-lower-cases.rs:15:8 + | +LL | struct 𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝; + | ^^^^^^^^^^^ help: convert the identifier to upper camel case: `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` + +warning: static variable `𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲` should have an upper case name + --> $DIR/special-upper-lower-cases.rs:18:8 + | +LL | static 𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲: i32 = 1; + | ^^^^^^^^^^^^ + | + = note: `#[warn(non_upper_case_globals)]` on by default + +warning: variable `𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢` should have a snake case name + --> $DIR/special-upper-lower-cases.rs:22:9 + | +LL | let 𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢 = 1; + | ^^^^^^^^^ + | + = note: `#[warn(non_snake_case)]` on by default + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/unused_labels.stderr b/src/test/ui/lint/unused_labels.stderr index 443faebd0f..4bb1a437d2 100644 --- a/src/test/ui/lint/unused_labels.stderr +++ b/src/test/ui/lint/unused_labels.stderr @@ -59,7 +59,7 @@ LL | 'many_used_shadowed: for _ in 0..10 { | ------------------- first declared here LL | LL | 'many_used_shadowed: for _ in 0..10 { - | ^^^^^^^^^^^^^^^^^^^ lifetime 'many_used_shadowed already in scope + | ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope warning: 9 warnings emitted diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs index d7efa4aac6..7d641e08bf 100644 --- a/src/test/ui/lint/use_suggestion_json.rs +++ b/src/test/ui/lint/use_suggestion_json.rs @@ -1,4 +1,3 @@ -// ignore-cloudabi // ignore-windows // ignore-sgx std::os::fortanix_sgx::usercalls::alloc::Iter changes compiler suggestions // compile-flags: --error-format pretty-json --json=diagnostic-rendered-ansi diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index d0d91bb61f..21342e2ef3 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -72,10 +72,10 @@ mod foo { "spans": [ { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 560, - "byte_end": 564, - "line_start": 13, - "line_end": 13, + "byte_start": 541, + "byte_end": 545, + "line_start": 12, + "line_end": 12, "column_start": 12, "column_end": 16, "is_primary": true, @@ -100,10 +100,10 @@ mod foo { "spans": [ { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -123,10 +123,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -146,10 +146,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -169,10 +169,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -192,10 +192,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -215,10 +215,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -238,10 +238,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -261,10 +261,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -284,10 +284,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -307,10 +307,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -330,10 +330,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -353,10 +353,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 537, - "byte_end": 537, - "line_start": 12, - "line_end": 12, + "byte_start": 518, + "byte_end": 518, + "line_start": 11, + "line_end": 11, "column_start": 1, "column_end": 1, "is_primary": true, @@ -380,7 +380,7 @@ mod foo { } ], "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:13:12\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m let x: Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m diff --git a/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr b/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr index 843db8ce81..ab19d80e73 100644 --- a/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr +++ b/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr @@ -1,5 +1,5 @@ error: `#[inline]` is ignored on function prototypes - --> $DIR/warn-unused-inline-on-fn-prototypes.rs:9:5 + --> $DIR/warn-unused-inline-on-fn-prototypes.rs:4:5 | LL | #[inline] | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: `#[inline]` is ignored on function prototypes - --> $DIR/warn-unused-inline-on-fn-prototypes.rs:4:5 + --> $DIR/warn-unused-inline-on-fn-prototypes.rs:9:5 | LL | #[inline] | ^^^^^^^^^ diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs index 6c4160c36a..8a080cfdf4 100644 --- a/src/test/ui/loops/loop-break-value.rs +++ b/src/test/ui/loops/loop-break-value.rs @@ -90,4 +90,10 @@ fn main() { break; //~ ERROR mismatched types break 4; }; + + 'LOOP: for _ in 0 .. 9 { + break LOOP; + //~^ ERROR cannot find value `LOOP` in this scope + //~| ERROR `break` with value from a `for` loop + } } diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr index 0503d3d4c7..0237435c8b 100644 --- a/src/test/ui/loops/loop-break-value.stderr +++ b/src/test/ui/loops/loop-break-value.stderr @@ -1,3 +1,12 @@ +error[E0425]: cannot find value `LOOP` in this scope + --> $DIR/loop-break-value.rs:95:15 + | +LL | break LOOP; + | ^^^^ + | | + | not found in this scope + | help: a label with a similar name exists: `'LOOP` + warning: denote infinite loops with `loop { ... }` --> $DIR/loop-break-value.rs:26:5 | @@ -94,6 +103,17 @@ help: instead, use `break` on its own without a value inside this `for` loop LL | break; | ^^^^^ +error[E0571]: `break` with value from a `for` loop + --> $DIR/loop-break-value.rs:95:9 + | +LL | break LOOP; + | ^^^^^^^^^^ can only break with a value inside `loop` or breakable block + | +help: instead, use `break` on its own without a value inside this `for` loop + | +LL | break; + | ^^^^^ + error[E0308]: mismatched types --> $DIR/loop-break-value.rs:4:31 | @@ -151,7 +171,7 @@ LL | break; | expected integer, found `()` | help: give it a value of the expected type: `break value` -error: aborting due to 16 previous errors; 1 warning emitted +error: aborting due to 18 previous errors; 1 warning emitted -Some errors have detailed explanations: E0308, E0571. +Some errors have detailed explanations: E0308, E0425, E0571. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr index 3c8e2938d4..724c36e520 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr @@ -4,7 +4,7 @@ warning: label name `'fl` shadows a label name that is already in scope LL | { 'fl: for _ in 0..10 { break; } } | --- first declared here LL | { 'fl: loop { break; } } - | ^^^ lifetime 'fl already in scope + | ^^^ label `'fl` already in scope warning: label name `'lf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:16:7 @@ -12,7 +12,7 @@ warning: label name `'lf` shadows a label name that is already in scope LL | { 'lf: loop { break; } } | --- first declared here LL | { 'lf: for _ in 0..10 { break; } } - | ^^^ lifetime 'lf already in scope + | ^^^ label `'lf` already in scope warning: label name `'wl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:18:7 @@ -20,7 +20,7 @@ warning: label name `'wl` shadows a label name that is already in scope LL | { 'wl: while 2 > 1 { break; } } | --- first declared here LL | { 'wl: loop { break; } } - | ^^^ lifetime 'wl already in scope + | ^^^ label `'wl` already in scope warning: label name `'lw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:20:7 @@ -28,7 +28,7 @@ warning: label name `'lw` shadows a label name that is already in scope LL | { 'lw: loop { break; } } | --- first declared here LL | { 'lw: while 2 > 1 { break; } } - | ^^^ lifetime 'lw already in scope + | ^^^ label `'lw` already in scope warning: label name `'fw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:22:7 @@ -36,7 +36,7 @@ warning: label name `'fw` shadows a label name that is already in scope LL | { 'fw: for _ in 0..10 { break; } } | --- first declared here LL | { 'fw: while 2 > 1 { break; } } - | ^^^ lifetime 'fw already in scope + | ^^^ label `'fw` already in scope warning: label name `'wf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:24:7 @@ -44,7 +44,7 @@ warning: label name `'wf` shadows a label name that is already in scope LL | { 'wf: while 2 > 1 { break; } } | --- first declared here LL | { 'wf: for _ in 0..10 { break; } } - | ^^^ lifetime 'wf already in scope + | ^^^ label `'wf` already in scope warning: label name `'tl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:26:7 @@ -52,7 +52,7 @@ warning: label name `'tl` shadows a label name that is already in scope LL | { 'tl: while let Some(_) = None:: { break; } } | --- first declared here LL | { 'tl: loop { break; } } - | ^^^ lifetime 'tl already in scope + | ^^^ label `'tl` already in scope warning: label name `'lt` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:28:7 @@ -60,7 +60,7 @@ warning: label name `'lt` shadows a label name that is already in scope LL | { 'lt: loop { break; } } | --- first declared here LL | { 'lt: while let Some(_) = None:: { break; } } - | ^^^ lifetime 'lt already in scope + | ^^^ label `'lt` already in scope warning: 8 warnings emitted diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.stderr b/src/test/ui/loops/loops-reject-duplicate-labels.stderr index 5a3e5158fe..2d11281201 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels.stderr @@ -4,7 +4,7 @@ warning: label name `'fl` shadows a label name that is already in scope LL | 'fl: for _ in 0..10 { break; } | --- first declared here LL | 'fl: loop { break; } - | ^^^ lifetime 'fl already in scope + | ^^^ label `'fl` already in scope warning: label name `'lf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:14:5 @@ -12,7 +12,7 @@ warning: label name `'lf` shadows a label name that is already in scope LL | 'lf: loop { break; } | --- first declared here LL | 'lf: for _ in 0..10 { break; } - | ^^^ lifetime 'lf already in scope + | ^^^ label `'lf` already in scope warning: label name `'wl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:16:5 @@ -20,7 +20,7 @@ warning: label name `'wl` shadows a label name that is already in scope LL | 'wl: while 2 > 1 { break; } | --- first declared here LL | 'wl: loop { break; } - | ^^^ lifetime 'wl already in scope + | ^^^ label `'wl` already in scope warning: label name `'lw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:18:5 @@ -28,7 +28,7 @@ warning: label name `'lw` shadows a label name that is already in scope LL | 'lw: loop { break; } | --- first declared here LL | 'lw: while 2 > 1 { break; } - | ^^^ lifetime 'lw already in scope + | ^^^ label `'lw` already in scope warning: label name `'fw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:20:5 @@ -36,7 +36,7 @@ warning: label name `'fw` shadows a label name that is already in scope LL | 'fw: for _ in 0..10 { break; } | --- first declared here LL | 'fw: while 2 > 1 { break; } - | ^^^ lifetime 'fw already in scope + | ^^^ label `'fw` already in scope warning: label name `'wf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:22:5 @@ -44,7 +44,7 @@ warning: label name `'wf` shadows a label name that is already in scope LL | 'wf: while 2 > 1 { break; } | --- first declared here LL | 'wf: for _ in 0..10 { break; } - | ^^^ lifetime 'wf already in scope + | ^^^ label `'wf` already in scope warning: label name `'tl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:24:5 @@ -52,7 +52,7 @@ warning: label name `'tl` shadows a label name that is already in scope LL | 'tl: while let Some(_) = None:: { break; } | --- first declared here LL | 'tl: loop { break; } - | ^^^ lifetime 'tl already in scope + | ^^^ label `'tl` already in scope warning: label name `'lt` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:26:5 @@ -60,7 +60,7 @@ warning: label name `'lt` shadows a label name that is already in scope LL | 'lt: loop { break; } | --- first declared here LL | 'lt: while let Some(_) = None:: { break; } - | ^^^ lifetime 'lt already in scope + | ^^^ label `'lt` already in scope warning: 8 warnings emitted diff --git a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr index c27e61190b..0d96c0b3a3 100644 --- a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr +++ b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr @@ -4,7 +4,7 @@ warning: label name `'a` shadows a lifetime name that is already in scope LL | fn foo<'a>() { | -- first declared here LL | 'a: loop { break 'a; } - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:35:13 @@ -13,7 +13,7 @@ LL | impl<'bad, 'c> Struct<'bad, 'c> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:42:13 @@ -22,7 +22,7 @@ LL | impl<'b, 'bad> Struct<'b, 'bad> { | ---- first declared here LL | fn meth_bad2(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:49:13 @@ -30,7 +30,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad3<'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:54:13 @@ -38,7 +38,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:61:13 @@ -47,7 +47,7 @@ LL | impl <'bad, 'e> Enum<'bad, 'e> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:67:13 @@ -56,7 +56,7 @@ LL | impl <'d, 'bad> Enum<'d, 'bad> { | ---- first declared here LL | fn meth_bad2(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:73:13 @@ -64,7 +64,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad3<'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:78:13 @@ -72,7 +72,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad4<'a,'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:88:13 @@ -81,7 +81,7 @@ LL | trait HasDefaultMethod1<'bad> { | ---- first declared here ... LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:94:13 @@ -90,7 +90,7 @@ LL | trait HasDefaultMethod2<'a,'bad> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:100:13 @@ -98,7 +98,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad<'bad>(&self) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: 12 warnings emitted diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr index b31ef273fc..dcee1a8009 100644 --- a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr +++ b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr @@ -4,7 +4,7 @@ warning: lifetime name `'a` shadows a label name that is already in scope LL | 'a: loop { | -- first declared here LL | let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; - | ^^ lifetime 'a already in scope + | ^^ label `'a` already in scope warning: 1 warning emitted diff --git a/src/test/ui/macros/issue-78333.rs b/src/test/ui/macros/issue-78333.rs new file mode 100644 index 0000000000..c376f20670 --- /dev/null +++ b/src/test/ui/macros/issue-78333.rs @@ -0,0 +1,13 @@ +// build-pass + +#![no_implicit_prelude] + +fn main() { + ::std::panic!(); + ::std::todo!(); + ::std::unimplemented!(); + ::std::assert_eq!(0, 0); + ::std::assert_ne!(0, 1); + ::std::dbg!(123); + ::std::unreachable!(); +} diff --git a/src/test/ui/macros/macro-2.rs b/src/test/ui/macros/macro-2.rs index 4890c991dc..a315981b6a 100644 --- a/src/test/ui/macros/macro-2.rs +++ b/src/test/ui/macros/macro-2.rs @@ -3,7 +3,7 @@ pub fn main() { macro_rules! mylambda_tt { ($x:ident, $body:expr) => ({ - fn f($x: isize) -> isize { return $body; }; + fn f($x: isize) -> isize { return $body; } f }) } diff --git a/src/test/ui/macros/macro-attribute.rs b/src/test/ui/macros/macro-attribute.rs index f580dfa8e3..88834a9672 100644 --- a/src/test/ui/macros/macro-attribute.rs +++ b/src/test/ui/macros/macro-attribute.rs @@ -1,2 +1,2 @@ -#[doc = $not_there] //~ ERROR unexpected token: `$` +#[doc = $not_there] //~ ERROR expected expression, found `$` fn main() { } diff --git a/src/test/ui/macros/macro-attribute.stderr b/src/test/ui/macros/macro-attribute.stderr index d28ce25341..3316d38726 100644 --- a/src/test/ui/macros/macro-attribute.stderr +++ b/src/test/ui/macros/macro-attribute.stderr @@ -1,8 +1,8 @@ -error: unexpected token: `$` +error: expected expression, found `$` --> $DIR/macro-attribute.rs:1:9 | LL | #[doc = $not_there] - | ^ + | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/macros/macro-comma-behavior-rpass.rs b/src/test/ui/macros/macro-comma-behavior-rpass.rs index 32cf59294e..e814e07564 100644 --- a/src/test/ui/macros/macro-comma-behavior-rpass.rs +++ b/src/test/ui/macros/macro-comma-behavior-rpass.rs @@ -57,6 +57,7 @@ fn writeln_1arg() { // // (Example: Issue #48042) #[test] +#[allow(non_fmt_panic)] fn to_format_or_not_to_format() { // ("{}" is the easiest string to test because if this gets // sent to format_args!, it'll simply fail to compile. diff --git a/src/test/ui/macros/macro-first-set.rs b/src/test/ui/macros/macro-first-set.rs index eb2504d4bf..f85376dabc 100644 --- a/src/test/ui/macros/macro-first-set.rs +++ b/src/test/ui/macros/macro-first-set.rs @@ -249,7 +249,7 @@ macro_rules! test_path { test_path!(); test_path!(,); test_path!(::std); -test_path!(std::u8,); +test_path!(std::ops,); test_path!(any, super, super::super::self::path, X::Z<'a, T=U>); macro_rules! test_lifetime { diff --git a/src/test/ui/macros/macro-lifetime-used-with-labels.stderr b/src/test/ui/macros/macro-lifetime-used-with-labels.stderr index 98ee85d908..68f885e9e4 100644 --- a/src/test/ui/macros/macro-lifetime-used-with-labels.stderr +++ b/src/test/ui/macros/macro-lifetime-used-with-labels.stderr @@ -2,7 +2,7 @@ warning: label name `'b` shadows a label name that is already in scope --> $DIR/macro-lifetime-used-with-labels.rs:21:9 | LL | 'b: loop { - | ^^ lifetime 'b already in scope + | ^^ label `'b` already in scope ... LL | 'b: loop { | -- first declared here diff --git a/src/test/ui/macros/macro-pat-follow-2018.rs b/src/test/ui/macros/macro-pat-follow-2018.rs new file mode 100644 index 0000000000..ce2911de98 --- /dev/null +++ b/src/test/ui/macros/macro-pat-follow-2018.rs @@ -0,0 +1,15 @@ +// run-pass +// edition:2018 + +macro_rules! pat_bar { + ($p:pat | $p2:pat) => {{ + match Some(1u8) { + $p | $p2 => {} + _ => {} + } + }}; +} + +fn main() { + pat_bar!(Some(1u8) | None); +} diff --git a/src/test/ui/macros/macro-pat-follow.rs b/src/test/ui/macros/macro-pat-follow.rs index 8673cf7946..8e02789fdd 100644 --- a/src/test/ui/macros/macro-pat-follow.rs +++ b/src/test/ui/macros/macro-pat-follow.rs @@ -3,29 +3,19 @@ macro_rules! pat_in { ($p:pat in $e:expr) => {{ let mut iter = $e.into_iter(); while let $p = iter.next() {} - }} + }}; } macro_rules! pat_if { ($p:pat if $e:expr) => {{ match Some(1u8) { - $p if $e => {}, + $p if $e => {} _ => {} } - }} -} - -macro_rules! pat_bar { - ($p:pat | $p2:pat) => {{ - match Some(1u8) { - $p | $p2 => {}, - _ => {} - } - }} + }}; } fn main() { pat_in!(Some(_) in 0..10); pat_if!(Some(x) if x > 0); - pat_bar!(Some(1u8) | None); } diff --git a/src/test/ui/macros/macro-path.rs b/src/test/ui/macros/macro-path.rs index be59d8d139..6c011c897d 100644 --- a/src/test/ui/macros/macro-path.rs +++ b/src/test/ui/macros/macro-path.rs @@ -8,7 +8,7 @@ mod m { macro_rules! foo { ($p:path) => ({ - fn f() -> $p { 10 }; + fn f() -> $p { 10 } f() }) } diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs index 24692f7cf5..1fd7cddc7c 100644 --- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs +++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs @@ -4,7 +4,6 @@ struct CLI { #[derive(parse())] //~^ ERROR traits in `#[derive(...)]` don't accept arguments //~| ERROR cannot find derive macro `parse` in this scope - //~| ERROR cannot find derive macro `parse` in this scope path: (), //~^ ERROR `derive` may only be applied to structs, enums and unions } diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr index c4532a375a..db40ce0753 100644 --- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr +++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr @@ -5,7 +5,7 @@ LL | #[derive(parse())] | ^^ help: remove the arguments error[E0774]: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-69341-malformed-derive-inert.rs:8:5 + --> $DIR/issue-69341-malformed-derive-inert.rs:7:5 | LL | path: (), | ^^^^^^^^ @@ -16,12 +16,6 @@ error: cannot find derive macro `parse` in this scope LL | #[derive(parse())] | ^^^^^ -error: cannot find derive macro `parse` in this scope - --> $DIR/issue-69341-malformed-derive-inert.rs:4:14 - | -LL | #[derive(parse())] - | ^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/malformed/malformed-interpolated.rs b/src/test/ui/malformed/malformed-interpolated.rs index 5101b5caee..b962447e7e 100644 --- a/src/test/ui/malformed/malformed-interpolated.rs +++ b/src/test/ui/malformed/malformed-interpolated.rs @@ -2,8 +2,7 @@ macro_rules! check { ($expr: expr) => ( - #[rustc_dummy = $expr] //~ ERROR unexpected token: `-0` - //~| ERROR unexpected token: `0 + 0` + #[rustc_dummy = $expr] use main as _; ); } @@ -11,7 +10,7 @@ macro_rules! check { check!("0"); // OK check!(0); // OK check!(0u8); //~ ERROR suffixed literals are not allowed in attributes -check!(-0); // ERROR, see above -check!(0 + 0); // ERROR, see above +check!(-0); //~ ERROR unexpected token: `-0` +check!(0 + 0); //~ ERROR unexpected token: `0 + 0` fn main() {} diff --git a/src/test/ui/malformed/malformed-interpolated.stderr b/src/test/ui/malformed/malformed-interpolated.stderr index d1be82cf7b..4b9332ddd0 100644 --- a/src/test/ui/malformed/malformed-interpolated.stderr +++ b/src/test/ui/malformed/malformed-interpolated.stderr @@ -1,5 +1,5 @@ error: suffixed literals are not allowed in attributes - --> $DIR/malformed-interpolated.rs:13:8 + --> $DIR/malformed-interpolated.rs:12:8 | LL | check!(0u8); | ^^^ @@ -7,26 +7,16 @@ LL | check!(0u8); = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: unexpected token: `-0` - --> $DIR/malformed-interpolated.rs:5:25 - | -LL | #[rustc_dummy = $expr] - | ^^^^^ -... -LL | check!(-0); // ERROR, see above - | ----------- in this macro invocation + --> $DIR/malformed-interpolated.rs:13:8 | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | check!(-0); + | ^^ error: unexpected token: `0 + 0` - --> $DIR/malformed-interpolated.rs:5:25 - | -LL | #[rustc_dummy = $expr] - | ^^^^^ -... -LL | check!(0 + 0); // ERROR, see above - | -------------- in this macro invocation + --> $DIR/malformed-interpolated.rs:14:8 | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | check!(0 + 0); + | ^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/match/issue-72680.rs b/src/test/ui/match/issue-72680.rs new file mode 100644 index 0000000000..5b933edc82 --- /dev/null +++ b/src/test/ui/match/issue-72680.rs @@ -0,0 +1,65 @@ +// run-pass + +#![feature(or_patterns)] + +fn main() { + assert!(f("", 0)); + assert!(f("a", 1)); + assert!(f("b", 1)); + + assert!(!f("", 1)); + assert!(!f("a", 0)); + assert!(!f("b", 0)); + + assert!(!f("asdf", 32)); + + //// + + assert!(!g(true, true, true)); + assert!(!g(false, true, true)); + assert!(!g(true, false, true)); + assert!(!g(false, false, true)); + assert!(!g(true, true, false)); + + assert!(g(false, true, false)); + assert!(g(true, false, false)); + assert!(g(false, false, false)); + + //// + + assert!(!h(true, true, true)); + assert!(!h(false, true, true)); + assert!(!h(true, false, true)); + assert!(!h(false, false, true)); + assert!(!h(true, true, false)); + + assert!(h(false, true, false)); + assert!(h(true, false, false)); + assert!(h(false, false, false)); +} + +fn f(s: &str, num: usize) -> bool { + match (s, num) { + ("", 0) | ("a" | "b", 1) => true, + + _ => false, + } +} + +fn g(x: bool, y: bool, z: bool) -> bool { + match (x, y, x, z) { + (true | false, false, true, false) => true, + (false, true | false, true | false, false) => true, + (true | false, true | false, true | false, true) => false, + (true, true | false, true | false, false) => false, + } +} + +fn h(x: bool, y: bool, z: bool) -> bool { + match (x, (y, (x, (z,)))) { + (true | false, (false, (true, (false,)))) => true, + (false, (true | false, (true | false, (false,)))) => true, + (true | false, (true | false, (true | false, (true,)))) => false, + (true, (true | false, (true | false, (false,)))) => false, + } +} diff --git a/src/test/ui/mir/auxiliary/issue_76375_aux.rs b/src/test/ui/mir/auxiliary/issue_76375_aux.rs index f8b318d58b..72f32ecf7e 100644 --- a/src/test/ui/mir/auxiliary/issue_76375_aux.rs +++ b/src/test/ui/mir/auxiliary/issue_76375_aux.rs @@ -1,8 +1,8 @@ // edition:2018 -// compile-flags: -Z mir-opt-level=2 -Z unsound-mir-opts +// compile-flags: -Z mir-opt-level=2 #[inline(always)] -pub fn f(s: bool) -> String { +pub fn copy_prop(s: bool) -> String { let a = "Hello world!".to_string(); let b = a; let c = b; @@ -12,3 +12,9 @@ pub fn f(s: bool) -> String { String::new() } } + +#[inline(always)] +pub fn dest_prop(x: &[u8]) -> &[u8] { + let y = &x[..x.len()]; + y +} diff --git a/src/test/ui/mir/issue-76375.rs b/src/test/ui/mir/issue-76375.rs index ef459f6a28..a7772cb1fe 100644 --- a/src/test/ui/mir/issue-76375.rs +++ b/src/test/ui/mir/issue-76375.rs @@ -1,6 +1,8 @@ +// Regression test for issue #76375. +// // edition:2018 // build-pass -// compile-flags: -Z mir-opt-level=2 -L. +// compile-flags: -Z mir-opt-level=2 // aux-build:issue_76375_aux.rs #![crate_type = "lib"] @@ -8,8 +10,18 @@ extern crate issue_76375_aux; pub async fn g() { - issue_76375_aux::f(true); + issue_76375_aux::copy_prop(true); h().await; } +pub async fn u() { + let b = [0u8; 32]; + let mut i = 0; + while i != 10 { + issue_76375_aux::dest_prop(&b); + h().await; + i += 1; + } +} + pub async fn h() {} diff --git a/src/test/ui/mir/issue-77911.rs b/src/test/ui/mir/issue-77911.rs index b24faa6f88..fff303495e 100644 --- a/src/test/ui/mir/issue-77911.rs +++ b/src/test/ui/mir/issue-77911.rs @@ -1,5 +1,4 @@ // compile-flags: -Z mir-opt-level=2 -// ignore-cloudabi no std::fs // build-pass use std::fs::File; diff --git a/src/test/ui/mir/issue-78496.rs b/src/test/ui/mir/issue-78496.rs new file mode 100644 index 0000000000..1b0687cfac --- /dev/null +++ b/src/test/ui/mir/issue-78496.rs @@ -0,0 +1,16 @@ +// run-pass +// compile-flags: -Z mir-opt-level=2 -C opt-level=0 + +// example from #78496 +pub enum E<'a> { + Empty, + Some(&'a E<'a>), +} + +fn f(e: &E) -> u32 { + if let E::Some(E::Some(_)) = e { 1 } else { 2 } +} + +fn main() { + assert_eq!(f(&E::Empty), 2); +} diff --git a/src/test/ui/mir/issue-80949.rs b/src/test/ui/mir/issue-80949.rs new file mode 100644 index 0000000000..7e34a4f5c2 --- /dev/null +++ b/src/test/ui/mir/issue-80949.rs @@ -0,0 +1,34 @@ +// build-pass + +trait Trait { type Item; } + +impl<'a, X> Trait for &'a Vec { + type Item = &'a X; +} + +impl Trait for Box> { + type Item = X; +} + +fn make_dyn_trait(_: &()) -> Box> { + todo!() +} + +fn diff<'a, M, N, S>(_: N, _: S) +where + M: 'a, + N: Trait, + S: Trait, +{ + todo!() +} + +fn may_panic(_: X) { } + +fn main() { + let dyn_trait = make_dyn_trait(&()); + let storage = vec![()]; + let _x = may_panic(()); + let storage_ref = &storage; + diff(dyn_trait, storage_ref); +} diff --git a/src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs b/src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs new file mode 100644 index 0000000000..8a96303e6b --- /dev/null +++ b/src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs @@ -0,0 +1,13 @@ +// Checks that we can build a clone shim for array with generic size. +// Regression test for issue #79269. +// +// build-pass +// compile-flags: -Zmir-opt-level=2 -Zvalidate-mir +#![feature(min_const_generics)] + +#[derive(Clone)] +struct Array([T; N]); + +fn main() { + let _ = Array([0u32, 1u32, 2u32]).clone(); +} diff --git a/src/test/ui/mir/mir_dynamic_drops_1.rs b/src/test/ui/mir/mir_dynamic_drops_1.rs index a77b2368d3..2b33b61660 100644 --- a/src/test/ui/mir/mir_dynamic_drops_1.rs +++ b/src/test/ui/mir/mir_dynamic_drops_1.rs @@ -1,7 +1,6 @@ // run-fail // error-pattern:drop 1 // error-pattern:drop 2 -// ignore-cloudabi no std::process // ignore-emscripten no processes /// Structure which will not allow to be dropped twice. diff --git a/src/test/ui/mir/mir_dynamic_drops_2.rs b/src/test/ui/mir/mir_dynamic_drops_2.rs index 088a16d338..c883efdabc 100644 --- a/src/test/ui/mir/mir_dynamic_drops_2.rs +++ b/src/test/ui/mir/mir_dynamic_drops_2.rs @@ -1,6 +1,5 @@ // run-fail // error-pattern:drop 1 -// ignore-cloudabi no std::process // ignore-emscripten no processes /// Structure which will not allow to be dropped twice. diff --git a/src/test/ui/mir/mir_dynamic_drops_3.rs b/src/test/ui/mir/mir_dynamic_drops_3.rs index 029bdcd9a1..eb76fdff88 100644 --- a/src/test/ui/mir/mir_dynamic_drops_3.rs +++ b/src/test/ui/mir/mir_dynamic_drops_3.rs @@ -3,7 +3,6 @@ // error-pattern:drop 3 // error-pattern:drop 2 // error-pattern:drop 1 -// ignore-cloudabi no std::process // ignore-emscripten no processes /// Structure which will not allow to be dropped twice. diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 0b1fcf58e2..2efd37b473 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -15,7 +15,7 @@ LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` | doesn't satisfy `_: FnMut<(&&str,)>` | - ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL + ::: $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL | LL | pub struct Filter { | ----------------------- doesn't satisfy `_: Iterator` diff --git a/src/test/ui/mismatched_types/recovered-block.rs b/src/test/ui/mismatched_types/recovered-block.rs index cb8ad8092d..b230b47d35 100644 --- a/src/test/ui/mismatched_types/recovered-block.rs +++ b/src/test/ui/mismatched_types/recovered-block.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::env support - use std::env; pub struct Foo { diff --git a/src/test/ui/mismatched_types/recovered-block.stderr b/src/test/ui/mismatched_types/recovered-block.stderr index 525d09b8fc..f2b8404a32 100644 --- a/src/test/ui/mismatched_types/recovered-block.stderr +++ b/src/test/ui/mismatched_types/recovered-block.stderr @@ -1,5 +1,5 @@ error: missing `struct` for struct definition - --> $DIR/recovered-block.rs:13:8 + --> $DIR/recovered-block.rs:11:8 | LL | pub Foo { text } | ^ @@ -10,7 +10,7 @@ LL | pub struct Foo { text } | ^^^^^^ error: expected one of `(` or `<`, found `{` - --> $DIR/recovered-block.rs:19:9 + --> $DIR/recovered-block.rs:17:9 | LL | Foo { text: "".to_string() } | ^ expected one of `(` or `<` diff --git a/src/test/ui/issues/issue-56411-aux.rs b/src/test/ui/modules/issue-56411-aux.rs similarity index 100% rename from src/test/ui/issues/issue-56411-aux.rs rename to src/test/ui/modules/issue-56411-aux.rs diff --git a/src/test/ui/issues/issue-56411.rs b/src/test/ui/modules/issue-56411.rs similarity index 100% rename from src/test/ui/issues/issue-56411.rs rename to src/test/ui/modules/issue-56411.rs diff --git a/src/test/ui/issues/issue-56411.stderr b/src/test/ui/modules/issue-56411.stderr similarity index 100% rename from src/test/ui/issues/issue-56411.stderr rename to src/test/ui/modules/issue-56411.stderr diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs index 5fcd3392d3..52a5103865 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs @@ -1,7 +1,5 @@ #![feature(box_syntax, unboxed_closures)] -use std::usize; - fn to_fn>(f: F) -> F { f } fn test(_x: Box) {} diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index 462bbd7be5..9427ba546a 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure - --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:11:28 + --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28 | LL | let i = box 3; | - captured outer variable diff --git a/src/test/ui/multi-panic.rs b/src/test/ui/multi-panic.rs index 0f8bddf27f..37e8b99c2f 100644 --- a/src/test/ui/multi-panic.rs +++ b/src/test/ui/multi-panic.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/never_type/auto-traits.rs b/src/test/ui/never_type/auto-traits.rs index 84c8db4053..42ede708e6 100644 --- a/src/test/ui/never_type/auto-traits.rs +++ b/src/test/ui/never_type/auto-traits.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] #![feature(never_type)] diff --git a/src/test/ui/never_type/issue-13352.rs b/src/test/ui/never_type/issue-13352.rs index e6995be27d..9c884a33c5 100644 --- a/src/test/ui/never_type/issue-13352.rs +++ b/src/test/ui/never_type/issue-13352.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::process - fn foo(_: Box) {} fn main() { diff --git a/src/test/ui/never_type/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr index 93c792a72e..b98f6c9392 100644 --- a/src/test/ui/never_type/issue-13352.stderr +++ b/src/test/ui/never_type/issue-13352.stderr @@ -1,5 +1,5 @@ error[E0277]: cannot add `()` to `usize` - --> $DIR/issue-13352.rs:9:13 + --> $DIR/issue-13352.rs:7:13 | LL | 2_usize + (loop {}); | ^ no implementation for `usize + ()` diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index 799ed89dcc..4e122d930f 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)), + for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) i32)), (), ] diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index a094fc4517..44d1d2327f 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)), + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32)), (), ] diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index c4f4facae1..fa9f994c4f 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index c1450564c4..0555f79bcb 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index e7b8dff4e7..0115f5412f 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -10,7 +10,7 @@ LL | | }) | = note: defining type: case1::{closure#0} with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>)), (), ] @@ -49,7 +49,7 @@ LL | | }) | = note: defining type: case2::{closure#0} with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>)), (), ] = note: number of external vids: 2 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index c7e68d02dc..e55d033d2c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) u32>)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index abbc76eaf4..ac4a4579c9 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index c91b514a79..60dca1baa4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 4ddf6f8323..cbb10eb187 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 6dc6f45680..f9f1d8bb6f 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 6bcada5c26..1587c28e1b 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t0) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t2) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t3) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('t1) }) u32>)), (), ] = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 1da6c6d2c6..44f743310b 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -6,7 +6,7 @@ LL | expect_sig(|a, b| b); // ought to return `a` | = note: defining type: test::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('r) }) i32, (), ] diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 37638a93d7..2f134f83ce 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -15,7 +15,7 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time LL | v.push(|| x = String::new()); | ^^ - borrows occur due to use of `x` in closure | | - | mutable borrow starts here in previous iteration of loop + | `x` was mutably borrowed here in the previous iteration of the loop error[E0524]: two closures require unique access to `x` at the same time --> $DIR/closures-in-loops.rs:20:16 diff --git a/src/test/ui/nll/issue-62007-assign-const-index.stderr b/src/test/ui/nll/issue-62007-assign-const-index.stderr index 758a14d017..0db9fe62c3 100644 --- a/src/test/ui/nll/issue-62007-assign-const-index.stderr +++ b/src/test/ui/nll/issue-62007-assign-const-index.stderr @@ -5,7 +5,7 @@ LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { | - let's call the lifetime of this reference `'1` ... LL | result.push(&mut list[0].value); - | ^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^ `list[_].value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list[_].value` is borrowed for `'1` @@ -19,7 +19,7 @@ LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { LL | if let Some(n) = list[0].next.as_mut() { | ^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list[_].next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list[_].next` is borrowed for `'1` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-62007-assign-differing-fields.stderr b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr index f942d7628b..f1af2e855a 100644 --- a/src/test/ui/nll/issue-62007-assign-differing-fields.stderr +++ b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr @@ -5,7 +5,7 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a | -- lifetime `'a` defined here ... LL | result.push(&mut (list.0).value); - | ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list.0.value` is borrowed for `'a` @@ -19,7 +19,7 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a LL | if let Some(n) = (list.0).next.as_mut() { | ^^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/polonius/assignment-to-differing-field.stderr b/src/test/ui/nll/polonius/assignment-to-differing-field.stderr index 07ca021b53..2fe6a53a49 100644 --- a/src/test/ui/nll/polonius/assignment-to-differing-field.stderr +++ b/src/test/ui/nll/polonius/assignment-to-differing-field.stderr @@ -5,7 +5,7 @@ LL | fn assignment_to_field_projection<'a, T>( | -- lifetime `'a` defined here ... LL | result.push(&mut (list.0).value); - | ^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list.0.value` is borrowed for `'a` @@ -19,7 +19,7 @@ LL | fn assignment_to_field_projection<'a, T>( LL | if let Some(n) = (list.0).next.as_mut() { | ^^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time @@ -29,7 +29,7 @@ LL | fn assignment_through_projection_chain<'a, T>( | -- lifetime `'a` defined here ... LL | result.push(&mut ((((list.0).0).0).0).0.value); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.value` was mutably borrowed here in the previous iteration of the loop ... LL | return result; | ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a` @@ -43,7 +43,7 @@ LL | fn assignment_through_projection_chain<'a, T>( LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^--------- | | - | mutable borrow starts here in previous iteration of loop + | `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.0.0.0.0.next` is borrowed for `'a` error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 7c0d63c368..dbf76cd132 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -6,7 +6,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic::::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) T)), (), ] = note: number of external vids: 2 @@ -31,7 +31,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic_fail::::{closure#0} with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { kind: BrNamed('s) }) T)), (), ] = note: late-bound region is '_#2r diff --git a/src/test/ui/no-std-macros.rs b/src/test/ui/no-std-macros.rs new file mode 100644 index 0000000000..ada643c7ac --- /dev/null +++ b/src/test/ui/no-std-macros.rs @@ -0,0 +1,13 @@ +// compile-flags: --crate-type=lib +// check-pass +// issue #55482 +#![no_std] + +macro_rules! foo { + ($e:expr) => { + $crate::core::assert!($e); + $crate::core::assert_eq!($e, true); + }; +} + +pub fn foo() { foo!(true); } diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs index 1b0ad930da..68e6fa838b 100644 --- a/src/test/ui/no-stdio.rs +++ b/src/test/ui/no-stdio.rs @@ -1,6 +1,5 @@ // run-pass // ignore-android -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs b/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs index ced3c61ec1..7691149602 100644 --- a/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs +++ b/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs @@ -2,8 +2,6 @@ #![deny(const_err)] -use std::{f32, f64}; - // Forces evaluation of constants, triggering hard error fn force(_: T) {} diff --git a/src/test/ui/numbers-arithmetic/float-nan.rs b/src/test/ui/numbers-arithmetic/float-nan.rs index ee87b8cccf..0cc6473e5c 100644 --- a/src/test/ui/numbers-arithmetic/float-nan.rs +++ b/src/test/ui/numbers-arithmetic/float-nan.rs @@ -1,5 +1,4 @@ // run-pass -use std::f64; pub fn main() { let nan: f64 = f64::NAN; diff --git a/src/test/ui/numbers-arithmetic/num-wrapping.rs b/src/test/ui/numbers-arithmetic/num-wrapping.rs index 9a01549ecd..43b1059f94 100644 --- a/src/test/ui/numbers-arithmetic/num-wrapping.rs +++ b/src/test/ui/numbers-arithmetic/num-wrapping.rs @@ -21,7 +21,8 @@ macro_rules! int_modules { ($(($name:ident, $size:expr),)*) => ($( mod $name { pub const BITS: usize = $size; - pub use std::$name::*; + pub const MAX: $name = $name::MAX; + pub const MIN: $name = $name::MIN; } )*) } diff --git a/src/test/ui/numbers-arithmetic/overflowing-neg.rs b/src/test/ui/numbers-arithmetic/overflowing-neg.rs index fe77544641..df11980530 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-neg.rs +++ b/src/test/ui/numbers-arithmetic/overflowing-neg.rs @@ -6,5 +6,5 @@ #![allow(arithmetic_overflow)] fn main() { - let _x = -std::i8::MIN; + let _x = -i8::MIN; } diff --git a/src/test/ui/numbers-arithmetic/saturating-float-casts-impl.rs b/src/test/ui/numbers-arithmetic/saturating-float-casts-impl.rs index 6c3e503693..4c6929d662 100644 --- a/src/test/ui/numbers-arithmetic/saturating-float-casts-impl.rs +++ b/src/test/ui/numbers-arithmetic/saturating-float-casts-impl.rs @@ -11,10 +11,6 @@ extern crate test; use self::test::black_box; -use std::{f32, f64}; -#[cfg(not(target_os = "emscripten"))] -use std::{i128, u128}; -use std::{i16, i32, i64, i8, u16, u32, u64, u8}; macro_rules! test { ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ( diff --git a/src/test/ui/numbers-arithmetic/shift-near-oflo.rs b/src/test/ui/numbers-arithmetic/shift-near-oflo.rs index 939eb97461..55006a1134 100644 --- a/src/test/ui/numbers-arithmetic/shift-near-oflo.rs +++ b/src/test/ui/numbers-arithmetic/shift-near-oflo.rs @@ -47,21 +47,21 @@ fn test_left_shift() { let x = 1_u8 << id(0); assert_eq!(x, 1); let x = 1_i8 << id(7); - assert_eq!(x, std::i8::MIN); + assert_eq!(x, i8::MIN); let x = 1_u8 << id(7); assert_eq!(x, 0x80); // high-order bits on LHS are silently discarded without panic. let x = 3_i8 << id(7); - assert_eq!(x, std::i8::MIN); + assert_eq!(x, i8::MIN); let x = 3_u8 << id(7); assert_eq!(x, 0x80); // above is (approximately) expanded from: - tests!(i8, u8, 7, std::i8::MIN, 0x80_u8); + tests!(i8, u8, 7, i8::MIN, 0x80_u8); - tests!(i16, u16, 15, std::i16::MIN, 0x8000_u16); - tests!(i32, u32, 31, std::i32::MIN, 0x8000_0000_u32); - tests!(i64, u64, 63, std::i64::MIN, 0x8000_0000_0000_0000_u64); + tests!(i16, u16, 15, i16::MIN, 0x8000_u16); + tests!(i32, u32, 31, i32::MIN, 0x8000_0000_u32); + tests!(i64, u64, 63, i64::MIN, 0x8000_0000_0000_0000_u64); } fn test_right_shift() { @@ -92,9 +92,9 @@ fn test_right_shift() { } } } - tests!(i8, u8, 7, std::i8::MIN, 0x40_i8, 0x80_u8); - tests!(i16, u16, 15, std::i16::MIN, 0x4000_u16, 0x8000_u16); - tests!(i32, u32, 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32); - tests!(i64, u64, 63, std::i64::MIN, + tests!(i8, u8, 7, i8::MIN, 0x40_i8, 0x80_u8); + tests!(i16, u16, 15, i16::MIN, 0x4000_u16, 0x8000_u16); + tests!(i32, u32, 31, i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32); + tests!(i64, u64, 63, i64::MIN, 0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64); } diff --git a/src/test/ui/numbers-arithmetic/u128-as-f32.rs b/src/test/ui/numbers-arithmetic/u128-as-f32.rs index 2671a267f4..839ce932d9 100644 --- a/src/test/ui/numbers-arithmetic/u128-as-f32.rs +++ b/src/test/ui/numbers-arithmetic/u128-as-f32.rs @@ -4,8 +4,6 @@ #![deny(overflowing_literals)] extern crate test; -use std::f32; -use std::u128; use test::black_box; macro_rules! test { diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs deleted file mode 100644 index aa59c11970..0000000000 --- a/src/test/ui/offset_from.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -fn main() { - let mut a = [0; 5]; - let ptr1: *mut i32 = &mut a[1]; - let ptr2: *mut i32 = &mut a[3]; - unsafe { - assert_eq!(ptr2.offset_from(ptr1), 2); - assert_eq!(ptr1.offset_from(ptr2), -2); - assert_eq!(ptr1.offset(2), ptr2); - assert_eq!(ptr2.offset(-2), ptr1); - } -} diff --git a/src/test/ui/old-suffixes-are-really-forbidden.stderr b/src/test/ui/old-suffixes-are-really-forbidden.stderr index ccfe60e964..fb309793b3 100644 --- a/src/test/ui/old-suffixes-are-really-forbidden.stderr +++ b/src/test/ui/old-suffixes-are-really-forbidden.stderr @@ -1,18 +1,18 @@ -error: invalid suffix `is` for integer literal +error: invalid suffix `is` for number literal --> $DIR/old-suffixes-are-really-forbidden.rs:2:13 | LL | let a = 1_is; | ^^^^ invalid suffix `is` | - = help: the suffix must be one of the integral types (`u32`, `isize`, etc) + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) -error: invalid suffix `us` for integer literal +error: invalid suffix `us` for number literal --> $DIR/old-suffixes-are-really-forbidden.rs:3:13 | LL | let b = 2_us; | ^^^^ invalid suffix `us` | - = help: the suffix must be one of the integral types (`u32`, `isize`, etc) + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) error: aborting due to 2 previous errors diff --git a/src/test/ui/option-ext.rs b/src/test/ui/option-ext.rs deleted file mode 100644 index 76d0cf4398..0000000000 --- a/src/test/ui/option-ext.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -pub fn main() { - let thing = "{{ f }}"; - let f = thing.find("{{"); - - if f.is_none() { - println!("None!"); - } -} diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 512f1e283c..184ffa85c4 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -64,6 +64,35 @@ fn main() { | 2, ..] => {} _ => {} } + match &[][..] { + [true] => {} + [true | false, ..] => {} + _ => {} + } + match &[][..] { + [false] => {} + [true, ..] => {} + [true //~ ERROR unreachable + | false, ..] => {} + _ => {} + } + match (true, None) { + (true, Some(_)) => {} + (false, Some(true)) => {} + (true | false, None | Some(true //~ ERROR unreachable + | false)) => {} + } + macro_rules! t_or_f { + () => { + (true // FIXME: should be unreachable + | false) + }; + } + match (true, None) { + (true, Some(_)) => {} + (false, Some(true)) => {} + (true | false, None | Some(t_or_f!())) => {} + } match Some(0) { Some(0) => {} Some(0 //~ ERROR unreachable diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index e968310d10..8b1003b551 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -95,28 +95,40 @@ LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:69:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:75:10 + | +LL | [true + | ^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:82:36 + | +LL | (true | false, None | Some(true + | ^^^^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:98:14 | LL | Some(0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:88:19 + --> $DIR/exhaustiveness-unreachable-pattern.rs:117:19 | LL | | false) => {} | ^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:96:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:125:15 | LL | | true) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:102:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:131:15 | LL | | true, | ^^^^ -error: aborting due to 19 previous errors +error: aborting due to 21 previous errors diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs new file mode 100644 index 0000000000..9c3c5dd360 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs @@ -0,0 +1,15 @@ +// Test that :pat doesn't accept top-level or-patterns in edition 2018. + +// edition:2018 + +#![feature(or_patterns)] + +fn main() {} + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {}; +} + +accept_pat!(p | q); //~ ERROR no rules expected the token `|` +accept_pat!(|p| q); //~ ERROR no rules expected the token `|` diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr new file mode 100644 index 0000000000..7dbc308766 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -0,0 +1,20 @@ +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail-2018.rs:14:15 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(p | q); + | ^ no rules expected this token in macro call + +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail-2018.rs:15:13 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(|p| q); + | ^ no rules expected this token in macro call + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index d232200565..efe90b3e3c 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -5,16 +5,6 @@ fn main() {} -// Test the `pat` macro fragment parser: -macro_rules! accept_pat { - ($p:pat) => {} -} - -accept_pat!(p | q); //~ ERROR no rules expected the token `|` -accept_pat!(| p | q); //~ ERROR no rules expected the token `|` - -// Non-macro tests: - enum E { A, B } use E::*; diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 861d274ab5..989aeb5200 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,53 +1,53 @@ error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:27:13 + --> $DIR/or-patterns-syntactic-fail.rs:17:13 | LL | fn fun1(A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is not allowed in a parameter pattern - --> $DIR/or-patterns-syntactic-fail.rs:29:13 + --> $DIR/or-patterns-syntactic-fail.rs:19:13 | LL | fn fun2(| A | B: E) {} | ^ help: remove the `|` error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:29:15 + --> $DIR/or-patterns-syntactic-fail.rs:19:15 | LL | fn fun2(| A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:40:11 + --> $DIR/or-patterns-syntactic-fail.rs:30:11 | LL | let ( | A | B) = E::A; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:41:11 + --> $DIR/or-patterns-syntactic-fail.rs:31:11 | LL | let ( | A | B,) = (E::B,); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:42:11 + --> $DIR/or-patterns-syntactic-fail.rs:32:11 | LL | let [ | A | B ] = [E::A]; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:43:13 + --> $DIR/or-patterns-syntactic-fail.rs:33:13 | LL | let TS( | A | B ); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:44:17 + --> $DIR/or-patterns-syntactic-fail.rs:34:17 | LL | let NS { f: | A | B }; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:46:11 + --> $DIR/or-patterns-syntactic-fail.rs:36:11 | LL | let ( || A | B) = E::A; | ^^ help: remove the `||` @@ -55,7 +55,7 @@ LL | let ( || A | B) = E::A; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:47:11 + --> $DIR/or-patterns-syntactic-fail.rs:37:11 | LL | let [ || A | B ] = [E::A]; | ^^ help: remove the `||` @@ -63,7 +63,7 @@ LL | let [ || A | B ] = [E::A]; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:48:13 + --> $DIR/or-patterns-syntactic-fail.rs:38:13 | LL | let TS( || A | B ); | ^^ help: remove the `||` @@ -71,33 +71,15 @@ LL | let TS( || A | B ); = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:49:17 + --> $DIR/or-patterns-syntactic-fail.rs:39:17 | LL | let NS { f: || A | B }; | ^^ help: remove the `||` | = note: alternatives in or-patterns are separated with `|`, not `||` -error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:13:15 - | -LL | macro_rules! accept_pat { - | ----------------------- when calling this macro -... -LL | accept_pat!(p | q); - | ^ no rules expected this token in macro call - -error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:14:13 - | -LL | macro_rules! accept_pat { - | ----------------------- when calling this macro -... -LL | accept_pat!(| p | q); - | ^ no rules expected this token in macro call - error[E0369]: no implementation for `E | ()` - --> $DIR/or-patterns-syntactic-fail.rs:23:22 + --> $DIR/or-patterns-syntactic-fail.rs:13:22 | LL | let _ = |A | B: E| (); | ----^ -- () @@ -107,7 +89,7 @@ LL | let _ = |A | B: E| (); = note: an implementation of `std::ops::BitOr` might be missing for `E` error[E0308]: mismatched types - --> $DIR/or-patterns-syntactic-fail.rs:51:36 + --> $DIR/or-patterns-syntactic-fail.rs:41:36 | LL | let recovery_witness: String = 0; | ------ ^ @@ -116,7 +98,7 @@ LL | let recovery_witness: String = 0; | | help: try using a conversion method: `0.to_string()` | expected due to this -error: aborting due to 16 previous errors +error: aborting due to 14 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs new file mode 100644 index 0000000000..f0ce7597ae --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs @@ -0,0 +1,14 @@ +// Tests that :pat in macros in edition 2021 allows top-level or-patterns. + +// run-pass +// ignore-test +// edition:2021 +// FIXME(mark-i-m): unignore when 2021 machinery is in place. + +macro_rules! accept_pat { + ($p:pat) => {}; +} + +accept_pat!(p | q); + +fn main() {} diff --git a/src/test/ui/out-of-stack.rs b/src/test/ui/out-of-stack.rs index 6beafc0732..2d59c9f29b 100644 --- a/src/test/ui/out-of-stack.rs +++ b/src/test/ui/out-of-stack.rs @@ -3,7 +3,6 @@ #![allow(unused_must_use)] #![allow(unconditional_recursion)] // ignore-android: FIXME (#20004) -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/overloaded-calls-nontuple.rs b/src/test/ui/overloaded-calls-nontuple.rs index 62a7130dde..76b114c559 100644 --- a/src/test/ui/overloaded-calls-nontuple.rs +++ b/src/test/ui/overloaded-calls-nontuple.rs @@ -11,11 +11,13 @@ impl FnMut for S { extern "rust-call" fn call_mut(&mut self, z: isize) -> isize { self.x + self.y + z } + //~^^^ ERROR A function with the "rust-call" ABI must take a single non-self argument } impl FnOnce for S { type Output = isize; extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) } + //~^ ERROR A function with the "rust-call" ABI must take a single non-self argument } fn main() { diff --git a/src/test/ui/overloaded-calls-nontuple.stderr b/src/test/ui/overloaded-calls-nontuple.stderr index 82c12c4b6e..bdadb95db2 100644 --- a/src/test/ui/overloaded-calls-nontuple.stderr +++ b/src/test/ui/overloaded-calls-nontuple.stderr @@ -1,9 +1,21 @@ +error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple + --> $DIR/overloaded-calls-nontuple.rs:11:5 + | +LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: A function with the "rust-call" ABI must take a single non-self argument that is a tuple + --> $DIR/overloaded-calls-nontuple.rs:19:5 + | +LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit - --> $DIR/overloaded-calls-nontuple.rs:26:10 + --> $DIR/overloaded-calls-nontuple.rs:28:10 | LL | drop(s(3)) | ^^^^ -error: aborting due to previous error +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0059`. diff --git a/src/test/ui/panic-brace.rs b/src/test/ui/panic-brace.rs new file mode 100644 index 0000000000..754dcc287d --- /dev/null +++ b/src/test/ui/panic-brace.rs @@ -0,0 +1,31 @@ +// build-pass (FIXME(62277): should be check-pass) +// aux-build:fancy-panic.rs + +extern crate fancy_panic; + +const C: &str = "abc {}"; +static S: &str = "{bla}"; + +#[allow(unreachable_code)] +fn main() { + panic!("here's a brace: {"); //~ WARN panic message contains a brace + std::panic!("another one: }"); //~ WARN panic message contains a brace + core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder + assert!(false, "{:03x} {test} bla"); + //~^ WARN panic message contains unused formatting placeholders + debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces + panic!(C); // No warning (yet) + panic!(S); // No warning (yet) + panic!(concat!("{", "}")); //~ WARN panic message contains an unused formatting placeholder + panic!(concat!("{", "{")); //~ WARN panic message contains braces + + fancy_panic::fancy_panic!("test {} 123"); + //~^ WARN panic message contains an unused formatting placeholder + + // Check that the lint only triggers for std::panic and core::panic, + // not any panic macro: + macro_rules! panic { + ($e:expr) => (); + } + panic!("{}"); // OK +} diff --git a/src/test/ui/panic-brace.stderr b/src/test/ui/panic-brace.stderr new file mode 100644 index 0000000000..c2aa19c580 --- /dev/null +++ b/src/test/ui/panic-brace.stderr @@ -0,0 +1,107 @@ +warning: panic message contains a brace + --> $DIR/panic-brace.rs:11:29 + | +LL | panic!("here's a brace: {"); + | ^ + | + = note: `#[warn(non_fmt_panic)]` on by default + = note: this message is not used as a format string, but will be in a future Rust edition +help: add a "{}" format string to use the message literally + | +LL | panic!("{}", "here's a brace: {"); + | ^^^^^ + +warning: panic message contains a brace + --> $DIR/panic-brace.rs:12:31 + | +LL | std::panic!("another one: }"); + | ^ + | + = note: this message is not used as a format string, but will be in a future Rust edition +help: add a "{}" format string to use the message literally + | +LL | std::panic!("{}", "another one: }"); + | ^^^^^ + +warning: panic message contains an unused formatting placeholder + --> $DIR/panic-brace.rs:13:25 + | +LL | core::panic!("Hello {}"); + | ^^ + | + = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition +help: add the missing argument + | +LL | core::panic!("Hello {}", ...); + | ^^^^^ +help: or add a "{}" format string to use the message literally + | +LL | core::panic!("{}", "Hello {}"); + | ^^^^^ + +warning: panic message contains unused formatting placeholders + --> $DIR/panic-brace.rs:14:21 + | +LL | assert!(false, "{:03x} {test} bla"); + | ^^^^^^ ^^^^^^ + | + = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition +help: add the missing arguments + | +LL | assert!(false, "{:03x} {test} bla", ...); + | ^^^^^ +help: or add a "{}" format string to use the message literally + | +LL | assert!(false, "{}", "{:03x} {test} bla"); + | ^^^^^ + +warning: panic message contains braces + --> $DIR/panic-brace.rs:16:27 + | +LL | debug_assert!(false, "{{}} bla"); + | ^^^^ + | + = note: this message is not used as a format string, but will be in a future Rust edition +help: add a "{}" format string to use the message literally + | +LL | debug_assert!(false, "{}", "{{}} bla"); + | ^^^^^ + +warning: panic message contains an unused formatting placeholder + --> $DIR/panic-brace.rs:19:12 + | +LL | panic!(concat!("{", "}")); + | ^^^^^^^^^^^^^^^^^ + | + = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition +help: add the missing argument + | +LL | panic!(concat!("{", "}"), ...); + | ^^^^^ +help: or add a "{}" format string to use the message literally + | +LL | panic!("{}", concat!("{", "}")); + | ^^^^^ + +warning: panic message contains braces + --> $DIR/panic-brace.rs:20:5 + | +LL | panic!(concat!("{", "{")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this message is not used as a format string, but will be in a future Rust edition +help: add a "{}" format string to use the message literally + | +LL | panic!("{}", concat!("{", "{")); + | ^^^^^ + +warning: panic message contains an unused formatting placeholder + --> $DIR/panic-brace.rs:22:37 + | +LL | fancy_panic::fancy_panic!("test {} 123"); + | ^^ + | + = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition + +warning: 8 warnings emitted + diff --git a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs index 4b0f92456e..f8368ff690 100644 --- a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs +++ b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs @@ -1,7 +1,6 @@ // build-fail // compile-flags:-C panic=abort -C prefer-dynamic // ignore-musl - no dylibs here -// ignore-cloudabi // ignore-emscripten // ignore-sgx no dynamic lib support // error-pattern:`panic_unwind` is not compiled with this crate's panic strategy diff --git a/src/test/ui/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/ui/panic-runtime/abort-link-to-unwinding-crates.rs index 9c099911ea..566626513e 100644 --- a/src/test/ui/panic-runtime/abort-link-to-unwinding-crates.rs +++ b/src/test/ui/panic-runtime/abort-link-to-unwinding-crates.rs @@ -3,7 +3,6 @@ // compile-flags:-C panic=abort // aux-build:exit-success-if-unwind.rs // no-prefer-dynamic -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes // ignore-macos diff --git a/src/test/ui/panic-runtime/abort.rs b/src/test/ui/panic-runtime/abort.rs index f625fe35d7..dcc4061fde 100644 --- a/src/test/ui/panic-runtime/abort.rs +++ b/src/test/ui/panic-runtime/abort.rs @@ -2,7 +2,6 @@ #![allow(unused_variables)] // compile-flags:-C panic=abort // no-prefer-dynamic -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes // ignore-macos diff --git a/src/test/ui/panic-runtime/lto-abort.rs b/src/test/ui/panic-runtime/lto-abort.rs index 8fff71a629..5cc4c01323 100644 --- a/src/test/ui/panic-runtime/lto-abort.rs +++ b/src/test/ui/panic-runtime/lto-abort.rs @@ -2,7 +2,6 @@ #![allow(unused_variables)] // compile-flags:-C lto -C panic=abort // no-prefer-dynamic -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/panic-runtime/lto-unwind.rs b/src/test/ui/panic-runtime/lto-unwind.rs index 94a0b596e4..6f39b76526 100644 --- a/src/test/ui/panic-runtime/lto-unwind.rs +++ b/src/test/ui/panic-runtime/lto-unwind.rs @@ -3,7 +3,6 @@ // compile-flags:-C lto -C panic=unwind // no-prefer-dynamic -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/panic-while-printing.rs b/src/test/ui/panic-while-printing.rs index 21fc12759f..96b35e4553 100644 --- a/src/test/ui/panic-while-printing.rs +++ b/src/test/ui/panic-while-printing.rs @@ -1,11 +1,12 @@ // run-pass // ignore-emscripten no subprocess support -#![feature(set_stdio)] +#![feature(internal_output_capture)] use std::fmt; use std::fmt::{Display, Formatter}; -use std::io::{self, set_panic, LocalOutput, Write}; +use std::io::set_output_capture; +use std::sync::{Arc, Mutex}; pub struct A; @@ -15,23 +16,8 @@ impl Display for A { } } -struct Sink; -impl Write for Sink { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} -impl LocalOutput for Sink { - fn clone_box(&self) -> Box { - Box::new(Sink) - } -} - fn main() { - set_panic(Some(Box::new(Sink))); + set_output_capture(Some(Arc::new(Mutex::new(Vec::new())))); assert!(std::panic::catch_unwind(|| { eprintln!("{}", A); }) diff --git a/src/test/ui/panics/abort-on-panic.rs b/src/test/ui/panics/abort-on-panic.rs index c6e8dbf012..f34cf6a9cb 100644 --- a/src/test/ui/panics/abort-on-panic.rs +++ b/src/test/ui/panics/abort-on-panic.rs @@ -5,7 +5,6 @@ // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that // we never unwind through them. -// ignore-cloudabi no env and process // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/panics/issue-47429-short-backtraces.rs b/src/test/ui/panics/issue-47429-short-backtraces.rs index 1e8c38cc34..015ab8fdd8 100644 --- a/src/test/ui/panics/issue-47429-short-backtraces.rs +++ b/src/test/ui/panics/issue-47429-short-backtraces.rs @@ -7,7 +7,6 @@ // ignore-msvc see #62897 and `backtrace-debuginfo.rs` test // ignore-android FIXME #17520 -// ignore-cloudabi spawning processes is not supported // ignore-openbsd no support for libbacktrace without filename // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support diff --git a/src/test/ui/panics/issue-47429-short-backtraces.run.stderr b/src/test/ui/panics/issue-47429-short-backtraces.run.stderr index 99ee26fe55..3287963890 100644 --- a/src/test/ui/panics/issue-47429-short-backtraces.run.stderr +++ b/src/test/ui/panics/issue-47429-short-backtraces.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:17:5 +thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:16:5 stack backtrace: 0: std::panicking::begin_panic 1: issue_47429_short_backtraces::main diff --git a/src/test/ui/parser/attr-bad-meta-2.rs b/src/test/ui/parser/attr-bad-meta-2.rs index cefd336974..db612ed883 100644 --- a/src/test/ui/parser/attr-bad-meta-2.rs +++ b/src/test/ui/parser/attr-bad-meta-2.rs @@ -1,2 +1,2 @@ -#[path =] //~ ERROR unexpected token: `]` +#[path =] //~ ERROR expected expression, found `]` mod m {} diff --git a/src/test/ui/parser/attr-bad-meta-2.stderr b/src/test/ui/parser/attr-bad-meta-2.stderr index 2d772dae69..6fc6fb665a 100644 --- a/src/test/ui/parser/attr-bad-meta-2.stderr +++ b/src/test/ui/parser/attr-bad-meta-2.stderr @@ -1,8 +1,8 @@ -error: unexpected token: `]` +error: expected expression, found `]` --> $DIR/attr-bad-meta-2.rs:1:9 | LL | #[path =] - | ^ + | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs index 7db83674ef..446a094055 100644 --- a/src/test/ui/parser/bad-lit-suffixes.rs +++ b/src/test/ui/parser/bad-lit-suffixes.rs @@ -19,8 +19,8 @@ fn main() { 1234f1024; //~ ERROR invalid width `1024` for float literal 1234.5f1024; //~ ERROR invalid width `1024` for float literal - 1234suffix; //~ ERROR invalid suffix `suffix` for integer literal - 0b101suffix; //~ ERROR invalid suffix `suffix` for integer literal + 1234suffix; //~ ERROR invalid suffix `suffix` for number literal + 0b101suffix; //~ ERROR invalid suffix `suffix` for number literal 1.0suffix; //~ ERROR invalid suffix `suffix` for float literal 1.0e10suffix; //~ ERROR invalid suffix `suffix` for float literal } diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr index 6b0049298f..9b59657148 100644 --- a/src/test/ui/parser/bad-lit-suffixes.stderr +++ b/src/test/ui/parser/bad-lit-suffixes.stderr @@ -78,21 +78,21 @@ LL | 1234.5f1024; | = help: valid widths are 32 and 64 -error: invalid suffix `suffix` for integer literal +error: invalid suffix `suffix` for number literal --> $DIR/bad-lit-suffixes.rs:22:5 | LL | 1234suffix; | ^^^^^^^^^^ invalid suffix `suffix` | - = help: the suffix must be one of the integral types (`u32`, `isize`, etc) + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) -error: invalid suffix `suffix` for integer literal +error: invalid suffix `suffix` for number literal --> $DIR/bad-lit-suffixes.rs:23:5 | LL | 0b101suffix; | ^^^^^^^^^^^ invalid suffix `suffix` | - = help: the suffix must be one of the integral types (`u32`, `isize`, etc) + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) error: invalid suffix `suffix` for float literal --> $DIR/bad-lit-suffixes.rs:24:5 diff --git a/src/test/ui/parser/default-unmatched-assoc.stderr b/src/test/ui/parser/default-unmatched-assoc.stderr index c8d1769cb5..ee35fded99 100644 --- a/src/test/ui/parser/default-unmatched-assoc.stderr +++ b/src/test/ui/parser/default-unmatched-assoc.stderr @@ -39,13 +39,13 @@ LL | } | - item list ends here error: cannot find macro `default` in this scope - --> $DIR/default-unmatched-assoc.rs:12:5 + --> $DIR/default-unmatched-assoc.rs:4:5 | LL | default!(); | ^^^^^^^ error: cannot find macro `default` in this scope - --> $DIR/default-unmatched-assoc.rs:4:5 + --> $DIR/default-unmatched-assoc.rs:12:5 | LL | default!(); | ^^^^^^^ diff --git a/src/test/ui/parser/fn-colon-return-type.rs b/src/test/ui/parser/fn-colon-return-type.rs index c791fb3ae6..0001ef57c9 100644 --- a/src/test/ui/parser/fn-colon-return-type.rs +++ b/src/test/ui/parser/fn-colon-return-type.rs @@ -1,4 +1,5 @@ -fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` +fn foo(x: i32): i32 { +//~^ ERROR return types are denoted using `->` x } diff --git a/src/test/ui/parser/fn-colon-return-type.stderr b/src/test/ui/parser/fn-colon-return-type.stderr index 92df9bc60b..1de9187820 100644 --- a/src/test/ui/parser/fn-colon-return-type.stderr +++ b/src/test/ui/parser/fn-colon-return-type.stderr @@ -1,8 +1,8 @@ -error: expected one of `->`, `;`, `where`, or `{`, found `:` +error: return types are denoted using `->` --> $DIR/fn-colon-return-type.rs:1:15 | LL | fn foo(x: i32): i32 { - | ^ expected one of `->`, `;`, `where`, or `{` + | ^ help: use `->` instead error: aborting due to previous error diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index 4193b3ee69..2f11f95bf4 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -108,9 +108,12 @@ error: functions in `extern` blocks cannot have qualifiers LL | extern { | ------ in this `extern` block LL | async fn fe1(); - | ---------^^^ - | | - | help: remove the qualifiers: `fn` + | ^^^ + | +help: remove the qualifiers + | +LL | fn fe1(); + | ^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:52:19 @@ -119,9 +122,12 @@ LL | extern { | ------ in this `extern` block LL | async fn fe1(); LL | unsafe fn fe2(); - | ----------^^^ - | | - | help: remove the qualifiers: `fn` + | ^^^ + | +help: remove the qualifiers + | +LL | fn fe2(); + | ^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:53:18 @@ -130,9 +136,12 @@ LL | extern { | ------ in this `extern` block ... LL | const fn fe3(); - | ---------^^^ - | | - | help: remove the qualifiers: `fn` + | ^^^ + | +help: remove the qualifiers + | +LL | fn fe3(); + | ^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:54:23 @@ -141,9 +150,12 @@ LL | extern { | ------ in this `extern` block ... LL | extern "C" fn fe4(); - | --------------^^^ - | | - | help: remove the qualifiers: `fn` + | ^^^ + | +help: remove the qualifiers + | +LL | fn fe4(); + | ^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:55:42 @@ -152,9 +164,12 @@ LL | extern { | ------ in this `extern` block ... LL | const async unsafe extern "C" fn fe5(); - | ---------------------------------^^^ - | | - | help: remove the qualifiers: `fn` + | ^^^ + | +help: remove the qualifiers + | +LL | fn fe5(); + | ^^ error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:55:9 diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed new file mode 100644 index 0000000000..055800d23b --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.fixed @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs new file mode 100644 index 0000000000..e8be16516d --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.rs @@ -0,0 +1,8 @@ +// run-rustfix +// edition:2018 + +// Regression test for issue 79694 + +fn main() { + let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect +} diff --git a/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr new file mode 100644 index 0000000000..2add9fb33c --- /dev/null +++ b/src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr @@ -0,0 +1,13 @@ +error: the order of `move` and `async` is incorrect + --> $DIR/incorrect-move-async-order-issue-79694.rs:7:13 + | +LL | let _ = move async { }; + | ^^^^^^^^^^ + | +help: try switching the order + | +LL | let _ = async move { }; + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/parser/issue-14303-fncall.stderr b/src/test/ui/parser/issue-14303-fncall.stderr index 1095422371..cdda0d001c 100644 --- a/src/test/ui/parser/issue-14303-fncall.stderr +++ b/src/test/ui/parser/issue-14303-fncall.stderr @@ -3,8 +3,6 @@ error[E0747]: type provided when a lifetime was expected | LL | .collect::>>(); | ^ - | - = note: lifetime arguments must be provided before type arguments error: aborting due to previous error diff --git a/src/test/ui/parser/issue-14303-path.stderr b/src/test/ui/parser/issue-14303-path.stderr index c1ad2332b5..841e63ecbe 100644 --- a/src/test/ui/parser/issue-14303-path.stderr +++ b/src/test/ui/parser/issue-14303-path.stderr @@ -3,8 +3,6 @@ error[E0747]: type provided when a lifetime was expected | LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} | ^ - | - = note: lifetime arguments must be provided before type arguments error: aborting due to previous error diff --git a/src/test/ui/parser/issue-62660.rs b/src/test/ui/parser/issue-62660.rs index 33c8a9fa32..4f866b7897 100644 --- a/src/test/ui/parser/issue-62660.rs +++ b/src/test/ui/parser/issue-62660.rs @@ -5,7 +5,7 @@ struct Foo; impl Foo { pub fn foo(_: i32, self: Box`, found `)` + //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)` } fn main() {} diff --git a/src/test/ui/parser/issue-62660.stderr b/src/test/ui/parser/issue-62660.stderr index 0844da1bd9..a50ada9056 100644 --- a/src/test/ui/parser/issue-62660.stderr +++ b/src/test/ui/parser/issue-62660.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` +error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)` --> $DIR/issue-62660.rs:7:38 | LL | pub fn foo(_: i32, self: Box`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;` +error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `:`, `<`, `=`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;` --> $DIR/issue-63116.rs:3:15 | LL | impl W $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13 + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 | -LL | mac1! { does_not_exist!() } +LL | mac2! { does_not_exist!() } | ^^^^^^^^^^^^^^ error: cannot find macro `does_not_exist` in this scope - --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13 | -LL | mac2! { does_not_exist!() } +LL | mac1! { does_not_exist!() } | ^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/lifetime-semicolon.rs b/src/test/ui/parser/lifetime-semicolon.rs index 1f147216ea..7cc14971f6 100644 --- a/src/test/ui/parser/lifetime-semicolon.rs +++ b/src/test/ui/parser/lifetime-semicolon.rs @@ -3,6 +3,6 @@ struct Foo<'a, 'b> { } fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {} -//~^ ERROR expected one of `,` or `>`, found `;` +//~^ ERROR expected one of `,`, `:`, `=`, or `>`, found `;` fn main() {} diff --git a/src/test/ui/parser/lifetime-semicolon.stderr b/src/test/ui/parser/lifetime-semicolon.stderr index 4641c286cb..3b67705aae 100644 --- a/src/test/ui/parser/lifetime-semicolon.stderr +++ b/src/test/ui/parser/lifetime-semicolon.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `>`, found `;` +error: expected one of `,`, `:`, `=`, or `>`, found `;` --> $DIR/lifetime-semicolon.rs:5:30 | LL | fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {} - | ^ expected one of `,` or `>` + | ^ expected one of `,`, `:`, `=`, or `>` error: aborting due to previous error diff --git a/src/test/ui/parser/no-binary-float-literal.rs b/src/test/ui/parser/no-binary-float-literal.rs index 052cb4934f..e07ff6518e 100644 --- a/src/test/ui/parser/no-binary-float-literal.rs +++ b/src/test/ui/parser/no-binary-float-literal.rs @@ -4,5 +4,5 @@ fn main() { 0b101.010; //~^ ERROR binary float literal is not supported 0b101p4f64; - //~^ ERROR invalid suffix `p4f64` for integer literal + //~^ ERROR invalid suffix `p4f64` for number literal } diff --git a/src/test/ui/parser/no-binary-float-literal.stderr b/src/test/ui/parser/no-binary-float-literal.stderr index 65b129b582..cfd4486845 100644 --- a/src/test/ui/parser/no-binary-float-literal.stderr +++ b/src/test/ui/parser/no-binary-float-literal.stderr @@ -10,13 +10,13 @@ error: binary float literal is not supported LL | 0b101010f64; | ^^^^^^^^^^^ not supported -error: invalid suffix `p4f64` for integer literal +error: invalid suffix `p4f64` for number literal --> $DIR/no-binary-float-literal.rs:6:5 | LL | 0b101p4f64; | ^^^^^^^^^^ invalid suffix `p4f64` | - = help: the suffix must be one of the integral types (`u32`, `isize`, etc) + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.stderr b/src/test/ui/parser/no-const-fn-in-extern-block.stderr index de653987e4..af92f2d94f 100644 --- a/src/test/ui/parser/no-const-fn-in-extern-block.stderr +++ b/src/test/ui/parser/no-const-fn-in-extern-block.stderr @@ -4,9 +4,12 @@ error: functions in `extern` blocks cannot have qualifiers LL | extern { | ------ in this `extern` block LL | const fn foo(); - | ---------^^^ - | | - | help: remove the qualifiers: `fn` + | ^^^ + | +help: remove the qualifiers + | +LL | fn foo(); + | ^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/no-const-fn-in-extern-block.rs:4:21 @@ -15,9 +18,12 @@ LL | extern { | ------ in this `extern` block ... LL | const unsafe fn bar(); - | ----------------^^^ - | | - | help: remove the qualifiers: `fn` + | ^^^ + | +help: remove the qualifiers + | +LL | fn bar(); + | ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/not-a-pred.rs b/src/test/ui/parser/not-a-pred.rs index 1b3d9bf66b..5518b554d8 100644 --- a/src/test/ui/parser/not-a-pred.rs +++ b/src/test/ui/parser/not-a-pred.rs @@ -1,6 +1,15 @@ fn f(a: isize, b: isize) : lt(a, b) { } -//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` +//~^ ERROR return types are denoted using `->` +//~| ERROR expected type, found function `lt` [E0573] +//~| ERROR expected type, found local variable `a` [E0573] +//~| ERROR expected type, found local variable `b` [E0573] fn lt(a: isize, b: isize) { } -fn main() { let a: isize = 10; let b: isize = 23; check (lt(a, b)); f(a, b); } +fn main() { + let a: isize = 10; + let b: isize = 23; + check (lt(a, b)); + //~^ ERROR cannot find function `check` in this scope [E0425] + f(a, b); +} diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index ec413c5594..bcc64a687f 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -1,8 +1,34 @@ -error: expected one of `->`, `;`, `where`, or `{`, found `:` +error: return types are denoted using `->` --> $DIR/not-a-pred.rs:1:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ expected one of `->`, `;`, `where`, or `{` + | ^ help: use `->` instead -error: aborting due to previous error +error[E0573]: expected type, found function `lt` + --> $DIR/not-a-pred.rs:1:28 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^^^^^^^^ not a type + +error[E0573]: expected type, found local variable `a` + --> $DIR/not-a-pred.rs:1:31 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^ not a type + +error[E0573]: expected type, found local variable `b` + --> $DIR/not-a-pred.rs:1:34 + | +LL | fn f(a: isize, b: isize) : lt(a, b) { } + | ^ not a type + +error[E0425]: cannot find function `check` in this scope + --> $DIR/not-a-pred.rs:12:5 + | +LL | check (lt(a, b)); + | ^^^^^ not found in this scope + +error: aborting due to 5 previous errors +Some errors have detailed explanations: E0425, E0573. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.rs b/src/test/ui/parser/removed-syntax-closure-lifetime.rs index ceac940800..e807a17947 100644 --- a/src/test/ui/parser/removed-syntax-closure-lifetime.rs +++ b/src/test/ui/parser/removed-syntax-closure-lifetime.rs @@ -1,2 +1,2 @@ type closure = Box; -//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/` +//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/` diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr index a100f689fb..63b6e138ce 100644 --- a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr +++ b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/` +error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/` --> $DIR/removed-syntax-closure-lifetime.rs:1:22 | LL | type closure = Box; - | ^ expected one of 7 possible tokens + | ^ expected one of 9 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs b/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs index f9a9d071a3..a8dee5bbda 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs @@ -1,2 +1,2 @@ type mut_box = Box; -//~^ ERROR expected one of `>`, const, lifetime, or type, found keyword `mut` +//~^ ERROR expected one of `>`, a const expression, lifetime, or type, found keyword `mut` diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr index 0703caf5be..39db0be9fb 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found keyword `mut` +error: expected one of `>`, a const expression, lifetime, or type, found keyword `mut` --> $DIR/removed-syntax-uniq-mut-ty.rs:1:20 | LL | type mut_box = Box; - | ^^^ expected one of `>`, const, lifetime, or type + | ^^^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs index 34aee7f693..f2d97b7bac 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs @@ -3,10 +3,10 @@ fn main() {} trait X { - default const A: u8; //~ ERROR `default` is only allowed on items in `impl` definitions - default const B: u8 = 0; //~ ERROR `default` is only allowed on items in `impl` definitions - default type D; //~ ERROR `default` is only allowed on items in `impl` definitions - default type C: Ord; //~ ERROR `default` is only allowed on items in `impl` definitions - default fn f1(); //~ ERROR `default` is only allowed on items in `impl` definitions - default fn f2() {} //~ ERROR `default` is only allowed on items in `impl` definitions + default const A: u8; //~ ERROR `default` is only allowed on items in trait impls + default const B: u8 = 0; //~ ERROR `default` is only allowed on items in trait impls + default type D; //~ ERROR `default` is only allowed on items in trait impls + default type C: Ord; //~ ERROR `default` is only allowed on items in trait impls + default fn f1(); //~ ERROR `default` is only allowed on items in trait impls + default fn f2() {} //~ ERROR `default` is only allowed on items in trait impls } diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr index cdc9ee8d9e..76fa860334 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr @@ -1,4 +1,4 @@ -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:6:5 | LL | default const A: u8; @@ -6,7 +6,7 @@ LL | default const A: u8; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:7:5 | LL | default const B: u8 = 0; @@ -14,7 +14,7 @@ LL | default const B: u8 = 0; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:8:5 | LL | default type D; @@ -22,7 +22,7 @@ LL | default type D; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:9:5 | LL | default type C: Ord; @@ -30,7 +30,7 @@ LL | default type C: Ord; | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:10:5 | LL | default fn f1(); @@ -38,7 +38,7 @@ LL | default fn f1(); | | | `default` because of this -error: `default` is only allowed on items in `impl` definitions +error: `default` is only allowed on items in trait impls --> $DIR/trait-item-with-defaultness-fail-semantic.rs:11:5 | LL | default fn f2() {} diff --git a/src/test/ui/parser/trait-object-bad-parens.rs b/src/test/ui/parser/trait-object-bad-parens.rs index 0a2836d691..8e267c7448 100644 --- a/src/test/ui/parser/trait-object-bad-parens.rs +++ b/src/test/ui/parser/trait-object-bad-parens.rs @@ -1,4 +1,4 @@ -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] #![allow(bare_trait_objects)] diff --git a/src/test/ui/paths-containing-nul.rs b/src/test/ui/paths-containing-nul.rs index e9510b53fe..cb40c4f6fb 100644 --- a/src/test/ui/paths-containing-nul.rs +++ b/src/test/ui/paths-containing-nul.rs @@ -1,7 +1,6 @@ // run-pass #![allow(deprecated)] -// ignore-cloudabi no files or I/O // ignore-wasm32-bare no files or I/O // ignore-emscripten no files // ignore-sgx no files diff --git a/src/test/ui/pattern/usefulness/irrefutable-exhaustive-integer-binding.rs b/src/test/ui/pattern/integer-range-binding.rs similarity index 100% rename from src/test/ui/pattern/usefulness/irrefutable-exhaustive-integer-binding.rs rename to src/test/ui/pattern/integer-range-binding.rs diff --git a/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.rs b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.rs new file mode 100644 index 0000000000..a5e9b1db54 --- /dev/null +++ b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.rs @@ -0,0 +1,9 @@ +// Regression test for correct pretty-printing of an AST representing `&(mut x)` in help +// suggestion diagnostic. + +fn main() { + let mut &x = &0; + //~^ ERROR `mut` must be attached to each individual binding + //~| HELP add `mut` to each binding + //~| SUGGESTION &(mut x) +} diff --git a/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr new file mode 100644 index 0000000000..75b6c163b2 --- /dev/null +++ b/src/test/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr @@ -0,0 +1,10 @@ +error: `mut` must be attached to each individual binding + --> $DIR/issue-80186-mut-binding-help-suggestion.rs:5:9 + | +LL | let mut &x = &0; + | ^^^^^^ help: add `mut` to each binding: `&(mut x)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: aborting due to previous error + diff --git a/src/test/ui/pattern/or-pattern-macro-pat.rs b/src/test/ui/pattern/or-pattern-macro-pat.rs new file mode 100644 index 0000000000..8749407675 --- /dev/null +++ b/src/test/ui/pattern/or-pattern-macro-pat.rs @@ -0,0 +1,44 @@ +// run-pass +// edition:2021 +// ignore-test +// FIXME(mark-i-m): enable this test again when 2021 machinery is available + +#![feature(or_patterns)] + +use Foo::*; + +#[derive(Eq, PartialEq, Debug)] +enum Foo { + A(u64), + B(u64), + C, + D, +} + +macro_rules! foo { + ($orpat:pat, $val:expr) => { + match $val { + x @ ($orpat) => x, // leading vert would not be allowed in $orpat + _ => B(0xDEADBEEFu64), + } + }; +} + +macro_rules! bar { + ($orpat:pat, $val:expr) => { + match $val { + $orpat => 42, // leading vert allowed here + _ => 0xDEADBEEFu64, + } + }; +} + +fn main() { + // Test or-pattern. + let y = foo!(A(_)|B(_), A(32)); + assert_eq!(y, A(32)); + + // Leading vert in or-pattern. + let y = bar!(|C| D, C); + assert_eq!(y, 42u64); +} diff --git a/src/test/ui/pattern/usefulness/auxiliary/empty.rs b/src/test/ui/pattern/usefulness/auxiliary/empty.rs new file mode 100644 index 0000000000..0b0719f48e --- /dev/null +++ b/src/test/ui/pattern/usefulness/auxiliary/empty.rs @@ -0,0 +1,2 @@ +#![crate_type = "rlib"] +pub enum EmptyForeignEnum {} diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/usefulness/const-pat-ice.rs similarity index 100% rename from src/test/ui/pattern/const-pat-ice.rs rename to src/test/ui/pattern/usefulness/const-pat-ice.rs diff --git a/src/test/ui/pattern/usefulness/consts-opaque.rs b/src/test/ui/pattern/usefulness/consts-opaque.rs index f87f96e34f..ca4fcd85bb 100644 --- a/src/test/ui/pattern/usefulness/consts-opaque.rs +++ b/src/test/ui/pattern/usefulness/consts-opaque.rs @@ -25,10 +25,6 @@ enum Baz { impl Eq for Baz {} const BAZ: Baz = Baz::Baz1; -type Quux = fn(usize, usize) -> usize; -fn quux(a: usize, b: usize) -> usize { a + b } -const QUUX: Quux = quux; - fn main() { match FOO { FOO => {} @@ -106,9 +102,44 @@ fn main() { //~^ ERROR unreachable pattern } + type Quux = fn(usize, usize) -> usize; + fn quux(a: usize, b: usize) -> usize { a + b } + const QUUX: Quux = quux; + match QUUX { QUUX => {} QUUX => {} _ => {} } + + #[derive(PartialEq, Eq)] + struct Wrap(T); + const WRAPQUUX: Wrap = Wrap(quux); + + match WRAPQUUX { + WRAPQUUX => {} + WRAPQUUX => {} + Wrap(_) => {} + } + + match WRAPQUUX { + Wrap(_) => {} + WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer + //~^ ERROR unreachable pattern + } + + #[derive(PartialEq, Eq)] + enum WhoKnows { + Yay(T), + Nope, + }; + const WHOKNOWSQUUX: WhoKnows = WhoKnows::Yay(quux); + + match WHOKNOWSQUUX { + WHOKNOWSQUUX => {} + WhoKnows::Yay(_) => {} + WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer + //~^ ERROR unreachable pattern + WhoKnows::Nope => {} + } } diff --git a/src/test/ui/pattern/usefulness/consts-opaque.stderr b/src/test/ui/pattern/usefulness/consts-opaque.stderr index f10166d5a3..68451043cf 100644 --- a/src/test/ui/pattern/usefulness/consts-opaque.stderr +++ b/src/test/ui/pattern/usefulness/consts-opaque.stderr @@ -1,11 +1,11 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:34:9 + --> $DIR/consts-opaque.rs:30:9 | LL | FOO => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:36:9 + --> $DIR/consts-opaque.rs:32:9 | LL | _ => {} // should not be emitting unreachable warning | ^ @@ -17,19 +17,19 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:41:9 + --> $DIR/consts-opaque.rs:37:9 | LL | FOO_REF => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:43:9 + --> $DIR/consts-opaque.rs:39:9 | LL | Foo(_) => {} // should not be emitting unreachable warning | ^^^^^^ warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:49:9 + --> $DIR/consts-opaque.rs:45:9 | LL | FOO_REF_REF => {} | ^^^^^^^^^^^ @@ -39,13 +39,13 @@ LL | FOO_REF_REF => {} = note: for more information, see issue #62411 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:57:9 + --> $DIR/consts-opaque.rs:53:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:57:9 + --> $DIR/consts-opaque.rs:53:9 | LL | Bar => {} | --- matches any value @@ -53,7 +53,7 @@ LL | BAR => {} // should not be emitting unreachable warning | ^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:60:9 + --> $DIR/consts-opaque.rs:56:9 | LL | Bar => {} | --- matches any value @@ -62,19 +62,19 @@ LL | _ => {} | ^ unreachable pattern error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:65:9 + --> $DIR/consts-opaque.rs:61:9 | LL | BAR => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:67:9 + --> $DIR/consts-opaque.rs:63:9 | LL | Bar => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:69:9 + --> $DIR/consts-opaque.rs:65:9 | LL | Bar => {} // should not be emitting unreachable warning | --- matches any value @@ -83,76 +83,88 @@ LL | _ => {} | ^ unreachable pattern error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:74:9 + --> $DIR/consts-opaque.rs:70:9 | LL | BAR => {} | ^^^ error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:76:9 + --> $DIR/consts-opaque.rs:72:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:76:9 + --> $DIR/consts-opaque.rs:72:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:79:9 + --> $DIR/consts-opaque.rs:75:9 | LL | _ => {} // should not be emitting unreachable warning | ^ error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:84:9 + --> $DIR/consts-opaque.rs:80:9 | LL | BAZ => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:86:9 + --> $DIR/consts-opaque.rs:82:9 | LL | Baz::Baz1 => {} // should not be emitting unreachable warning | ^^^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:88:9 + --> $DIR/consts-opaque.rs:84:9 | LL | _ => {} | ^ error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:94:9 + --> $DIR/consts-opaque.rs:90:9 | LL | BAZ => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:96:9 + --> $DIR/consts-opaque.rs:92:9 | LL | _ => {} | ^ error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:101:9 + --> $DIR/consts-opaque.rs:97:9 | LL | BAZ => {} | ^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:103:9 + --> $DIR/consts-opaque.rs:99:9 | LL | Baz::Baz2 => {} // should not be emitting unreachable warning | ^^^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:105:9 + --> $DIR/consts-opaque.rs:101:9 | LL | _ => {} // should not be emitting unreachable warning | ^ -error: aborting due to 22 previous errors; 1 warning emitted +error: unreachable pattern + --> $DIR/consts-opaque.rs:127:9 + | +LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:141:9 + | +LL | WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer + | ^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted diff --git a/src/test/ui/pattern/deny-irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs similarity index 100% rename from src/test/ui/pattern/deny-irrefutable-let-patterns.rs rename to src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs diff --git a/src/test/ui/pattern/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr similarity index 100% rename from src/test/ui/pattern/deny-irrefutable-let-patterns.stderr rename to src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs deleted file mode 100644 index 78cc0d28fb..0000000000 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs +++ /dev/null @@ -1,172 +0,0 @@ -#![feature(precise_pointer_size_matching)] -#![feature(exclusive_range_pattern)] -#![deny(unreachable_patterns)] -#![deny(overlapping_patterns)] - -use std::{char, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128}; - -fn main() { - let x: u8 = 0; - - // A single range covering the entire domain. - match x { - 0 ..= 255 => {} // ok - } - - // A combination of ranges and values. - // These are currently allowed to be overlapping. - match x { - 0 ..= 32 => {} - 33 => {} - 34 .. 128 => {} - 100 ..= 200 => {} - 200 => {} //~ ERROR unreachable pattern - 201 ..= 255 => {} - } - - // An incomplete set of values. - match x { //~ ERROR non-exhaustive patterns - 0 .. 128 => {} - } - - // A more incomplete set of values. - match x { //~ ERROR non-exhaustive patterns - 0 ..= 10 => {} - 20 ..= 30 => {} - 35 => {} - 70 .. 255 => {} - } - - let x: i8 = 0; - match x { //~ ERROR non-exhaustive patterns - -7 => {} - -5..=120 => {} - -2..=20 => {} - //~^ ERROR unreachable pattern - 125 => {} - } - - // Let's test other types too! - let c: char = '\u{0}'; - match c { - '\u{0}' ..= char::MAX => {} // ok - } - - // We can actually get away with just covering the - // following two ranges, which correspond to all - // valid Unicode Scalar Values. - match c { - '\u{0000}' ..= '\u{D7FF}' => {} - '\u{E000}' ..= '\u{10_FFFF}' => {} - } - - match 0u16 { - 0 ..= u16::MAX => {} // ok - } - - match 0u32 { - 0 ..= u32::MAX => {} // ok - } - - match 0u64 { - 0 ..= u64::MAX => {} // ok - } - - match 0u128 { - 0 ..= u128::MAX => {} // ok - } - - match 0i8 { - -128 ..= 127 => {} // ok - } - - match 0i8 { //~ ERROR non-exhaustive patterns - -127 ..= 127 => {} - } - - match 0i16 { - i16::MIN ..= i16::MAX => {} // ok - } - - match 0i16 { //~ ERROR non-exhaustive patterns - i16::MIN ..= -1 => {} - 1 ..= i16::MAX => {} - } - - match 0i32 { - i32::MIN ..= i32::MAX => {} // ok - } - - match 0i64 { - i64::MIN ..= i64::MAX => {} // ok - } - - match 0i128 { - i128::MIN ..= i128::MAX => {} // ok - } - - // Make sure that guards don't factor into the exhaustiveness checks. - match 0u8 { //~ ERROR non-exhaustive patterns - 0 .. 128 => {} - 128 ..= 255 if true => {} - } - - match 0u8 { - 0 .. 128 => {} - 128 ..= 255 if false => {} - 128 ..= 255 => {} // ok, because previous arm was guarded - } - - // Now things start getting a bit more interesting. Testing products! - match (0u8, Some(())) { //~ ERROR non-exhaustive patterns - (1, _) => {} - (_, None) => {} - } - - match (0u8, true) { //~ ERROR non-exhaustive patterns - (0 ..= 125, false) => {} - (128 ..= 255, false) => {} - (0 ..= 255, true) => {} - } - - match (0u8, true) { // ok - (0 ..= 125, false) => {} - (128 ..= 255, false) => {} - (0 ..= 255, true) => {} - (125 .. 128, false) => {} - } - - match 0u8 { - 0 .. 2 => {} - 1 ..= 2 => {} //~ ERROR multiple patterns covering the same range - _ => {} - } - - const LIM: u128 = u128::MAX - 1; - match 0u128 { //~ ERROR non-exhaustive patterns - 0 ..= LIM => {} - } - - match 0u128 { //~ ERROR non-exhaustive patterns - 0 ..= 4 => {} - } - - match 0u128 { //~ ERROR non-exhaustive patterns - 4 ..= u128::MAX => {} - } - - const FOO: i32 = 42; - const BAR: &i32 = &42; - match &0 { - &42 => {} - &FOO => {} //~ ERROR unreachable pattern - BAR => {} //~ ERROR unreachable pattern - _ => {} - } - - // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933 - match &0 { - BAR => {} // ok - _ => {} - } -} diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr deleted file mode 100644 index 9f076c50a8..0000000000 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr +++ /dev/null @@ -1,146 +0,0 @@ -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:23:9 - | -LL | 200 => {} - | ^^^ - | -note: the lint level is defined here - --> $DIR/exhaustive_integer_patterns.rs:3:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:28:11 - | -LL | match x { - | ^ pattern `128_u8..=u8::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u8` - -error[E0004]: non-exhaustive patterns: `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered - --> $DIR/exhaustive_integer_patterns.rs:33:11 - | -LL | match x { - | ^ patterns `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u8` - -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:44:9 - | -LL | -2..=20 => {} - | ^^^^^^^ - -error[E0004]: non-exhaustive patterns: `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered - --> $DIR/exhaustive_integer_patterns.rs:41:11 - | -LL | match x { - | ^ patterns `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `i8` - -error[E0004]: non-exhaustive patterns: `i8::MIN` not covered - --> $DIR/exhaustive_integer_patterns.rs:83:11 - | -LL | match 0i8 { - | ^^^ pattern `i8::MIN` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `i8` - -error[E0004]: non-exhaustive patterns: `0_i16` not covered - --> $DIR/exhaustive_integer_patterns.rs:91:11 - | -LL | match 0i16 { - | ^^^^ pattern `0_i16` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `i16` - -error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:109:11 - | -LL | match 0u8 { - | ^^^ pattern `128_u8..=u8::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u8` - -error[E0004]: non-exhaustive patterns: `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered - --> $DIR/exhaustive_integer_patterns.rs:121:11 - | -LL | match (0u8, Some(())) { - | ^^^^^^^^^^^^^^^ patterns `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(u8, Option<()>)` - -error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered - --> $DIR/exhaustive_integer_patterns.rs:126:11 - | -LL | match (0u8, true) { - | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `(u8, bool)` - -error: multiple patterns covering the same range - --> $DIR/exhaustive_integer_patterns.rs:141:9 - | -LL | 0 .. 2 => {} - | ------ this range overlaps on `1_u8` -LL | 1 ..= 2 => {} - | ^^^^^^^ overlapping patterns - | -note: the lint level is defined here - --> $DIR/exhaustive_integer_patterns.rs:4:9 - | -LL | #![deny(overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0004]: non-exhaustive patterns: `u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:146:11 - | -LL | match 0u128 { - | ^^^^^ pattern `u128::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u128` - -error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered - --> $DIR/exhaustive_integer_patterns.rs:150:11 - | -LL | match 0u128 { - | ^^^^^ pattern `5_u128..=u128::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u128` - -error[E0004]: non-exhaustive patterns: `0_u128..=3_u128` not covered - --> $DIR/exhaustive_integer_patterns.rs:154:11 - | -LL | match 0u128 { - | ^^^^^ pattern `0_u128..=3_u128` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `u128` - -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:162:9 - | -LL | &FOO => {} - | ^^^^ - -error: unreachable pattern - --> $DIR/exhaustive_integer_patterns.rs:163:9 - | -LL | BAR => {} - | ^^^ - -error: aborting due to 16 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.rs b/src/test/ui/pattern/usefulness/floats.rs similarity index 66% rename from src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.rs rename to src/test/ui/pattern/usefulness/floats.rs index 588fecbf10..095f5ac9a8 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.rs +++ b/src/test/ui/pattern/usefulness/floats.rs @@ -10,4 +10,10 @@ fn main() { match 0.0 { //~ ERROR non-exhaustive patterns 0.0..=1.0 => {} } + + match 1.0f64 { + 0.01f64 ..= 6.5f64 => {} + 0.02f64 => {} //~ ERROR unreachable pattern + _ => {} + }; } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr b/src/test/ui/pattern/usefulness/floats.stderr similarity index 53% rename from src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr rename to src/test/ui/pattern/usefulness/floats.stderr index 4835fa86cc..464bfbdb2c 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr +++ b/src/test/ui/pattern/usefulness/floats.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-float-range-match.rs:10:11 + --> $DIR/floats.rs:10:11 | LL | match 0.0 { | ^^^ pattern `_` not covered @@ -7,6 +7,18 @@ LL | match 0.0 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `f64` -error: aborting due to previous error +error: unreachable pattern + --> $DIR/floats.rs:16:7 + | +LL | 0.02f64 => {} + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/floats.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/guards-not-exhaustive.rs b/src/test/ui/pattern/usefulness/guards-not-exhaustive.rs deleted file mode 100644 index b74f162c0c..0000000000 --- a/src/test/ui/pattern/usefulness/guards-not-exhaustive.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-pass - -#![allow(non_snake_case)] - -#[derive(Copy, Clone)] -enum Q { R(Option) } - -fn xyzzy(q: Q) -> usize { - match q { - Q::R(S) if S.is_some() => { 0 } - _ => 1 - } -} - - -pub fn main() { - assert_eq!(xyzzy(Q::R(Some(5))), 0); -} diff --git a/src/test/ui/pattern/usefulness/guards.rs b/src/test/ui/pattern/usefulness/guards.rs new file mode 100644 index 0000000000..b15440cf60 --- /dev/null +++ b/src/test/ui/pattern/usefulness/guards.rs @@ -0,0 +1,22 @@ +#![feature(exclusive_range_pattern)] +#![deny(unreachable_patterns)] + +enum Q { R(Option) } + +pub fn main() { + match Q::R(None) { + Q::R(S) if S.is_some() => {} + _ => {} + } + + match 0u8 { //~ ERROR non-exhaustive patterns + 0 .. 128 => {} + 128 ..= 255 if true => {} + } + + match 0u8 { + 0 .. 128 => {} + 128 ..= 255 if false => {} + 128 ..= 255 => {} // ok, because previous arm was guarded + } +} diff --git a/src/test/ui/pattern/usefulness/guards.stderr b/src/test/ui/pattern/usefulness/guards.stderr new file mode 100644 index 0000000000..61f7facb33 --- /dev/null +++ b/src/test/ui/pattern/usefulness/guards.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered + --> $DIR/guards.rs:12:11 + | +LL | match 0u8 { + | ^^^ pattern `128_u8..=u8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs new file mode 100644 index 0000000000..ef573db821 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.rs @@ -0,0 +1,102 @@ +#![feature(exclusive_range_pattern)] +#![feature(assoc_char_consts)] +#![allow(overlapping_range_endpoints)] +#![deny(unreachable_patterns)] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +macro_rules! test_int { + ($s:expr, $min:path, $max:path) => { + m!($s, $min..=$max); + m!($s, $min..5 | 5..=$max); + m!($s, $min..=4 | 5..=$max); + m!($s, $min..$max | $max); + m!(($s, true), ($min..5, true) | (5..=$max, true) | ($min..=$max, false)); + } +} + +fn main() { + test_int!(0u8, u8::MIN, u8::MAX); + test_int!(0u16, u16::MIN, u16::MAX); + test_int!(0u32, u32::MIN, u32::MAX); + test_int!(0u64, u64::MIN, u64::MAX); + test_int!(0u128, u128::MIN, u128::MAX); + + test_int!(0i8, i8::MIN, i8::MAX); + test_int!(0i16, i16::MIN, i16::MAX); + test_int!(0i32, i32::MIN, i32::MAX); + test_int!(0i64, i64::MIN, i64::MAX); + test_int!(0i128, i128::MIN, i128::MAX); + + m!('a', '\u{0}'..=char::MAX); + m!('a', '\u{0}'..='\u{10_FFFF}'); + // We can get away with just covering the following two ranges, which correspond to all valid + // Unicode Scalar Values. + m!('a', '\u{0}'..='\u{D7FF}' | '\u{E000}'..=char::MAX); + m!('a', '\u{0}'..'\u{D7FF}' | '\u{D7FF}' | '\u{E000}'..=char::MAX); + + let 0..=255 = 0u8; + let -128..=127 = 0i8; + let -2147483648..=2147483647 = 0i32; + let '\u{0000}'..='\u{10FFFF}' = 'v'; + + // Almost exhaustive + m!(0u8, 0..255); //~ ERROR non-exhaustive patterns + m!(0u8, 0..=254); //~ ERROR non-exhaustive patterns + m!(0u8, 1..=255); //~ ERROR non-exhaustive patterns + m!(0u8, 0..42 | 43..=255); //~ ERROR non-exhaustive patterns + m!(0i8, -128..127); //~ ERROR non-exhaustive patterns + m!(0i8, -128..=126); //~ ERROR non-exhaustive patterns + m!(0i8, -127..=127); //~ ERROR non-exhaustive patterns + match 0i8 { //~ ERROR non-exhaustive patterns + i8::MIN ..= -1 => {} + 1 ..= i8::MAX => {} + } + const ALMOST_MAX: u128 = u128::MAX - 1; + m!(0u128, 0..=ALMOST_MAX); //~ ERROR non-exhaustive patterns + m!(0u128, 0..=4); //~ ERROR non-exhaustive patterns + m!(0u128, 1..=u128::MAX); //~ ERROR non-exhaustive patterns + + // More complicatedly (non-)exhaustive + match 0u8 { + 0 ..= 30 => {} + 20 ..= 70 => {} + 50 ..= 255 => {} + } + match (0u8, true) { //~ ERROR non-exhaustive patterns + (0 ..= 125, false) => {} + (128 ..= 255, false) => {} + (0 ..= 255, true) => {} + } + match (0u8, true) { // ok + (0 ..= 125, false) => {} + (128 ..= 255, false) => {} + (0 ..= 255, true) => {} + (125 .. 128, false) => {} + } + match (true, 0u8) { + (true, 0 ..= 255) => {} + (false, 0 ..= 125) => {} + (false, 128 ..= 255) => {} + (false, 125 .. 128) => {} + } + match Some(0u8) { + None => {} + Some(0 ..= 125) => {} + Some(128 ..= 255) => {} + Some(125 .. 128) => {} + } + const FOO: u8 = 41; + const BAR: &u8 = &42; + match &0u8 { + 0..41 => {} + &FOO => {} + BAR => {} + 43..=255 => {} + } + +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr new file mode 100644 index 0000000000..b144037549 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr @@ -0,0 +1,111 @@ +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered + --> $DIR/exhaustiveness.rs:48:8 + | +LL | m!(0u8, 0..255); + | ^^^ pattern `u8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered + --> $DIR/exhaustiveness.rs:49:8 + | +LL | m!(0u8, 0..=254); + | ^^^ pattern `u8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `0_u8` not covered + --> $DIR/exhaustiveness.rs:50:8 + | +LL | m!(0u8, 1..=255); + | ^^^ pattern `0_u8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `42_u8` not covered + --> $DIR/exhaustiveness.rs:51:8 + | +LL | m!(0u8, 0..42 | 43..=255); + | ^^^ pattern `42_u8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered + --> $DIR/exhaustiveness.rs:52:8 + | +LL | m!(0i8, -128..127); + | ^^^ pattern `i8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered + --> $DIR/exhaustiveness.rs:53:8 + | +LL | m!(0i8, -128..=126); + | ^^^ pattern `i8::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `i8::MIN` not covered + --> $DIR/exhaustiveness.rs:54:8 + | +LL | m!(0i8, -127..=127); + | ^^^ pattern `i8::MIN` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `0_i8` not covered + --> $DIR/exhaustiveness.rs:55:11 + | +LL | match 0i8 { + | ^^^ pattern `0_i8` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `i8` + +error[E0004]: non-exhaustive patterns: `u128::MAX` not covered + --> $DIR/exhaustiveness.rs:60:8 + | +LL | m!(0u128, 0..=ALMOST_MAX); + | ^^^^^ pattern `u128::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u128` + +error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered + --> $DIR/exhaustiveness.rs:61:8 + | +LL | m!(0u128, 0..=4); + | ^^^^^ pattern `5_u128..=u128::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u128` + +error[E0004]: non-exhaustive patterns: `0_u128` not covered + --> $DIR/exhaustiveness.rs:62:8 + | +LL | m!(0u128, 1..=u128::MAX); + | ^^^^^ pattern `0_u128` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u128` + +error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered + --> $DIR/exhaustiveness.rs:70:11 + | +LL | match (0u8, true) { + | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(u8, bool)` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs new file mode 100644 index 0000000000..5ea92b0708 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs @@ -0,0 +1,59 @@ +#![feature(exclusive_range_pattern)] +#![deny(overlapping_range_endpoints)] + +macro_rules! m { + ($s:expr, $t1:pat, $t2:pat) => { + match $s { + $t1 => {} + $t2 => {} + _ => {} + } + } +} + +fn main() { + m!(0u8, 20..=30, 30..=40); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20..=30, 31..=40); + m!(0u8, 20..=30, 29..=40); + m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20.. 30, 28..=40); + m!(0u8, 20.. 30, 30..=40); + m!(0u8, 20..=30, 30..=30); + m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20..=30, 29..=30); + m!(0u8, 20..=30, 20..=20); + m!(0u8, 20..=30, 20..=21); + m!(0u8, 20..=30, 19..=20); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20..=30, 20); + m!(0u8, 20..=30, 25); + m!(0u8, 20..=30, 30); + m!(0u8, 20.. 30, 29); + m!(0u8, 20, 20..=30); + m!(0u8, 25, 20..=30); + m!(0u8, 30, 20..=30); + + match 0u8 { + 0..=10 => {} + 20..=30 => {} + 10..=20 => {} //~ ERROR multiple patterns overlap on their endpoints + _ => {} + } + match (0u8, true) { + (0..=10, true) => {} + (10..20, true) => {} // not detected + (10..20, false) => {} + _ => {} + } + match (true, 0u8) { + (true, 0..=10) => {} + (true, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints + (false, 10..20) => {} + _ => {} + } + match Some(0u8) { + Some(0..=10) => {} + Some(10..20) => {} //~ ERROR multiple patterns overlap on their endpoints + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr new file mode 100644 index 0000000000..24c0419e1d --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -0,0 +1,89 @@ +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:15:22 + | +LL | m!(0u8, 20..=30, 30..=40); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `30_u8`... + | +note: the lint level is defined here + --> $DIR/overlapping_range_endpoints.rs:2:9 + | +LL | #![deny(overlapping_range_endpoints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:16:22 + | +LL | m!(0u8, 30..=40, 20..=30); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `30_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:19:22 + | +LL | m!(0u8, 20.. 30, 29..=40); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `29_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:23:22 + | +LL | m!(0u8, 20..=30, 30..=31); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `30_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:27:22 + | +LL | m!(0u8, 20..=30, 19..=20); + | ------- ^^^^^^^ ... with this range + | | + | this range overlaps on `20_u8`... + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:39:9 + | +LL | 0..=10 => {} + | ------ this range overlaps on `10_u8`... +LL | 20..=30 => {} + | ------- this range overlaps on `20_u8`... +LL | 10..=20 => {} + | ^^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:50:16 + | +LL | (true, 0..=10) => {} + | ------ this range overlaps on `10_u8`... +LL | (true, 10..20) => {} + | ^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:56:14 + | +LL | Some(0..=10) => {} + | ------ this range overlaps on `10_u8`... +LL | Some(10..20) => {} + | ^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs new file mode 100644 index 0000000000..6173053cc4 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs @@ -0,0 +1,38 @@ +#![feature(precise_pointer_size_matching)] +#![feature(exclusive_range_pattern)] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +fn main() { + match 0usize { + 0 ..= usize::MAX => {} + } + + match 0isize { + isize::MIN ..= isize::MAX => {} + } + + m!(0usize, 0..=usize::MAX); + m!(0usize, 0..5 | 5..=usize::MAX); + m!(0usize, 0..usize::MAX | usize::MAX); + m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + + m!(0isize, isize::MIN..=isize::MAX); + m!(0isize, isize::MIN..5 | 5..=isize::MAX); + m!(0isize, isize::MIN..isize::MAX | isize::MAX); + m!((0isize, true), (isize::MIN..5, true) + | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)); + + match 0isize { + isize::MIN ..= -1 => {} + 0 => {} + 1 ..= isize::MAX => {} + } + + match 7usize {} + //~^ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr new file mode 100644 index 0000000000..0b3c65166e --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr @@ -0,0 +1,12 @@ +error[E0004]: non-exhaustive patterns: type `usize` is non-empty + --> $DIR/pointer-sized-int-allow.rs:36:11 + | +LL | match 7usize {} + | ^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs new file mode 100644 index 0000000000..9292f22e09 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs @@ -0,0 +1,48 @@ +#![feature(exclusive_range_pattern)] + +macro_rules! m { + ($s:expr, $($t:tt)+) => { + match $s { $($t)+ => {} } + } +} + +fn main() { + match 0usize { + //~^ ERROR non-exhaustive patterns + 0 ..= usize::MAX => {} + } + + match 0isize { + //~^ ERROR non-exhaustive patterns + isize::MIN ..= isize::MAX => {} + } + + m!(0usize, 0..=usize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0usize, 0..5 | 5..=usize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0usize, 0..usize::MAX | usize::MAX); + //~^ ERROR non-exhaustive patterns + m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + //~^ ERROR non-exhaustive patterns + + m!(0isize, isize::MIN..=isize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0isize, isize::MIN..5 | 5..=isize::MAX); + //~^ ERROR non-exhaustive patterns + m!(0isize, isize::MIN..isize::MAX | isize::MAX); + //~^ ERROR non-exhaustive patterns + m!((0isize, true), (isize::MIN..5, true) + | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)); + //~^^ ERROR non-exhaustive patterns + + match 0isize { + //~^ ERROR non-exhaustive patterns + isize::MIN ..= -1 => {} + 0 => {} + 1 ..= isize::MAX => {} + } + + match 7usize {} + //~^ ERROR non-exhaustive patterns +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr new file mode 100644 index 0000000000..9d566b0e77 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr @@ -0,0 +1,129 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:10:11 + | +LL | match 0usize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:15:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:20:8 + | +LL | m!(0usize, 0..=usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:22:8 + | +LL | m!(0usize, 0..5 | 5..=usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:24:8 + | +LL | m!(0usize, 0..usize::MAX | usize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching + +error[E0004]: non-exhaustive patterns: `(_, _)` not covered + --> $DIR/pointer-sized-int-deny.rs:26:8 + | +LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); + | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(usize, bool)` + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:29:8 + | +LL | m!(0isize, isize::MIN..=isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:31:8 + | +LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:33:8 + | +LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX); + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: `(_, _)` not covered + --> $DIR/pointer-sized-int-deny.rs:35:8 + | +LL | m!((0isize, true), (isize::MIN..5, true) + | ^^^^^^^^^^^^^^ pattern `(_, _)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `(isize, bool)` + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/pointer-sized-int-deny.rs:39:11 + | +LL | match 0isize { + | ^^^^^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `isize` + = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching + +error[E0004]: non-exhaustive patterns: type `usize` is non-empty + --> $DIR/pointer-sized-int-deny.rs:46:11 + | +LL | match 7usize {} + | ^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs similarity index 56% rename from src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs rename to src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs index 0c52876e21..a2aa655ca5 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs +++ b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs @@ -1,23 +1,18 @@ -use std::{usize, isize}; - +// This tests that the lint message explains the reason for the error. fn main() { match 0usize { - //~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns: `_` not covered //~| NOTE pattern `_` not covered //~| NOTE the matched value is of type `usize` //~| NOTE `usize` does not have a fixed maximum value - 0 ..= usize::MAX => {} + 0..=usize::MAX => {} } match 0isize { - //~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns: `_` not covered //~| NOTE pattern `_` not covered //~| NOTE the matched value is of type `isize` //~| NOTE `isize` does not have a fixed maximum value - isize::MIN ..= isize::MAX => {} + isize::MIN..=isize::MAX => {} } - - match 7usize {} - //~^ ERROR non-exhaustive patterns - //~| NOTE the matched value is of type `usize` } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr similarity index 68% rename from src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr rename to src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr index d0aa452fd3..37e73a68f2 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:4:11 + --> $DIR/precise_pointer_matching-message.rs:3:11 | LL | match 0usize { | ^^^^^^ pattern `_` not covered @@ -10,7 +10,7 @@ LL | match 0usize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:12:11 + --> $DIR/precise_pointer_matching-message.rs:11:11 | LL | match 0isize { | ^^^^^^ pattern `_` not covered @@ -20,15 +20,6 @@ LL | match 0isize { = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching -error[E0004]: non-exhaustive patterns: type `usize` is non-empty - --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:20:11 - | -LL | match 7usize {} - | ^^^^^^ - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `usize` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs new file mode 100644 index 0000000000..fb4d59b057 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs @@ -0,0 +1,113 @@ +#![feature(exclusive_range_pattern)] +#![allow(overlapping_range_endpoints)] +#![deny(unreachable_patterns)] + +macro_rules! m { + ($s:expr, $t1:pat, $t2:pat) => { + match $s { + $t1 => {} + $t2 => {} + _ => {} + } + } +} + +fn main() { + m!(0u8, 42, 41); + m!(0u8, 42, 42); //~ ERROR unreachable pattern + m!(0u8, 42, 43); + + m!(0u8, 20..=30, 19); + m!(0u8, 20..=30, 20); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 21); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 25); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 29); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 31); + m!(0u8, 20..30, 19); + m!(0u8, 20..30, 20); //~ ERROR unreachable pattern + m!(0u8, 20..30, 21); //~ ERROR unreachable pattern + m!(0u8, 20..30, 25); //~ ERROR unreachable pattern + m!(0u8, 20..30, 29); //~ ERROR unreachable pattern + m!(0u8, 20..30, 30); + m!(0u8, 20..30, 31); + + m!(0u8, 20..=30, 20..=30); //~ ERROR unreachable pattern + m!(0u8, 20.. 30, 20.. 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20.. 30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 19..=30); + m!(0u8, 20..=30, 21..=30); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20..=29); //~ ERROR unreachable pattern + m!(0u8, 20..=30, 20..=31); + m!('a', 'A'..='z', 'a'..='z'); //~ ERROR unreachable pattern + + match 0u8 { + 5 => {}, + 6 => {}, + 7 => {}, + 8 => {}, + 5..=8 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10..20 => {}, + 5..15 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10..20 => {}, + 20..30 => {}, + 5..25 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0u8 { + 0..10 => {}, + 10 => {}, + 11..=23 => {}, + 19..30 => {}, + 5..25 => {}, //~ ERROR unreachable pattern + _ => {}, + } + match 0usize { + 0..10 => {}, + 10..20 => {}, + 5..15 => {}, //~ ERROR unreachable pattern + _ => {}, + } + // Chars between '\u{D7FF}' and '\u{E000}' are invalid even though ranges that contain them are + // allowed. + match 'a' { + _ => {}, + '\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern + } + match 'a' { + '\u{0}'..='\u{D7FF}' => {}, + '\u{E000}'..='\u{10_FFFF}' => {}, + '\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable + } + + match (0u8, true) { + (0..=255, false) => {} + (0..=255, true) => {} // ok + } + match (true, 0u8) { + (false, 0..=255) => {} + (true, 0..=255) => {} // ok + } + + const FOO: i32 = 42; + const BAR: &i32 = &42; + match &0 { + &42 => {} + &FOO => {} //~ ERROR unreachable pattern + BAR => {} //~ ERROR unreachable pattern + _ => {} + } + // Regression test, see https://github.com/rust-lang/rust/pull/66326#issuecomment-552889933 + match &0 { + BAR => {} // ok + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr new file mode 100644 index 0000000000..9a02fac6a7 --- /dev/null +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -0,0 +1,152 @@ +error: unreachable pattern + --> $DIR/reachability.rs:17:17 + | +LL | m!(0u8, 42, 42); + | ^^ + | +note: the lint level is defined here + --> $DIR/reachability.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:21:22 + | +LL | m!(0u8, 20..=30, 20); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:22:22 + | +LL | m!(0u8, 20..=30, 21); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:23:22 + | +LL | m!(0u8, 20..=30, 25); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:24:22 + | +LL | m!(0u8, 20..=30, 29); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:25:22 + | +LL | m!(0u8, 20..=30, 30); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:28:21 + | +LL | m!(0u8, 20..30, 20); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:29:21 + | +LL | m!(0u8, 20..30, 21); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:30:21 + | +LL | m!(0u8, 20..30, 25); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:31:21 + | +LL | m!(0u8, 20..30, 29); + | ^^ + +error: unreachable pattern + --> $DIR/reachability.rs:35:22 + | +LL | m!(0u8, 20..=30, 20..=30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:36:22 + | +LL | m!(0u8, 20.. 30, 20.. 30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:37:22 + | +LL | m!(0u8, 20..=30, 20.. 30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:39:22 + | +LL | m!(0u8, 20..=30, 21..=30); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:40:22 + | +LL | m!(0u8, 20..=30, 20..=29); + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:42:24 + | +LL | m!('a', 'A'..='z', 'a'..='z'); + | ^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:49:9 + | +LL | 5..=8 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:55:9 + | +LL | 5..15 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:62:9 + | +LL | 5..25 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:70:9 + | +LL | 5..25 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:76:9 + | +LL | 5..15 => {}, + | ^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:83:9 + | +LL | '\u{D7FF}'..='\u{E000}' => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:104:9 + | +LL | &FOO => {} + | ^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:105:9 + | +LL | BAR => {} + | ^^^ + +error: aborting due to 24 previous errors + diff --git a/src/test/ui/pattern/irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs similarity index 100% rename from src/test/ui/pattern/irrefutable-let-patterns.rs rename to src/test/ui/pattern/usefulness/irrefutable-let-patterns.rs diff --git a/src/test/ui/issues/issue-12116.rs b/src/test/ui/pattern/usefulness/issue-12116.rs similarity index 100% rename from src/test/ui/issues/issue-12116.rs rename to src/test/ui/pattern/usefulness/issue-12116.rs diff --git a/src/test/ui/issues/issue-12116.stderr b/src/test/ui/pattern/usefulness/issue-12116.stderr similarity index 100% rename from src/test/ui/issues/issue-12116.stderr rename to src/test/ui/pattern/usefulness/issue-12116.stderr diff --git a/src/test/ui/issues/issue-12369.rs b/src/test/ui/pattern/usefulness/issue-12369.rs similarity index 100% rename from src/test/ui/issues/issue-12369.rs rename to src/test/ui/pattern/usefulness/issue-12369.rs diff --git a/src/test/ui/issues/issue-12369.stderr b/src/test/ui/pattern/usefulness/issue-12369.stderr similarity index 100% rename from src/test/ui/issues/issue-12369.stderr rename to src/test/ui/pattern/usefulness/issue-12369.stderr diff --git a/src/test/ui/issues/issue-13727.rs b/src/test/ui/pattern/usefulness/issue-13727.rs similarity index 100% rename from src/test/ui/issues/issue-13727.rs rename to src/test/ui/pattern/usefulness/issue-13727.rs diff --git a/src/test/ui/issues/issue-13727.stderr b/src/test/ui/pattern/usefulness/issue-13727.stderr similarity index 100% rename from src/test/ui/issues/issue-13727.stderr rename to src/test/ui/pattern/usefulness/issue-13727.stderr diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs new file mode 100644 index 0000000000..d2b72a86b7 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-15129.rs @@ -0,0 +1,17 @@ +pub enum T { + T1(()), + T2(()), +} + +pub enum V { + V1(isize), + V2(bool), +} + +fn main() { + match (T::T1(()), V::V2(true)) { + //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered + (T::T1(()), V::V1(i)) => (), + (T::T2(()), V::V2(b)) => (), + } +} diff --git a/src/test/ui/issues/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr similarity index 64% rename from src/test/ui/issues/issue-15129.stderr rename to src/test/ui/pattern/usefulness/issue-15129.stderr index aa4434e72b..79a7724093 100644 --- a/src/test/ui/issues/issue-15129.stderr +++ b/src/test/ui/pattern/usefulness/issue-15129.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered +error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered --> $DIR/issue-15129.rs:12:11 | LL | match (T::T1(()), V::V2(true)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(T, V)` diff --git a/src/test/ui/pattern/usefulness/issue-2111.rs b/src/test/ui/pattern/usefulness/issue-2111.rs new file mode 100644 index 0000000000..d27beaeffd --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-2111.rs @@ -0,0 +1,11 @@ +fn foo(a: Option, b: Option) { + match (a, b) { + //~^ ERROR: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered + (Some(a), Some(b)) if a == b => {} + (Some(_), None) | (None, Some(_)) => {} + } +} + +fn main() { + foo(None, None); +} diff --git a/src/test/ui/issues/issue-2111.stderr b/src/test/ui/pattern/usefulness/issue-2111.stderr similarity index 56% rename from src/test/ui/issues/issue-2111.stderr rename to src/test/ui/pattern/usefulness/issue-2111.stderr index a39a479e07..60d9b8514b 100644 --- a/src/test/ui/issues/issue-2111.stderr +++ b/src/test/ui/pattern/usefulness/issue-2111.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `(None, None)` not covered - --> $DIR/issue-2111.rs:2:9 +error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered + --> $DIR/issue-2111.rs:2:11 | -LL | match (a,b) { - | ^^^^^ pattern `(None, None)` not covered +LL | match (a, b) { + | ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(Option, Option)` diff --git a/src/test/ui/issues/issue-30240-b.rs b/src/test/ui/pattern/usefulness/issue-30240-b.rs similarity index 100% rename from src/test/ui/issues/issue-30240-b.rs rename to src/test/ui/pattern/usefulness/issue-30240-b.rs diff --git a/src/test/ui/issues/issue-30240-b.stderr b/src/test/ui/pattern/usefulness/issue-30240-b.stderr similarity index 100% rename from src/test/ui/issues/issue-30240-b.stderr rename to src/test/ui/pattern/usefulness/issue-30240-b.stderr diff --git a/src/test/ui/issues/issue-30240-rpass.rs b/src/test/ui/pattern/usefulness/issue-30240-rpass.rs similarity index 100% rename from src/test/ui/issues/issue-30240-rpass.rs rename to src/test/ui/pattern/usefulness/issue-30240-rpass.rs diff --git a/src/test/ui/issues/issue-30240.rs b/src/test/ui/pattern/usefulness/issue-30240.rs similarity index 100% rename from src/test/ui/issues/issue-30240.rs rename to src/test/ui/pattern/usefulness/issue-30240.rs diff --git a/src/test/ui/issues/issue-30240.stderr b/src/test/ui/pattern/usefulness/issue-30240.stderr similarity index 100% rename from src/test/ui/issues/issue-30240.stderr rename to src/test/ui/pattern/usefulness/issue-30240.stderr diff --git a/src/test/ui/issues/issue-3096-1.rs b/src/test/ui/pattern/usefulness/issue-3096-1.rs similarity index 100% rename from src/test/ui/issues/issue-3096-1.rs rename to src/test/ui/pattern/usefulness/issue-3096-1.rs diff --git a/src/test/ui/issues/issue-3096-1.stderr b/src/test/ui/pattern/usefulness/issue-3096-1.stderr similarity index 100% rename from src/test/ui/issues/issue-3096-1.stderr rename to src/test/ui/pattern/usefulness/issue-3096-1.stderr diff --git a/src/test/ui/issues/issue-3096-2.rs b/src/test/ui/pattern/usefulness/issue-3096-2.rs similarity index 100% rename from src/test/ui/issues/issue-3096-2.rs rename to src/test/ui/pattern/usefulness/issue-3096-2.rs diff --git a/src/test/ui/issues/issue-3096-2.stderr b/src/test/ui/pattern/usefulness/issue-3096-2.stderr similarity index 100% rename from src/test/ui/issues/issue-3096-2.stderr rename to src/test/ui/pattern/usefulness/issue-3096-2.stderr diff --git a/src/test/ui/issues/issue-31221.rs b/src/test/ui/pattern/usefulness/issue-31221.rs similarity index 100% rename from src/test/ui/issues/issue-31221.rs rename to src/test/ui/pattern/usefulness/issue-31221.rs diff --git a/src/test/ui/issues/issue-31221.stderr b/src/test/ui/pattern/usefulness/issue-31221.stderr similarity index 100% rename from src/test/ui/issues/issue-31221.stderr rename to src/test/ui/pattern/usefulness/issue-31221.stderr diff --git a/src/test/ui/issues/issue-31561.rs b/src/test/ui/pattern/usefulness/issue-31561.rs similarity index 100% rename from src/test/ui/issues/issue-31561.rs rename to src/test/ui/pattern/usefulness/issue-31561.rs diff --git a/src/test/ui/issues/issue-31561.stderr b/src/test/ui/pattern/usefulness/issue-31561.stderr similarity index 100% rename from src/test/ui/issues/issue-31561.stderr rename to src/test/ui/pattern/usefulness/issue-31561.stderr diff --git a/src/test/ui/issues/issue-3601.rs b/src/test/ui/pattern/usefulness/issue-3601.rs similarity index 100% rename from src/test/ui/issues/issue-3601.rs rename to src/test/ui/pattern/usefulness/issue-3601.rs diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/pattern/usefulness/issue-3601.stderr similarity index 100% rename from src/test/ui/issues/issue-3601.stderr rename to src/test/ui/pattern/usefulness/issue-3601.stderr diff --git a/src/test/ui/issues/issue-39362.rs b/src/test/ui/pattern/usefulness/issue-39362.rs similarity index 100% rename from src/test/ui/issues/issue-39362.rs rename to src/test/ui/pattern/usefulness/issue-39362.rs diff --git a/src/test/ui/issues/issue-39362.stderr b/src/test/ui/pattern/usefulness/issue-39362.stderr similarity index 100% rename from src/test/ui/issues/issue-39362.stderr rename to src/test/ui/pattern/usefulness/issue-39362.stderr diff --git a/src/test/ui/missing/missing-items/issue-40221.rs b/src/test/ui/pattern/usefulness/issue-40221.rs similarity index 100% rename from src/test/ui/missing/missing-items/issue-40221.rs rename to src/test/ui/pattern/usefulness/issue-40221.rs diff --git a/src/test/ui/missing/missing-items/issue-40221.stderr b/src/test/ui/pattern/usefulness/issue-40221.stderr similarity index 100% rename from src/test/ui/missing/missing-items/issue-40221.stderr rename to src/test/ui/pattern/usefulness/issue-40221.stderr diff --git a/src/test/ui/issues/issue-4321.rs b/src/test/ui/pattern/usefulness/issue-4321.rs similarity index 100% rename from src/test/ui/issues/issue-4321.rs rename to src/test/ui/pattern/usefulness/issue-4321.rs diff --git a/src/test/ui/issues/issue-4321.stderr b/src/test/ui/pattern/usefulness/issue-4321.stderr similarity index 100% rename from src/test/ui/issues/issue-4321.stderr rename to src/test/ui/pattern/usefulness/issue-4321.stderr diff --git a/src/test/ui/pattern/usefulness/issue-43253.rs b/src/test/ui/pattern/usefulness/issue-43253.rs deleted file mode 100644 index 349ba11a7c..0000000000 --- a/src/test/ui/pattern/usefulness/issue-43253.rs +++ /dev/null @@ -1,47 +0,0 @@ -// check-pass -#![feature(exclusive_range_pattern)] -#![warn(unreachable_patterns)] -#![warn(overlapping_patterns)] - -fn main() { - // These cases should generate no warning. - match 10 { - 1..10 => {}, - 10 => {}, - _ => {}, - } - - match 10 { - 1..10 => {}, - 9..=10 => {}, //~ WARNING multiple patterns covering the same range - _ => {}, - } - - match 10 { - 1..10 => {}, - 10..=10 => {}, - _ => {}, - } - - // These cases should generate "unreachable pattern" warnings. - match 10 { - 1..10 => {}, - 9 => {}, //~ WARNING unreachable pattern - _ => {}, - } - - match 10 { - 1..10 => {}, - 8..=9 => {}, //~ WARNING unreachable pattern - _ => {}, - } - - match 10 { - 5..7 => {}, - 6 => {}, //~ WARNING unreachable pattern - 1..10 => {}, - 9..=9 => {}, //~ WARNING unreachable pattern - 6 => {}, //~ WARNING unreachable pattern - _ => {}, - } -} diff --git a/src/test/ui/pattern/usefulness/issue-43253.stderr b/src/test/ui/pattern/usefulness/issue-43253.stderr deleted file mode 100644 index 04feef1706..0000000000 --- a/src/test/ui/pattern/usefulness/issue-43253.stderr +++ /dev/null @@ -1,52 +0,0 @@ -warning: multiple patterns covering the same range - --> $DIR/issue-43253.rs:16:9 - | -LL | 1..10 => {}, - | ----- this range overlaps on `9_i32` -LL | 9..=10 => {}, - | ^^^^^^ overlapping patterns - | -note: the lint level is defined here - --> $DIR/issue-43253.rs:4:9 - | -LL | #![warn(overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:29:9 - | -LL | 9 => {}, - | ^ - | -note: the lint level is defined here - --> $DIR/issue-43253.rs:3:9 - | -LL | #![warn(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:35:9 - | -LL | 8..=9 => {}, - | ^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:41:9 - | -LL | 6 => {}, - | ^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:43:9 - | -LL | 9..=9 => {}, - | ^^^^^ - -warning: unreachable pattern - --> $DIR/issue-43253.rs:44:9 - | -LL | 6 => {}, - | ^ - -warning: 6 warnings emitted - diff --git a/src/test/ui/match/issue-50900.rs b/src/test/ui/pattern/usefulness/issue-50900.rs similarity index 100% rename from src/test/ui/match/issue-50900.rs rename to src/test/ui/pattern/usefulness/issue-50900.rs diff --git a/src/test/ui/match/issue-50900.stderr b/src/test/ui/pattern/usefulness/issue-50900.stderr similarity index 100% rename from src/test/ui/match/issue-50900.stderr rename to src/test/ui/pattern/usefulness/issue-50900.stderr diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs new file mode 100644 index 0000000000..9bccccca9c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-56379.rs @@ -0,0 +1,14 @@ +enum Foo { + A(bool), + B(bool), + C(bool), +} + +fn main() { + match Foo::A(true) { + //~^ ERROR non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered + Foo::A(true) => {} + Foo::B(true) => {} + Foo::C(true) => {} + } +} diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr new file mode 100644 index 0000000000..6a231b868c --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-56379.stderr @@ -0,0 +1,22 @@ +error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered + --> $DIR/issue-56379.rs:8:11 + | +LL | / enum Foo { +LL | | A(bool), + | | - not covered +LL | | B(bool), + | | - not covered +LL | | C(bool), + | | - not covered +LL | | } + | |_- `Foo` defined here +... +LL | match Foo::A(true) { + | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-57472.rs b/src/test/ui/pattern/usefulness/issue-57472.rs similarity index 100% rename from src/test/ui/issues/issue-57472.rs rename to src/test/ui/pattern/usefulness/issue-57472.rs diff --git a/src/test/ui/issues/issue-57472.stderr b/src/test/ui/pattern/usefulness/issue-57472.stderr similarity index 100% rename from src/test/ui/issues/issue-57472.stderr rename to src/test/ui/pattern/usefulness/issue-57472.stderr diff --git a/src/test/ui/pattern/issue-66501.rs b/src/test/ui/pattern/usefulness/issue-66501.rs similarity index 100% rename from src/test/ui/pattern/issue-66501.rs rename to src/test/ui/pattern/usefulness/issue-66501.rs diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs index 57b6b910ca..c5c3a214f9 100644 --- a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs +++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs @@ -1,7 +1,12 @@ +// aux-build:empty.rs #![feature(never_type)] +#![feature(never_type_fallback)] #![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] -enum Foo {} + +extern crate empty; + +enum EmptyEnum {} struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here @@ -41,8 +46,28 @@ macro_rules! match_false { }; } -fn foo(x: Foo) { - match_empty!(x); // ok +fn empty_enum(x: EmptyEnum) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +fn empty_foreign_enum(x: empty::EmptyForeignEnum) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +fn never(x: !) { + match x {} // ok match x { _ => {}, //~ ERROR unreachable pattern } @@ -56,7 +81,7 @@ fn main() { None => {} Some(_) => {} //~ ERROR unreachable pattern } - match None:: { + match None:: { None => {} Some(_) => {} //~ ERROR unreachable pattern } diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr index 1f6503e3e9..9d8b5f38e8 100644 --- a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr +++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr @@ -1,35 +1,59 @@ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:47:9 + --> $DIR/match-empty-exhaustive_patterns.rs:52:9 | LL | _ => {}, | ^ | note: the lint level is defined here - --> $DIR/match-empty-exhaustive_patterns.rs:3:9 + --> $DIR/match-empty-exhaustive_patterns.rs:5:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:50:9 + --> $DIR/match-empty-exhaustive_patterns.rs:55:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:57:9 + --> $DIR/match-empty-exhaustive_patterns.rs:62:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:65:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:72:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:75:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty-exhaustive_patterns.rs:82:9 | LL | Some(_) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:61:9 + --> $DIR/match-empty-exhaustive_patterns.rs:86:9 | LL | Some(_) => {} | ^^^^^^^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/match-empty-exhaustive_patterns.rs:64:18 + --> $DIR/match-empty-exhaustive_patterns.rs:89:18 | LL | match_empty!(0u8); | ^^^ @@ -38,7 +62,7 @@ LL | match_empty!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty - --> $DIR/match-empty-exhaustive_patterns.rs:66:18 + --> $DIR/match-empty-exhaustive_patterns.rs:91:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -50,7 +74,7 @@ LL | match_empty!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/match-empty-exhaustive_patterns.rs:68:18 + --> $DIR/match-empty-exhaustive_patterns.rs:93:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -64,7 +88,7 @@ LL | match_empty!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/match-empty-exhaustive_patterns.rs:70:18 + --> $DIR/match-empty-exhaustive_patterns.rs:95:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -79,7 +103,7 @@ LL | match_empty!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:72:18 + --> $DIR/match-empty-exhaustive_patterns.rs:97:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -96,7 +120,7 @@ LL | match_empty!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:74:18 + --> $DIR/match-empty-exhaustive_patterns.rs:99:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -117,7 +141,7 @@ LL | match_empty!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/match-empty-exhaustive_patterns.rs:76:18 + --> $DIR/match-empty-exhaustive_patterns.rs:101:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -131,7 +155,7 @@ LL | match_empty!(NonEmptyEnum5::V1); = note: the matched value is of type `NonEmptyEnum5` error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:79:18 + --> $DIR/match-empty-exhaustive_patterns.rs:104:18 | LL | match_false!(0u8); | ^^^ pattern `_` not covered @@ -140,7 +164,7 @@ LL | match_false!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:81:18 + --> $DIR/match-empty-exhaustive_patterns.rs:106:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -152,7 +176,7 @@ LL | match_false!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:83:18 + --> $DIR/match-empty-exhaustive_patterns.rs:108:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -166,7 +190,7 @@ LL | match_false!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:85:18 + --> $DIR/match-empty-exhaustive_patterns.rs:110:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -181,7 +205,7 @@ LL | match_false!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:87:18 + --> $DIR/match-empty-exhaustive_patterns.rs:112:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -198,7 +222,7 @@ LL | match_false!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:89:18 + --> $DIR/match-empty-exhaustive_patterns.rs:114:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -219,7 +243,7 @@ LL | match_false!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/match-empty-exhaustive_patterns.rs:91:18 + --> $DIR/match-empty-exhaustive_patterns.rs:116:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -232,6 +256,6 @@ LL | match_false!(NonEmptyEnum5::V1); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `NonEmptyEnum5` -error: aborting due to 18 previous errors +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs index f7577125d8..10ea2a1040 100644 --- a/src/test/ui/pattern/usefulness/match-empty.rs +++ b/src/test/ui/pattern/usefulness/match-empty.rs @@ -1,6 +1,11 @@ +// aux-build:empty.rs #![feature(never_type)] +#![feature(never_type_fallback)] #![deny(unreachable_patterns)] -enum Foo {} + +extern crate empty; + +enum EmptyEnum {} struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here @@ -40,12 +45,33 @@ macro_rules! match_false { }; } -fn foo(x: Foo) { - match_empty!(x); // ok - match_false!(x); // Not detected as unreachable nor exhaustive. - //~^ ERROR non-exhaustive patterns: `_` not covered +fn empty_enum(x: EmptyEnum) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +fn empty_foreign_enum(x: empty::EmptyForeignEnum) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } + match x { + _ if false => {}, //~ ERROR unreachable pattern + } +} + +fn never(x: !) { + match x {} // ok + match x { + _ => {}, //~ ERROR unreachable pattern + } match x { - _ => {}, // Not detected as unreachable, see #55123. + _ if false => {}, //~ ERROR unreachable pattern } } @@ -55,7 +81,7 @@ fn main() { None => {} Some(_) => {} } - match None:: { + match None:: { None => {} Some(_) => {} } diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/match-empty.stderr index 08095f6e7f..6065c55239 100644 --- a/src/test/ui/pattern/usefulness/match-empty.stderr +++ b/src/test/ui/pattern/usefulness/match-empty.stderr @@ -1,17 +1,47 @@ -error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/match-empty.rs:45:18 +error: unreachable pattern + --> $DIR/match-empty.rs:51:9 | -LL | enum Foo {} - | ----------- `Foo` defined here -... -LL | match_false!(x); // Not detected as unreachable nor exhaustive. - | ^ pattern `_` not covered +LL | _ => {}, + | ^ | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `Foo` +note: the lint level is defined here + --> $DIR/match-empty.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/match-empty.rs:54:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty.rs:61:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty.rs:64:9 + | +LL | _ if false => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty.rs:71:9 + | +LL | _ => {}, + | ^ + +error: unreachable pattern + --> $DIR/match-empty.rs:74:9 + | +LL | _ if false => {}, + | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/match-empty.rs:63:18 + --> $DIR/match-empty.rs:89:18 | LL | match_empty!(0u8); | ^^^ @@ -20,7 +50,7 @@ LL | match_empty!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty - --> $DIR/match-empty.rs:65:18 + --> $DIR/match-empty.rs:91:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -32,7 +62,7 @@ LL | match_empty!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/match-empty.rs:67:18 + --> $DIR/match-empty.rs:93:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -46,7 +76,7 @@ LL | match_empty!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/match-empty.rs:69:18 + --> $DIR/match-empty.rs:95:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -61,7 +91,7 @@ LL | match_empty!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/match-empty.rs:71:18 + --> $DIR/match-empty.rs:97:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -78,7 +108,7 @@ LL | match_empty!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/match-empty.rs:73:18 + --> $DIR/match-empty.rs:99:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -99,7 +129,7 @@ LL | match_empty!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/match-empty.rs:75:18 + --> $DIR/match-empty.rs:101:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -113,7 +143,7 @@ LL | match_empty!(NonEmptyEnum5::V1); = note: the matched value is of type `NonEmptyEnum5` error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/match-empty.rs:78:18 + --> $DIR/match-empty.rs:104:18 | LL | match_false!(0u8); | ^^^ pattern `_` not covered @@ -122,7 +152,7 @@ LL | match_false!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered - --> $DIR/match-empty.rs:80:18 + --> $DIR/match-empty.rs:106:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -134,7 +164,7 @@ LL | match_false!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/match-empty.rs:82:18 + --> $DIR/match-empty.rs:108:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -148,7 +178,7 @@ LL | match_false!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/match-empty.rs:84:18 + --> $DIR/match-empty.rs:110:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -163,7 +193,7 @@ LL | match_false!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/match-empty.rs:86:18 + --> $DIR/match-empty.rs:112:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -180,7 +210,7 @@ LL | match_false!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/match-empty.rs:88:18 + --> $DIR/match-empty.rs:114:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -201,7 +231,7 @@ LL | match_false!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/match-empty.rs:90:18 + --> $DIR/match-empty.rs:116:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -214,6 +244,6 @@ LL | match_false!(NonEmptyEnum5::V1); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `NonEmptyEnum5` -error: aborting due to 15 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-range-fail-dominate.rs b/src/test/ui/pattern/usefulness/match-range-fail-dominate.rs deleted file mode 100644 index 37c4ccda0f..0000000000 --- a/src/test/ui/pattern/usefulness/match-range-fail-dominate.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![deny(unreachable_patterns, overlapping_patterns)] - -fn main() { - match 5 { - 1 ..= 10 => { } - 5 ..= 6 => { } - //~^ ERROR unreachable pattern - _ => {} - }; - - match 5 { - 3 ..= 6 => { } - 4 ..= 6 => { } - //~^ ERROR unreachable pattern - _ => {} - }; - - match 5 { - 4 ..= 6 => { } - 4 ..= 6 => { } - //~^ ERROR unreachable pattern - _ => {} - }; - - match 'c' { - 'A' ..= 'z' => {} - 'a' ..= 'z' => {} - //~^ ERROR unreachable pattern - _ => {} - }; - - match 1.0f64 { - 0.01f64 ..= 6.5f64 => {} - //~^ WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - 0.02f64 => {} //~ ERROR unreachable pattern - //~^ WARNING floating-point types cannot be used in patterns - //~| WARNING floating-point types cannot be used in patterns - //~| WARNING this was previously accepted by the compiler - //~| WARNING this was previously accepted by the compiler - _ => {} - }; -} diff --git a/src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr b/src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr deleted file mode 100644 index 6922170fcc..0000000000 --- a/src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr +++ /dev/null @@ -1,93 +0,0 @@ -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:6:7 - | -LL | 5 ..= 6 => { } - | ^^^^^^^ - | -note: the lint level is defined here - --> $DIR/match-range-fail-dominate.rs:1:9 - | -LL | #![deny(unreachable_patterns, overlapping_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:13:7 - | -LL | 4 ..= 6 => { } - | ^^^^^^^ - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:20:7 - | -LL | 4 ..= 6 => { } - | ^^^^^^^ - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:27:7 - | -LL | 'a' ..= 'z' => {} - | ^^^^^^^^^^^ - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:7 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^^ - | - = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:19 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:42:7 - | -LL | 0.02f64 => {} - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: unreachable pattern - --> $DIR/match-range-fail-dominate.rs:42:7 - | -LL | 0.02f64 => {} - | ^^^^^^^ - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:7 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:33:19 - | -LL | 0.01f64 ..= 6.5f64 => {} - | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -warning: floating-point types cannot be used in patterns - --> $DIR/match-range-fail-dominate.rs:42:7 - | -LL | 0.02f64 => {} - | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #41620 - -error: aborting due to 5 previous errors; 6 warnings emitted - diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs index a28cfb579f..4ff12aa2ff 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs @@ -15,7 +15,7 @@ fn main() { // and `(_, _, 5_i32..=i32::MAX)` not covered (_, _, 4) => {} } - match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered + match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered (T::A, T::B) => {} (T::B, T::A) => {} } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index 12412743b8..c953cd3144 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -45,11 +45,11 @@ LL | match (2, 3, 4) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(i32, i32, i32)` -error[E0004]: non-exhaustive patterns: `(A, A)` not covered +error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered --> $DIR/non-exhaustive-match.rs:18:11 | LL | match (T::A, T::A) { - | ^^^^^^^^^^^^ pattern `(A, A)` not covered + | ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(T, T)` diff --git a/src/test/ui/match/type_polymorphic_byte_str_literals.rs b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs similarity index 100% rename from src/test/ui/match/type_polymorphic_byte_str_literals.rs rename to src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.rs diff --git a/src/test/ui/match/type_polymorphic_byte_str_literals.stderr b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr similarity index 100% rename from src/test/ui/match/type_polymorphic_byte_str_literals.stderr rename to src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr diff --git a/src/test/ui/phantom-oibit.rs b/src/test/ui/phantom-auto-trait.rs similarity index 69% rename from src/test/ui/phantom-oibit.rs rename to src/test/ui/phantom-auto-trait.rs index 04291a7060..0172ca335c 100644 --- a/src/test/ui/phantom-oibit.rs +++ b/src/test/ui/phantom-auto-trait.rs @@ -1,7 +1,7 @@ -// Ensure that OIBIT checks `T` when it encounters a `PhantomData` field, instead of checking -// the `PhantomData` type itself (which almost always implements an auto trait) +// Ensure that auto trait checks `T` when it encounters a `PhantomData` field, instead of +// checking the `PhantomData` type itself (which almost always implements an auto trait). -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] use std::marker::{PhantomData}; diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-auto-trait.stderr similarity index 94% rename from src/test/ui/phantom-oibit.stderr rename to src/test/ui/phantom-auto-trait.stderr index 8a02f23da9..779919f9d6 100644 --- a/src/test/ui/phantom-oibit.stderr +++ b/src/test/ui/phantom-auto-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: `T` cannot be shared between threads safely - --> $DIR/phantom-oibit.rs:21:12 + --> $DIR/phantom-auto-trait.rs:21:12 | LL | fn is_zen(_: T) {} | --- required by this bound in `is_zen` @@ -16,7 +16,7 @@ LL | fn not_sync(x: Guard) { | ^^^^^^ error[E0277]: `T` cannot be shared between threads safely - --> $DIR/phantom-oibit.rs:26:12 + --> $DIR/phantom-auto-trait.rs:26:12 | LL | fn is_zen(_: T) {} | --- required by this bound in `is_zen` diff --git a/src/test/ui/precise_pointer_size_matching.rs b/src/test/ui/precise_pointer_size_matching.rs deleted file mode 100644 index 54aeb8616d..0000000000 --- a/src/test/ui/precise_pointer_size_matching.rs +++ /dev/null @@ -1,33 +0,0 @@ -// normalize-stderr-32bit: "-2147483648isize" -> "$$ISIZE_MIN" -// normalize-stderr-64bit: "-9223372036854775808isize" -> "$$ISIZE_MIN" -// normalize-stderr-32bit: "2147483647isize" -> "$$ISIZE_MAX" -// normalize-stderr-64bit: "9223372036854775807isize" -> "$$ISIZE_MAX" -// normalize-stderr-32bit: "4294967295usize" -> "$$USIZE_MAX" -// normalize-stderr-64bit: "18446744073709551615usize" -> "$$USIZE_MAX" - -#![feature(precise_pointer_size_matching)] -#![feature(exclusive_range_pattern)] - -#![deny(unreachable_patterns, overlapping_patterns)] - -use std::{usize, isize}; - -fn main() { - match 0isize { - isize::MIN ..= isize::MAX => {} // ok - } - - match 0usize { - 0 ..= usize::MAX => {} // ok - } - - match 0isize { //~ ERROR non-exhaustive patterns - 1 ..= 8 => {} - -5 ..= 20 => {} - } - - match 0usize { //~ ERROR non-exhaustive patterns - 1 ..= 8 => {} - 5 ..= 20 => {} - } -} diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr deleted file mode 100644 index 9a34171a39..0000000000 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0004]: non-exhaustive patterns: `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered - --> $DIR/precise_pointer_size_matching.rs:24:11 - | -LL | match 0isize { - | ^^^^^^ patterns `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `isize` - -error[E0004]: non-exhaustive patterns: `0_usize` and `21_usize..=usize::MAX` not covered - --> $DIR/precise_pointer_size_matching.rs:29:11 - | -LL | match 0usize { - | ^^^^^^ patterns `0_usize` and `21_usize..=usize::MAX` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `usize` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/print-fuel/print-fuel.rs b/src/test/ui/print-fuel/print-fuel.rs index e443469544..f68de00b9b 100644 --- a/src/test/ui/print-fuel/print-fuel.rs +++ b/src/test/ui/print-fuel/print-fuel.rs @@ -2,8 +2,8 @@ #![allow(dead_code)] // (#55495: The --error-format is to sidestep an issue in our test harness) -// compile-flags: --error-format human -Z print-fuel=foo -// build-pass (FIXME(62277): could be check-pass?) +// compile-flags: -C opt-level=0 --error-format human -Z print-fuel=foo +// check-pass struct S1(u8, u16, u8); struct S2(u8, u16, u8); diff --git a/src/test/ui/print-stdout-eprint-stderr.rs b/src/test/ui/print-stdout-eprint-stderr.rs index 70c083e080..cfa9aec806 100644 --- a/src/test/ui/print-stdout-eprint-stderr.rs +++ b/src/test/ui/print-stdout-eprint-stderr.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported // ignore-sgx no processes diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 37ac45f7e0..0716cee21c 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -15,12 +15,19 @@ // padding and overall computed sizes can be quite different. #![feature(start)] +#![feature(rustc_attrs)] #![allow(dead_code)] use std::num::NonZeroU32; pub enum MyOption { None, Some(T) } +#[rustc_layout_scalar_valid_range_start(0)] +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +pub struct MyNotNegativeOne { + _i: i32, +} + impl Default for MyOption { fn default() -> Self { MyOption::None } } @@ -77,17 +84,18 @@ fn start(_: isize, _: *const *const u8) -> isize { let _a: MyOption = Default::default(); let _b: MyOption = Default::default(); let _c: MyOption = Default::default(); - let _b: MyOption> = Default::default(); + let _d: MyOption> = Default::default(); let _e: Enum4<(), char, (), ()> = Enum4::One(()); let _f: Enum4<(), (), bool, ()> = Enum4::One(()); let _g: Enum4<(), (), (), MyOption> = Enum4::One(()); + let _h: MyOption = Default::default(); // Unions do not currently participate in niche filling. - let _h: MyOption> = Default::default(); + let _i: MyOption> = Default::default(); // ...even when theoretically possible. - let _i: MyOption> = Default::default(); - let _j: MyOption> = Default::default(); + let _j: MyOption> = Default::default(); + let _k: MyOption> = Default::default(); 0 } diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout index 1894cd218e..d1753c26ca 100644 --- a/src/test/ui/print_type_sizes/niche-filling.stdout +++ b/src/test/ui/print_type_sizes/niche-filling.stdout @@ -43,6 +43,12 @@ print-type-size variant `Three`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Four`: 0 bytes print-type-size field `.0`: 0 bytes +print-type-size type: `MyNotNegativeOne`: 4 bytes, alignment: 4 bytes +print-type-size field `._i`: 4 bytes +print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes diff --git a/src/test/ui/privacy/privacy-ns1.rs b/src/test/ui/privacy/privacy-ns1.rs index c7084bfd98..1af5b857e9 100644 --- a/src/test/ui/privacy/privacy-ns1.rs +++ b/src/test/ui/privacy/privacy-ns1.rs @@ -32,8 +32,8 @@ pub mod foo2 { fn test_glob2() { use foo2::*; - let _x: Box; //~ ERROR wrong number of const arguments: expected 0, found 1 - //~^ ERROR wrong number of type arguments: expected at least 1, found 0 + let _x: Box; + //~^ ERROR constant provided when a type was expected } // neither public diff --git a/src/test/ui/privacy/privacy-ns1.stderr b/src/test/ui/privacy/privacy-ns1.stderr index ccbb5d5c90..714f28941f 100644 --- a/src/test/ui/privacy/privacy-ns1.stderr +++ b/src/test/ui/privacy/privacy-ns1.stderr @@ -52,19 +52,13 @@ help: consider importing this trait LL | use foo1::Bar; | -error[E0107]: wrong number of const arguments: expected 0, found 1 +error[E0747]: constant provided when a type was expected --> $DIR/privacy-ns1.rs:35:17 | LL | let _x: Box; - | ^^^ unexpected const argument - -error[E0107]: wrong number of type arguments: expected at least 1, found 0 - --> $DIR/privacy-ns1.rs:35:13 - | -LL | let _x: Box; - | ^^^^^^^^ expected at least 1 type argument + | ^^^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0107, E0412, E0423, E0425. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0412, E0423, E0425, E0747. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/privacy/privacy-ns2.rs b/src/test/ui/privacy/privacy-ns2.rs index b770c8f8f8..47035ef3af 100644 --- a/src/test/ui/privacy/privacy-ns2.rs +++ b/src/test/ui/privacy/privacy-ns2.rs @@ -38,16 +38,14 @@ pub mod foo2 { fn test_single2() { use foo2::Bar; - let _x : Box; //~ ERROR wrong number of const arguments: expected 0, found 1 - //~^ ERROR wrong number of type arguments: expected at least 1, found 0 + let _x : Box; //~ ERROR constant provided when a type was expected let _x : Bar(); //~ ERROR expected type, found function `Bar` } fn test_list2() { use foo2::{Bar,Baz}; - let _x: Box; //~ ERROR wrong number of const arguments: expected 0, found 1 - //~^ ERROR wrong number of type arguments: expected at least 1, found 0 + let _x: Box; //~ ERROR constant provided when a type was expected } // neither public diff --git a/src/test/ui/privacy/privacy-ns2.stderr b/src/test/ui/privacy/privacy-ns2.stderr index dbb269c0ba..c7ad8ec503 100644 --- a/src/test/ui/privacy/privacy-ns2.stderr +++ b/src/test/ui/privacy/privacy-ns2.stderr @@ -28,7 +28,7 @@ LL | use foo2::Bar; | error[E0573]: expected type, found function `Bar` - --> $DIR/privacy-ns2.rs:43:14 + --> $DIR/privacy-ns2.rs:42:14 | LL | let _x : Bar(); | ^^^^^ not a type @@ -43,66 +43,54 @@ LL | use foo1::Bar; | error[E0603]: trait `Bar` is private - --> $DIR/privacy-ns2.rs:63:15 + --> $DIR/privacy-ns2.rs:61:15 | LL | use foo3::Bar; | ^^^ private trait | note: the trait `Bar` is defined here - --> $DIR/privacy-ns2.rs:55:5 + --> $DIR/privacy-ns2.rs:53:5 | LL | trait Bar { | ^^^^^^^^^ error[E0603]: trait `Bar` is private - --> $DIR/privacy-ns2.rs:67:15 + --> $DIR/privacy-ns2.rs:65:15 | LL | use foo3::Bar; | ^^^ private trait | note: the trait `Bar` is defined here - --> $DIR/privacy-ns2.rs:55:5 + --> $DIR/privacy-ns2.rs:53:5 | LL | trait Bar { | ^^^^^^^^^ error[E0603]: trait `Bar` is private - --> $DIR/privacy-ns2.rs:74:16 + --> $DIR/privacy-ns2.rs:72:16 | LL | use foo3::{Bar,Baz}; | ^^^ private trait | note: the trait `Bar` is defined here - --> $DIR/privacy-ns2.rs:55:5 + --> $DIR/privacy-ns2.rs:53:5 | LL | trait Bar { | ^^^^^^^^^ -error[E0107]: wrong number of const arguments: expected 0, found 1 +error[E0747]: constant provided when a type was expected --> $DIR/privacy-ns2.rs:41:18 | LL | let _x : Box; - | ^^^ unexpected const argument + | ^^^ -error[E0107]: wrong number of type arguments: expected at least 1, found 0 - --> $DIR/privacy-ns2.rs:41:14 - | -LL | let _x : Box; - | ^^^^^^^^ expected at least 1 type argument - -error[E0107]: wrong number of const arguments: expected 0, found 1 - --> $DIR/privacy-ns2.rs:49:17 - | -LL | let _x: Box; - | ^^^ unexpected const argument - -error[E0107]: wrong number of type arguments: expected at least 1, found 0 - --> $DIR/privacy-ns2.rs:49:13 +error[E0747]: constant provided when a type was expected + --> $DIR/privacy-ns2.rs:48:17 | LL | let _x: Box; - | ^^^^^^^^ expected at least 1 type argument + | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0107, E0423, E0573, E0603. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0423, E0573, E0603, E0747. +For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/privacy/private-in-public-non-principal-2.rs b/src/test/ui/privacy/private-in-public-non-principal-2.rs index effcb508e2..db451d3342 100644 --- a/src/test/ui/privacy/private-in-public-non-principal-2.rs +++ b/src/test/ui/privacy/private-in-public-non-principal-2.rs @@ -1,4 +1,4 @@ -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] #[allow(private_in_public)] diff --git a/src/test/ui/privacy/private-in-public-non-principal.rs b/src/test/ui/privacy/private-in-public-non-principal.rs index aa946f5c0a..ac1d5a9e6a 100644 --- a/src/test/ui/privacy/private-in-public-non-principal.rs +++ b/src/test/ui/privacy/private-in-public-non-principal.rs @@ -1,4 +1,4 @@ -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] pub trait PubPrincipal {} diff --git a/src/test/ui/proc-macro/allowed-attr-stmt-expr.rs b/src/test/ui/proc-macro/allowed-attr-stmt-expr.rs new file mode 100644 index 0000000000..25243aeef3 --- /dev/null +++ b/src/test/ui/proc-macro/allowed-attr-stmt-expr.rs @@ -0,0 +1,78 @@ +// aux-build:attr-stmt-expr.rs +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// check-pass + +#![feature(proc_macro_hygiene)] +#![feature(stmt_expr_attributes)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate attr_stmt_expr; +extern crate test_macros; +use attr_stmt_expr::{expect_let, expect_my_macro_stmt, expect_expr, expect_my_macro_expr}; +use test_macros::print_attr; + +// We don't use `std::println` so that we avoid loading hygiene +// information from libstd, which would affect the SyntaxContext ids +macro_rules! my_macro { + ($($tt:tt)*) => { () } +} + + +fn print_str(string: &'static str) { + // macros are handled a bit differently + #[expect_my_macro_expr] + my_macro!("{}", string) +} + +macro_rules! make_stmt { + ($stmt:stmt) => { + #[print_attr] + #[rustc_dummy] + $stmt; // This semicolon is *not* passed to the macro, + // since `$stmt` is already a statement. + } +} + +macro_rules! second_make_stmt { + ($stmt:stmt) => { + make_stmt!($stmt); + } +} + +// The macro will see a semicolon here +#[print_attr] +struct ItemWithSemi; + + +fn main() { + make_stmt!(struct Foo {}); + + #[print_attr] + #[expect_let] + let string = "Hello, world!"; + + #[print_attr] + #[expect_my_macro_stmt] + my_macro!("{}", string); + + #[print_attr] + second_make_stmt!(#[allow(dead_code)] struct Bar {}); + + #[print_attr] + #[rustc_dummy] + struct Other {}; + + // The macro also sees a semicolon, + // for consistency with the `ItemWithSemi` case above. + #[print_attr] + #[rustc_dummy] + struct NonBracedStruct; + + #[expect_expr] + print_str("string") +} diff --git a/src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout b/src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout new file mode 100644 index 0000000000..6cf864f359 --- /dev/null +++ b/src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout @@ -0,0 +1,321 @@ +PRINT-ATTR INPUT (DISPLAY): struct ItemWithSemi ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "struct", + span: $DIR/allowed-attr-stmt-expr.rs:49:1: 49:7 (#0), + }, + Ident { + ident: "ItemWithSemi", + span: $DIR/allowed-attr-stmt-expr.rs:49:8: 49:20 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:49:20: 49:21 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:35:9: 35:10 (#11), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/allowed-attr-stmt-expr.rs:35:11: 35:22 (#11), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:35:10: 35:23 (#11), + }, + Ident { + ident: "struct", + span: $DIR/allowed-attr-stmt-expr.rs:53:16: 53:22 (#0), + }, + Ident { + ident: "Foo", + span: $DIR/allowed-attr-stmt-expr.rs:53:23: 53:26 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/allowed-attr-stmt-expr.rs:53:27: 53:29 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[expect_let] let string = "Hello, world!" ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:56:5: 56:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "expect_let", + span: $DIR/allowed-attr-stmt-expr.rs:56:7: 56:17 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:56:6: 56:18 (#0), + }, + Ident { + ident: "let", + span: $DIR/allowed-attr-stmt-expr.rs:57:5: 57:8 (#0), + }, + Ident { + ident: "string", + span: $DIR/allowed-attr-stmt-expr.rs:57:9: 57:15 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:57:16: 57:17 (#0), + }, + Literal { + kind: Str, + symbol: "Hello, world!", + suffix: None, + span: $DIR/allowed-attr-stmt-expr.rs:57:18: 57:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:57:33: 57:34 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[expect_my_macro_stmt] my_macro ! ("{}", string) ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:60:5: 60:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "expect_my_macro_stmt", + span: $DIR/allowed-attr-stmt-expr.rs:60:7: 60:27 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:60:6: 60:28 (#0), + }, + Ident { + ident: "my_macro", + span: $DIR/allowed-attr-stmt-expr.rs:61:5: 61:13 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:61:13: 61:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "{}", + suffix: None, + span: $DIR/allowed-attr-stmt-expr.rs:61:15: 61:19 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:61:19: 61:20 (#0), + }, + Ident { + ident: "string", + span: $DIR/allowed-attr-stmt-expr.rs:61:21: 61:27 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:61:14: 61:28 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:61:28: 61:29 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): second_make_stmt ! (#[allow(dead_code)] struct Bar { }) ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "second_make_stmt", + span: $DIR/allowed-attr-stmt-expr.rs:64:5: 64:21 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:64:21: 64:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:64:23: 64:24 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/allowed-attr-stmt-expr.rs:64:25: 64:30 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/allowed-attr-stmt-expr.rs:64:31: 64:40 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:64:30: 64:41 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:64:24: 64:42 (#0), + }, + Ident { + ident: "struct", + span: $DIR/allowed-attr-stmt-expr.rs:64:43: 64:49 (#0), + }, + Ident { + ident: "Bar", + span: $DIR/allowed-attr-stmt-expr.rs:64:50: 64:53 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/allowed-attr-stmt-expr.rs:64:54: 64:56 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:64:22: 64:57 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:64:57: 64:58 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:35:9: 35:10 (#32), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/allowed-attr-stmt-expr.rs:35:11: 35:22 (#32), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:35:10: 35:23 (#32), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:64:23: 64:24 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/allowed-attr-stmt-expr.rs:64:25: 64:30 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/allowed-attr-stmt-expr.rs:64:31: 64:40 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:64:30: 64:41 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:64:24: 64:42 (#0), + }, + Ident { + ident: "struct", + span: $DIR/allowed-attr-stmt-expr.rs:64:43: 64:49 (#0), + }, + Ident { + ident: "Bar", + span: $DIR/allowed-attr-stmt-expr.rs:64:50: 64:53 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/allowed-attr-stmt-expr.rs:64:54: 64:56 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:67:5: 67:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/allowed-attr-stmt-expr.rs:67:7: 67:18 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:67:6: 67:19 (#0), + }, + Ident { + ident: "struct", + span: $DIR/allowed-attr-stmt-expr.rs:68:5: 68:11 (#0), + }, + Ident { + ident: "Other", + span: $DIR/allowed-attr-stmt-expr.rs:68:12: 68:17 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/allowed-attr-stmt-expr.rs:68:18: 68:20 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct NonBracedStruct ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:73:5: 73:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/allowed-attr-stmt-expr.rs:73:7: 73:18 (#0), + }, + ], + span: $DIR/allowed-attr-stmt-expr.rs:73:6: 73:19 (#0), + }, + Ident { + ident: "struct", + span: $DIR/allowed-attr-stmt-expr.rs:74:5: 74:11 (#0), + }, + Ident { + ident: "NonBracedStruct", + span: $DIR/allowed-attr-stmt-expr.rs:74:12: 74:27 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/allowed-attr-stmt-expr.rs:74:27: 74:28 (#0), + }, +] diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs index 9f4f0abf32..142efb3c6c 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs @@ -17,7 +17,9 @@ fn test() {} #[bench] // OK, shadowed fn bench() {} -fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous +fn non_macro_expanded_location<#[repr(C)] T>() { + //~^ ERROR `repr` is ambiguous + //~| ERROR attribute should be applied to a struct, enum, or union match 0u8 { #[repr(C)] //~ ERROR `repr` is ambiguous _ => {} diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr index 23310f6c6f..276ee1cfd3 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `NonExistent` in this scope - --> $DIR/ambiguous-builtin-attrs.rs:30:5 + --> $DIR/ambiguous-builtin-attrs.rs:32:5 | LL | NonExistent; | ^^^^^^^^^^^ not found in this scope @@ -47,7 +47,7 @@ LL | use builtin_attrs::*; = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous (built-in attribute vs any other name) - --> $DIR/ambiguous-builtin-attrs.rs:22:11 + --> $DIR/ambiguous-builtin-attrs.rs:24:11 | LL | #[repr(C)] | ^^^^ ambiguous name @@ -74,7 +74,13 @@ LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::feature` to refer to this attribute macro unambiguously -error: aborting due to 6 previous errors +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/ambiguous-builtin-attrs.rs:20:39 + | +LL | fn non_macro_expanded_location<#[repr(C)] T>() { + | ^ - not a struct, enum, or union + +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0425, E0659. +Some errors have detailed explanations: E0425, E0517, E0659. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/proc-macro/attr-stmt-expr.rs b/src/test/ui/proc-macro/attr-stmt-expr.rs index 14a392db4e..0403684cda 100644 --- a/src/test/ui/proc-macro/attr-stmt-expr.rs +++ b/src/test/ui/proc-macro/attr-stmt-expr.rs @@ -1,24 +1,63 @@ // aux-build:attr-stmt-expr.rs +// aux-build:test-macros.rs +// compile-flags: -Z span-debug #![feature(proc_macro_hygiene)] +#![feature(rustc_attrs)] +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; +extern crate test_macros; extern crate attr_stmt_expr; -use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr}; + +use test_macros::print_attr; +use attr_stmt_expr::{expect_let, expect_my_macro_stmt, expect_expr, expect_my_macro_expr}; + +// We don't use `std::println` so that we avoid loading hygiene +// information from libstd, which would affect the SyntaxContext ids +macro_rules! my_macro { + ($($tt:tt)*) => { () } +} fn print_str(string: &'static str) { // macros are handled a bit differently - #[expect_print_expr] + #[expect_my_macro_expr] //~^ ERROR attributes on expressions are experimental //~| HELP add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable - println!("{}", string) + my_macro!("{}", string) +} + +macro_rules! make_stmt { + ($stmt:stmt) => { + #[print_attr] + #[rustc_dummy] + $stmt + } +} + +macro_rules! second_make_stmt { + ($stmt:stmt) => { + make_stmt!($stmt); + } } fn main() { + make_stmt!(struct Foo {}); + + #[print_attr] #[expect_let] let string = "Hello, world!"; - #[expect_print_stmt] - println!("{}", string); + #[print_attr] + #[expect_my_macro_stmt] + my_macro!("{}", string); + + #[print_attr] + second_make_stmt!(#[allow(dead_code)] struct Bar {}); + + #[print_attr] + #[rustc_dummy] + struct Other {} #[expect_expr] //~^ ERROR attributes on expressions are experimental diff --git a/src/test/ui/proc-macro/attr-stmt-expr.stderr b/src/test/ui/proc-macro/attr-stmt-expr.stderr index 0d6f247cf8..56178259d4 100644 --- a/src/test/ui/proc-macro/attr-stmt-expr.stderr +++ b/src/test/ui/proc-macro/attr-stmt-expr.stderr @@ -1,14 +1,14 @@ error[E0658]: attributes on expressions are experimental - --> $DIR/attr-stmt-expr.rs:10:5 + --> $DIR/attr-stmt-expr.rs:24:5 | -LL | #[expect_print_expr] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #[expect_my_macro_expr] + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #15701 for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/attr-stmt-expr.rs:23:5 + --> $DIR/attr-stmt-expr.rs:62:5 | LL | #[expect_expr] | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/attr-stmt-expr.stdout b/src/test/ui/proc-macro/attr-stmt-expr.stdout new file mode 100644 index 0000000000..f75309e687 --- /dev/null +++ b/src/test/ui/proc-macro/attr-stmt-expr.stdout @@ -0,0 +1,274 @@ +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:33:9: 33:10 (#8), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/attr-stmt-expr.rs:33:11: 33:22 (#8), + }, + ], + span: $DIR/attr-stmt-expr.rs:33:10: 33:23 (#8), + }, + Ident { + ident: "struct", + span: $DIR/attr-stmt-expr.rs:45:16: 45:22 (#0), + }, + Ident { + ident: "Foo", + span: $DIR/attr-stmt-expr.rs:45:23: 45:26 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/attr-stmt-expr.rs:45:27: 45:29 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[expect_let] let string = "Hello, world!" ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:48:5: 48:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "expect_let", + span: $DIR/attr-stmt-expr.rs:48:7: 48:17 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:48:6: 48:18 (#0), + }, + Ident { + ident: "let", + span: $DIR/attr-stmt-expr.rs:49:5: 49:8 (#0), + }, + Ident { + ident: "string", + span: $DIR/attr-stmt-expr.rs:49:9: 49:15 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:49:16: 49:17 (#0), + }, + Literal { + kind: Str, + symbol: "Hello, world!", + suffix: None, + span: $DIR/attr-stmt-expr.rs:49:18: 49:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:49:33: 49:34 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[expect_my_macro_stmt] my_macro ! ("{}", string) ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:52:5: 52:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "expect_my_macro_stmt", + span: $DIR/attr-stmt-expr.rs:52:7: 52:27 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:52:6: 52:28 (#0), + }, + Ident { + ident: "my_macro", + span: $DIR/attr-stmt-expr.rs:53:5: 53:13 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:53:13: 53:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "{}", + suffix: None, + span: $DIR/attr-stmt-expr.rs:53:15: 53:19 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:53:19: 53:20 (#0), + }, + Ident { + ident: "string", + span: $DIR/attr-stmt-expr.rs:53:21: 53:27 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:53:14: 53:28 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:53:28: 53:29 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): second_make_stmt ! (#[allow(dead_code)] struct Bar { }) ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "second_make_stmt", + span: $DIR/attr-stmt-expr.rs:56:5: 56:21 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:56:21: 56:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:56:23: 56:24 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/attr-stmt-expr.rs:56:25: 56:30 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/attr-stmt-expr.rs:56:31: 56:40 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:56:30: 56:41 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:56:24: 56:42 (#0), + }, + Ident { + ident: "struct", + span: $DIR/attr-stmt-expr.rs:56:43: 56:49 (#0), + }, + Ident { + ident: "Bar", + span: $DIR/attr-stmt-expr.rs:56:50: 56:53 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/attr-stmt-expr.rs:56:54: 56:56 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:56:22: 56:57 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:56:57: 56:58 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:33:9: 33:10 (#29), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/attr-stmt-expr.rs:33:11: 33:22 (#29), + }, + ], + span: $DIR/attr-stmt-expr.rs:33:10: 33:23 (#29), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:56:23: 56:24 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/attr-stmt-expr.rs:56:25: 56:30 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/attr-stmt-expr.rs:56:31: 56:40 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:56:30: 56:41 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:56:24: 56:42 (#0), + }, + Ident { + ident: "struct", + span: $DIR/attr-stmt-expr.rs:56:43: 56:49 (#0), + }, + Ident { + ident: "Bar", + span: $DIR/attr-stmt-expr.rs:56:50: 56:53 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/attr-stmt-expr.rs:56:54: 56:56 (#0), + }, +] +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attr-stmt-expr.rs:59:5: 59:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/attr-stmt-expr.rs:59:7: 59:18 (#0), + }, + ], + span: $DIR/attr-stmt-expr.rs:59:6: 59:19 (#0), + }, + Ident { + ident: "struct", + span: $DIR/attr-stmt-expr.rs:60:5: 60:11 (#0), + }, + Ident { + ident: "Other", + span: $DIR/attr-stmt-expr.rs:60:12: 60:17 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/attr-stmt-expr.rs:60:18: 60:20 (#0), + }, +] diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs index 213f999e9d..19183c6165 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs @@ -15,9 +15,9 @@ pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn expect_my_macro_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println ! (\"{}\", string) ;"); + assert_eq!(item.to_string(), "my_macro ! (\"{}\", string) ;"); item } @@ -29,9 +29,9 @@ pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn expect_my_macro_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println ! (\"{}\", string)"); + assert_eq!(item.to_string(), "my_macro ! (\"{}\", string)"); item } diff --git a/src/test/ui/proc-macro/auxiliary/issue-66286.rs b/src/test/ui/proc-macro/auxiliary/issue-66286.rs new file mode 100644 index 0000000000..6217f1c7e6 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-66286.rs @@ -0,0 +1,14 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn vec_ice(_attr: TokenStream, input: TokenStream) -> TokenStream { + // This redundant convert is necessary to reproduce ICE. + input.into_iter().collect() +} diff --git a/src/test/ui/proc-macro/auxiliary/issue-79242.rs b/src/test/ui/proc-macro/auxiliary/issue-79242.rs new file mode 100644 index 0000000000..e586980f0a --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-79242.rs @@ -0,0 +1,16 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn dummy(input: TokenStream) -> TokenStream { + // Iterate to force internal conversion of nonterminals + // to `proc_macro` structs + for _ in input {} + TokenStream::new() +} diff --git a/src/test/ui/proc-macro/capture-unglued-token.rs b/src/test/ui/proc-macro/capture-unglued-token.rs new file mode 100644 index 0000000000..727b779776 --- /dev/null +++ b/src/test/ui/proc-macro/capture-unglued-token.rs @@ -0,0 +1,20 @@ +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// check-pass + +// Tests that we properly handle parsing a nonterminal +// where we have two consecutive angle brackets (one inside +// the nonterminal, and one outside) + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; +extern crate test_macros; + +macro_rules! trailing_angle { + (Option<$field:ty>) => { + test_macros::print_bang_consume!($field); + } +} + +trailing_angle!(Option>); +fn main() {} diff --git a/src/test/ui/proc-macro/capture-unglued-token.stdout b/src/test/ui/proc-macro/capture-unglued-token.stdout new file mode 100644 index 0000000000..7e6b540332 --- /dev/null +++ b/src/test/ui/proc-macro/capture-unglued-token.stdout @@ -0,0 +1,28 @@ +PRINT-BANG INPUT (DISPLAY): Vec +PRINT-BANG RE-COLLECTED (DISPLAY): Vec < u8 > +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "Vec", + span: $DIR/capture-unglued-token.rs:19:24: 19:27 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/capture-unglued-token.rs:19:27: 19:28 (#0), + }, + Ident { + ident: "u8", + span: $DIR/capture-unglued-token.rs:19:28: 19:30 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/capture-unglued-token.rs:19:30: 19:31 (#0), + }, + ], + span: $DIR/capture-unglued-token.rs:15:42: 15:48 (#4), + }, +] diff --git a/src/test/ui/proc-macro/issue-66286.rs b/src/test/ui/proc-macro/issue-66286.rs new file mode 100644 index 0000000000..2a67aeab44 --- /dev/null +++ b/src/test/ui/proc-macro/issue-66286.rs @@ -0,0 +1,13 @@ +// aux-build:issue-66286.rs + +// Regression test for #66286. + +extern crate issue_66286; + +#[issue_66286::vec_ice] +pub extern fn foo(_: Vec(u32)) -> u32 { + //~^ ERROR: parenthesized type parameters may only be used with a `Fn` trait + 0 +} + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-66286.stderr b/src/test/ui/proc-macro/issue-66286.stderr new file mode 100644 index 0000000000..2854dd7d59 --- /dev/null +++ b/src/test/ui/proc-macro/issue-66286.stderr @@ -0,0 +1,12 @@ +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/issue-66286.rs:8:22 + | +LL | pub extern fn foo(_: Vec(u32)) -> u32 { + | ^^^^^^^^ + | | + | only `Fn` traits may use parentheses + | help: use angle brackets instead: `Vec` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0214`. diff --git a/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs b/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs new file mode 100644 index 0000000000..b68f19c5dd --- /dev/null +++ b/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs @@ -0,0 +1,34 @@ +// check-pass +// aux-build:issue-79242.rs + +// Regression test for issue #79242 +// Tests that compilation time doesn't blow up for a proc-macro +// invocation with deeply nested nonterminals + +#![allow(unused)] + +extern crate issue_79242; + +macro_rules! declare_nats { + ($prev:ty) => {}; + ($prev:ty, $n:literal$(, $tail:literal)*) => { + + issue_79242::dummy! { + $prev + } + + declare_nats!(Option<$prev>$(, $tail)*); + }; + (0, $($n:literal),+) => { + pub struct N0; + declare_nats!(N0, $($n),+); + }; +} + +declare_nats! { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 +} + + +fn main() {} diff --git a/src/test/ui/proc-macro/keep-expr-tokens.rs b/src/test/ui/proc-macro/keep-expr-tokens.rs index 888785363c..0bf889a855 100644 --- a/src/test/ui/proc-macro/keep-expr-tokens.rs +++ b/src/test/ui/proc-macro/keep-expr-tokens.rs @@ -1,7 +1,12 @@ // aux-build:test-macros.rs +// compile-flags: -Z span-debug #![feature(stmt_expr_attributes)] #![feature(proc_macro_hygiene)] +#![feature(rustc_attrs)] + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; extern crate test_macros; @@ -12,4 +17,8 @@ fn main() { for item in missing_fn() {} //~ ERROR cannot find (#[recollect_attr] #[recollect_attr] ((#[recollect_attr] bad))); //~ ERROR cannot + + #[test_macros::print_attr] + #[rustc_dummy] + { 1 +1; } // Don't change the weird spacing of the '+' } diff --git a/src/test/ui/proc-macro/keep-expr-tokens.stderr b/src/test/ui/proc-macro/keep-expr-tokens.stderr index 2be8c0184d..11052d11c2 100644 --- a/src/test/ui/proc-macro/keep-expr-tokens.stderr +++ b/src/test/ui/proc-macro/keep-expr-tokens.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find function `missing_fn` in this scope - --> $DIR/keep-expr-tokens.rs:12:17 + --> $DIR/keep-expr-tokens.rs:17:17 | LL | for item in missing_fn() {} | ^^^^^^^^^^ not found in this scope error[E0425]: cannot find value `bad` in this scope - --> $DIR/keep-expr-tokens.rs:14:62 + --> $DIR/keep-expr-tokens.rs:19:62 | LL | (#[recollect_attr] #[recollect_attr] ((#[recollect_attr] bad))); | ^^^ not found in this scope diff --git a/src/test/ui/proc-macro/keep-expr-tokens.stdout b/src/test/ui/proc-macro/keep-expr-tokens.stdout new file mode 100644 index 0000000000..fcd72a0e01 --- /dev/null +++ b/src/test/ui/proc-macro/keep-expr-tokens.stdout @@ -0,0 +1,46 @@ +PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] { 1 + 1 ; } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/keep-expr-tokens.rs:22:5: 22:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "rustc_dummy", + span: $DIR/keep-expr-tokens.rs:22:7: 22:18 (#0), + }, + ], + span: $DIR/keep-expr-tokens.rs:22:6: 22:19 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/keep-expr-tokens.rs:23:7: 23:8 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/keep-expr-tokens.rs:23:9: 23:10 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/keep-expr-tokens.rs:23:10: 23:11 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/keep-expr-tokens.rs:23:11: 23:12 (#0), + }, + ], + span: $DIR/keep-expr-tokens.rs:23:5: 23:14 (#0), + }, +] diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs index b3b677fa7f..e2cf4e7398 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.rs +++ b/src/test/ui/proc-macro/proc-macro-gates.rs @@ -7,11 +7,11 @@ extern crate test_macros; fn _test_inner() { - #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable + #![empty_attr] //~ ERROR: inner macro attributes are unstable } mod _test2_inner { - #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable + #![empty_attr] //~ ERROR: inner macro attributes are unstable } #[empty_attr = "y"] //~ ERROR: key-value macro attributes are not supported @@ -45,4 +45,9 @@ fn attrs() { //~^ ERROR: custom attributes cannot be applied to expressions } +fn test_case() { + #![test] //~ ERROR inner macro attributes are unstable + //~| WARN this was previously accepted +} + fn main() {} diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index c034349553..118213a17d 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -1,17 +1,17 @@ -error[E0658]: non-builtin inner attributes are unstable - --> $DIR/proc-macro-gates.rs:10:5 +error[E0658]: inner macro attributes are unstable + --> $DIR/proc-macro-gates.rs:10:8 | LL | #![empty_attr] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: see issue #54726 for more information = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable -error[E0658]: non-builtin inner attributes are unstable - --> $DIR/proc-macro-gates.rs:14:5 +error[E0658]: inner macro attributes are unstable + --> $DIR/proc-macro-gates.rs:14:8 | LL | #![empty_attr] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: see issue #54726 for more information = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable @@ -76,6 +76,16 @@ LL | let _x = #[identity_attr] println!(); = note: see issue #54727 for more information = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error: aborting due to 9 previous errors +error: inner macro attributes are unstable + --> $DIR/proc-macro-gates.rs:49:8 + | +LL | #![test] + | ^^^^ + | + = note: `#[deny(soft_unstable)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/proc-macro-gates2.rs b/src/test/ui/proc-macro/proc-macro-gates2.rs index 2fd5efd71f..38fbd4733d 100644 --- a/src/test/ui/proc-macro/proc-macro-gates2.rs +++ b/src/test/ui/proc-macro/proc-macro-gates2.rs @@ -10,11 +10,11 @@ extern crate test_macros; // should either require a feature gate or not be allowed on stable. fn _test6<#[empty_attr] T>() {} -//~^ ERROR: expected an inert attribute, found an attribute macro +//~^ ERROR: expected non-macro attribute, found attribute macro fn _test7() { match 1 { - #[empty_attr] //~ ERROR: expected an inert attribute, found an attribute macro + #[empty_attr] //~ ERROR: expected non-macro attribute, found attribute macro 0 => {} _ => {} } diff --git a/src/test/ui/proc-macro/proc-macro-gates2.stderr b/src/test/ui/proc-macro/proc-macro-gates2.stderr index fd271da615..64df34e7ce 100644 --- a/src/test/ui/proc-macro/proc-macro-gates2.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates2.stderr @@ -1,14 +1,14 @@ -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-gates2.rs:12:11 +error: expected non-macro attribute, found attribute macro `empty_attr` + --> $DIR/proc-macro-gates2.rs:12:13 | LL | fn _test6<#[empty_attr] T>() {} - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-gates2.rs:17:9 +error: expected non-macro attribute, found attribute macro `empty_attr` + --> $DIR/proc-macro-gates2.rs:17:11 | LL | #[empty_attr] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^ not a non-macro attribute error: aborting due to 2 previous errors diff --git a/src/test/ui/process/process-envs.rs b/src/test/ui/process/process-envs.rs index 62a4733f89..8fc99b23fd 100644 --- a/src/test/ui/process/process-envs.rs +++ b/src/test/ui/process/process-envs.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes // ignore-vxworks no 'env' diff --git a/src/test/ui/process/process-exit.rs b/src/test/ui/process/process-exit.rs index da3b4ca85c..d193e073e7 100644 --- a/src/test/ui/process/process-exit.rs +++ b/src/test/ui/process/process-exit.rs @@ -1,6 +1,5 @@ // run-pass #![allow(unused_imports)] -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/process/process-remove-from-env.rs b/src/test/ui/process/process-remove-from-env.rs index 3fee9e2abb..af4e49dfdb 100644 --- a/src/test/ui/process/process-remove-from-env.rs +++ b/src/test/ui/process/process-remove-from-env.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes // ignore-vxworks no 'env' diff --git a/src/test/ui/process/process-sigpipe.rs b/src/test/ui/process/process-sigpipe.rs index 36303440ee..ecf5e93c99 100644 --- a/src/test/ui/process/process-sigpipe.rs +++ b/src/test/ui/process/process-sigpipe.rs @@ -12,7 +12,6 @@ // (instead of running forever), and that it does not print an error // message about a broken pipe. -// ignore-cloudabi no subprocesses support // ignore-emscripten no threads support // ignore-vxworks no 'sh' diff --git a/src/test/ui/process/process-spawn-nonexistent.rs b/src/test/ui/process/process-spawn-nonexistent.rs index 182cf1748f..70de7316a8 100644 --- a/src/test/ui/process/process-spawn-nonexistent.rs +++ b/src/test/ui/process/process-spawn-nonexistent.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/process/process-spawn-with-unicode-params.rs b/src/test/ui/process/process-spawn-with-unicode-params.rs index edd3cb26ec..6e9229b629 100644 --- a/src/test/ui/process/process-spawn-with-unicode-params.rs +++ b/src/test/ui/process/process-spawn-with-unicode-params.rs @@ -7,7 +7,6 @@ // non-ASCII characters. The child process ensures all the strings are // intact. -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/process/process-status-inherits-stdin.rs b/src/test/ui/process/process-status-inherits-stdin.rs index f9b2da7e40..7719dd9ad8 100644 --- a/src/test/ui/process/process-status-inherits-stdin.rs +++ b/src/test/ui/process/process-status-inherits-stdin.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/process/tls-exit-status.rs b/src/test/ui/process/tls-exit-status.rs index 36d6aff9e7..6296e5042d 100644 --- a/src/test/ui/process/tls-exit-status.rs +++ b/src/test/ui/process/tls-exit-status.rs @@ -1,7 +1,6 @@ // run-fail // error-pattern:nonzero // exec-env:RUST_NEWRT=1 -// ignore-cloudabi no std::env // ignore-emscripten no processes use std::env; diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index 2e07fdcbe8..92d98c16c6 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -7,7 +7,7 @@ #![feature(allocator_api)] #![feature(slice_ptr_get)] -use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; use std::ptr::{self, NonNull}; fn main() { @@ -42,7 +42,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); if PRINT { println!("allocate({:?}) = {:?}", layout, ptr); @@ -56,7 +56,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Global.dealloc(NonNull::new_unchecked(ptr), layout); + Global.deallocate(NonNull::new_unchecked(ptr), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr index 345e617a7a..4c271a3916 100644 --- a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr +++ b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/regions-addr-of-upvar-self.rs:10:20 + --> $DIR/regions-addr-of-upvar-self.rs:8:20 | LL | let _f = || { | -- lifetime `'1` represents this closure's body @@ -9,7 +9,7 @@ LL | let p: &'static mut usize = &mut self.food; = note: closure implements `FnMut`, so references to captured variables can't escape the closure error: lifetime may not live long enough - --> $DIR/regions-addr-of-upvar-self.rs:10:20 + --> $DIR/regions-addr-of-upvar-self.rs:8:20 | LL | pub fn chase_cat(&mut self) { | - let's call the lifetime of this reference `'1` @@ -18,7 +18,7 @@ LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` error[E0597]: `self` does not live long enough - --> $DIR/regions-addr-of-upvar-self.rs:10:46 + --> $DIR/regions-addr-of-upvar-self.rs:8:46 | LL | let _f = || { | -- value captured here diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.rs b/src/test/ui/regions/regions-addr-of-upvar-self.rs index 1f8fe9a443..6159ab02d3 100644 --- a/src/test/ui/regions/regions-addr-of-upvar-self.rs +++ b/src/test/ui/regions/regions-addr-of-upvar-self.rs @@ -1,5 +1,3 @@ -use std::usize; - struct Dog { food: usize, } diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.stderr index 005800d50a..62e9058365 100644 --- a/src/test/ui/regions/regions-addr-of-upvar-self.stderr +++ b/src/test/ui/regions/regions-addr-of-upvar-self.stderr @@ -1,22 +1,22 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements - --> $DIR/regions-addr-of-upvar-self.rs:10:41 + --> $DIR/regions-addr-of-upvar-self.rs:8:41 | LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 9:18... - --> $DIR/regions-addr-of-upvar-self.rs:9:18 +note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 7:18... + --> $DIR/regions-addr-of-upvar-self.rs:7:18 | LL | let _f = || { | ^^ note: ...so that closure can access `self` - --> $DIR/regions-addr-of-upvar-self.rs:10:41 + --> $DIR/regions-addr-of-upvar-self.rs:8:41 | LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^ = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content - --> $DIR/regions-addr-of-upvar-self.rs:10:41 + --> $DIR/regions-addr-of-upvar-self.rs:8:41 | LL | let p: &'static mut usize = &mut self.food; | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/regions/regions-mock-codegen.rs b/src/test/ui/regions/regions-mock-codegen.rs index ad4b9c352a..9d0ca76e40 100644 --- a/src/test/ui/regions/regions-mock-codegen.rs +++ b/src/test/ui/regions/regions-mock-codegen.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 #![feature(allocator_api)] -use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; use std::ptr::NonNull; struct arena(()); @@ -22,23 +22,23 @@ struct Ccx { x: isize, } -fn alloc(_bcx: &arena) -> &Bcx<'_> { +fn allocate(_bcx: &arena) -> &Bcx<'_> { unsafe { let layout = Layout::new::(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); &*(ptr.as_ptr() as *const _) } } fn h<'a>(bcx: &'a Bcx<'a>) -> &'a Bcx<'a> { - return alloc(bcx.fcx.arena); + return allocate(bcx.fcx.arena); } fn g(fcx: &Fcx) { let bcx = Bcx { fcx }; let bcx2 = h(&bcx); unsafe { - Global.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); + Global.deallocate(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); } } diff --git a/src/test/ui/auxiliary/extern-prelude-vec.rs b/src/test/ui/resolve/auxiliary/extern-prelude-vec.rs similarity index 100% rename from src/test/ui/auxiliary/extern-prelude-vec.rs rename to src/test/ui/resolve/auxiliary/extern-prelude-vec.rs diff --git a/src/test/ui/auxiliary/extern-prelude.rs b/src/test/ui/resolve/auxiliary/extern-prelude.rs similarity index 100% rename from src/test/ui/auxiliary/extern-prelude.rs rename to src/test/ui/resolve/auxiliary/extern-prelude.rs diff --git a/src/test/ui/extern-prelude-fail.rs b/src/test/ui/resolve/extern-prelude-fail.rs similarity index 100% rename from src/test/ui/extern-prelude-fail.rs rename to src/test/ui/resolve/extern-prelude-fail.rs diff --git a/src/test/ui/extern-prelude-fail.stderr b/src/test/ui/resolve/extern-prelude-fail.stderr similarity index 100% rename from src/test/ui/extern-prelude-fail.stderr rename to src/test/ui/resolve/extern-prelude-fail.stderr diff --git a/src/test/ui/extern-prelude.rs b/src/test/ui/resolve/extern-prelude.rs similarity index 100% rename from src/test/ui/extern-prelude.rs rename to src/test/ui/resolve/extern-prelude.rs diff --git a/src/test/ui/issues/issue-49074.rs b/src/test/ui/resolve/issue-49074.rs similarity index 100% rename from src/test/ui/issues/issue-49074.rs rename to src/test/ui/resolve/issue-49074.rs diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/resolve/issue-49074.stderr similarity index 100% rename from src/test/ui/issues/issue-49074.stderr rename to src/test/ui/resolve/issue-49074.stderr diff --git a/src/test/ui/resolve/macro-determinacy-non-module.rs b/src/test/ui/resolve/macro-determinacy-non-module.rs new file mode 100644 index 0000000000..3215e0cd34 --- /dev/null +++ b/src/test/ui/resolve/macro-determinacy-non-module.rs @@ -0,0 +1,7 @@ +// check-pass + +use std as line; + +const C: u32 = line!(); + +fn main() {} diff --git a/src/test/ui/resolve-pseudo-shadowing.rs b/src/test/ui/resolve/resolve-pseudo-shadowing.rs similarity index 100% rename from src/test/ui/resolve-pseudo-shadowing.rs rename to src/test/ui/resolve/resolve-pseudo-shadowing.rs diff --git a/src/test/ui/resolve/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs index 5b08234c0a..52934085fa 100644 --- a/src/test/ui/resolve/token-error-correct-3.rs +++ b/src/test/ui/resolve/token-error-correct-3.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::fs support - // Test that we do some basic error correction in the tokeniser (and don't spew // too many bogus errors). diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index dd0e259785..31087e394a 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -1,5 +1,5 @@ error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` - --> $DIR/token-error-correct-3.rs:15:35 + --> $DIR/token-error-correct-3.rs:13:35 | LL | callback(path.as_ref(); | - ^ help: `)` may belong here @@ -7,7 +7,7 @@ LL | callback(path.as_ref(); | unclosed delimiter error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - --> $DIR/token-error-correct-3.rs:18:9 + --> $DIR/token-error-correct-3.rs:16:9 | LL | fs::create_dir_all(path.as_ref()).map(|()| true) | - expected one of `.`, `;`, `?`, `}`, or an operator @@ -15,7 +15,7 @@ LL | } else { | ^ unexpected token error[E0425]: cannot find function `is_directory` in this scope - --> $DIR/token-error-correct-3.rs:13:13 + --> $DIR/token-error-correct-3.rs:11:13 | LL | if !is_directory(path.as_ref()) { | ^^^^^^^^^^^^ not found in this scope diff --git a/src/test/ui/resolve/use_suggestion_placement.rs b/src/test/ui/resolve/use_suggestion_placement.rs index 9b8b9d88c7..56d4b8d6d1 100644 --- a/src/test/ui/resolve/use_suggestion_placement.rs +++ b/src/test/ui/resolve/use_suggestion_placement.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::path support - macro_rules! y { () => {} } diff --git a/src/test/ui/resolve/use_suggestion_placement.stderr b/src/test/ui/resolve/use_suggestion_placement.stderr index 3f91760fe2..af0495a57a 100644 --- a/src/test/ui/resolve/use_suggestion_placement.stderr +++ b/src/test/ui/resolve/use_suggestion_placement.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Path` in this scope - --> $DIR/use_suggestion_placement.rs:17:16 + --> $DIR/use_suggestion_placement.rs:15:16 | LL | type Bar = Path; | ^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | use std::path::Path; | error[E0425]: cannot find value `A` in this scope - --> $DIR/use_suggestion_placement.rs:22:13 + --> $DIR/use_suggestion_placement.rs:20:13 | LL | let _ = A; | ^ not found in this scope @@ -21,7 +21,7 @@ LL | use m::A; | error[E0412]: cannot find type `HashMap` in this scope - --> $DIR/use_suggestion_placement.rs:27:23 + --> $DIR/use_suggestion_placement.rs:25:23 | LL | type Dict = HashMap; | ^^^^^^^ not found in this scope diff --git a/src/test/ui/result-opt-conversions.rs b/src/test/ui/result-opt-conversions.rs deleted file mode 100644 index 57f258aab6..0000000000 --- a/src/test/ui/result-opt-conversions.rs +++ /dev/null @@ -1,47 +0,0 @@ -// run-pass - -#[derive(Copy, Clone, Debug, PartialEq)] -struct BadNumErr; - -fn try_num(x: i32) -> Result { - if x <= 5 { - Ok(x + 1) - } else { - Err(BadNumErr) - } -} - -type ResOpt = Result, BadNumErr>; -type OptRes = Option>; - -fn main() { - let mut x: ResOpt = Ok(Some(5)); - let mut y: OptRes = Some(Ok(5)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Ok(None); - y = None; - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Err(BadNumErr); - y = Some(Err(BadNumErr)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - let res: Result, BadNumErr> = - (0..10) - .map(|x| { - let y = try_num(x)?; - Ok(if y % 2 == 0 { - Some(y - 1) - } else { - None - }) - }) - .filter_map(Result::transpose) - .collect(); - - assert_eq!(res, Err(BadNumErr)) -} diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs index 1cca275206..fa5630837b 100644 --- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs +++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs @@ -1,5 +1,3 @@ -use std::f32; - #[derive(PartialEq)] struct Foo { x: u32 diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr index 02fa239818..9a5d57d411 100644 --- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr +++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr @@ -1,11 +1,11 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-forbidden-without-eq.rs:13:9 + --> $DIR/match-forbidden-without-eq.rs:11:9 | LL | FOO => { } | ^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:20:9 + --> $DIR/match-forbidden-without-eq.rs:18:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | f32::INFINITY => { } = note: for more information, see issue #41620 warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:20:9 + --> $DIR/match-forbidden-without-eq.rs:18:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs index afd6d996c1..70253a4fc9 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs @@ -25,7 +25,7 @@ pub enum EmptyNonExhaustiveEnum {} fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) { match x {} match x { - _ => {} // not detected as unreachable + _ => {} //~ ERROR unreachable pattern } } diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr index 752b08b2b6..966f3a2e41 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -1,3 +1,15 @@ +error: unreachable pattern + --> $DIR/enum_same_crate_empty_match.rs:28:9 + | +LL | _ => {} + | ^ + | +note: the lint level is defined here + --> $DIR/enum_same_crate_empty_match.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered --> $DIR/enum_same_crate_empty_match.rs:33:11 | @@ -42,6 +54,6 @@ LL | match NormalEnum::Unit {} = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `NormalEnum` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs index 2b110c9a32..70ec0e3033 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs @@ -1,21 +1,19 @@ -#![feature(naked_functions)] +#![feature(asm, naked_functions)] #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` #[naked] -fn f() {} +extern "C" fn f() { + asm!("", options(noreturn)); +} struct S; impl S { #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` #[naked] - fn g() {} -} - -extern "Rust" { - #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` - #[naked] - fn h(); + extern "C" fn g() { + asm!("", options(noreturn)); + } } fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr index 1249d1df07..1b49148d62 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr @@ -5,17 +5,11 @@ LL | #[track_caller] | ^^^^^^^^^^^^^^^ error[E0736]: cannot use `#[track_caller]` with `#[naked]` - --> $DIR/error-with-naked.rs:16:5 + --> $DIR/error-with-naked.rs:12:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -error[E0736]: cannot use `#[track_caller]` with `#[naked]` - --> $DIR/error-with-naked.rs:10:5 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0736`. diff --git a/src/test/ui/rfc-2294-if-let-guard/bindings.rs b/src/test/ui/rfc-2294-if-let-guard/bindings.rs new file mode 100644 index 0000000000..4e2d70e329 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/bindings.rs @@ -0,0 +1,10 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +fn main() { + match Some(None) { + Some(x) if let Some(y) = x => (x, y), + _ => y, //~ ERROR cannot find value `y` + } + y //~ ERROR cannot find value `y` +} diff --git a/src/test/ui/rfc-2294-if-let-guard/bindings.stderr b/src/test/ui/rfc-2294-if-let-guard/bindings.stderr new file mode 100644 index 0000000000..9c5d92a33a --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/bindings.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:7:14 + | +LL | _ => y, + | ^ not found in this scope + +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:9:5 + | +LL | y + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs index c0a9bbc36b..4ba7e1eeef 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -5,8 +5,7 @@ use std::ops::Range; fn _if_let_guard() { match () { () if let 0 = 1 => {} - //~^ ERROR `if let` guard is not implemented - //~| ERROR `let` expressions are not supported here + //~^ ERROR `if let` guards are experimental () if (let 0 = 1) => {} //~^ ERROR `let` expressions in this position are experimental @@ -75,7 +74,7 @@ fn _macros() { match () { #[cfg(FALSE)] () if let 0 = 1 => {} - //~^ ERROR `if let` guard is not implemented + //~^ ERROR `if let` guards are experimental _ => {} } use_expr!(let 0 = 1); diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index 5c7f8190dd..113870c19f 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `let` - --> $DIR/feature-gate.rs:81:15 + --> $DIR/feature-gate.rs:80:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -7,7 +7,7 @@ LL | macro_rules! use_expr { LL | use_expr!(let 0 = 1); | ^^^ no rules expected this token in macro call -error[E0658]: `if let` guard is not implemented +error[E0658]: `if let` guards are experimental --> $DIR/feature-gate.rs:7:12 | LL | () if let 0 = 1 => {} @@ -16,8 +16,8 @@ LL | () if let 0 = 1 => {} = note: see issue #51114 for more information = help: add `#![feature(if_let_guard)]` to the crate attributes to enable -error[E0658]: `if let` guard is not implemented - --> $DIR/feature-gate.rs:77:12 +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:76:12 | LL | () if let 0 = 1 => {} | ^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | () if let 0 = 1 => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:11:16 + --> $DIR/feature-gate.rs:10:16 | LL | () if (let 0 = 1) => {} | ^^^^^^^^^ @@ -35,7 +35,7 @@ LL | () if (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:15:18 + --> $DIR/feature-gate.rs:14:18 | LL | () if (((let 0 = 1))) => {} | ^^^^^^^^^ @@ -44,7 +44,7 @@ LL | () if (((let 0 = 1))) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:19:23 + --> $DIR/feature-gate.rs:18:23 | LL | () if true && let 0 = 1 => {} | ^^^^^^^^^ @@ -53,7 +53,7 @@ LL | () if true && let 0 = 1 => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:23:15 + --> $DIR/feature-gate.rs:22:15 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^ @@ -62,7 +62,7 @@ LL | () if let 0 = 1 && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:27:16 + --> $DIR/feature-gate.rs:26:16 | LL | () if (let 0 = 1) && true => {} | ^^^^^^^^^ @@ -71,7 +71,7 @@ LL | () if (let 0 = 1) && true => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:31:24 + --> $DIR/feature-gate.rs:30:24 | LL | () if true && (let 0 = 1) => {} | ^^^^^^^^^ @@ -80,7 +80,7 @@ LL | () if true && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:35:16 + --> $DIR/feature-gate.rs:34:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:35:31 + --> $DIR/feature-gate.rs:34:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -98,7 +98,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:15 + --> $DIR/feature-gate.rs:40:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -107,7 +107,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:28 + --> $DIR/feature-gate.rs:40:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -116,7 +116,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:42 + --> $DIR/feature-gate.rs:40:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:55 + --> $DIR/feature-gate.rs:40:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -134,7 +134,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:41:68 + --> $DIR/feature-gate.rs:40:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -143,7 +143,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:53:15 + --> $DIR/feature-gate.rs:52:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:69:16 + --> $DIR/feature-gate.rs:68:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ @@ -161,7 +161,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = help: add `#![feature(let_chains)]` to the crate attributes to enable error[E0658]: `let` expressions in this position are experimental - --> $DIR/feature-gate.rs:72:16 + --> $DIR/feature-gate.rs:71:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -170,16 +170,7 @@ LL | use_expr!((let 0 = 1)); = help: add `#![feature(let_chains)]` to the crate attributes to enable error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:7:15 - | -LL | () if let 0 = 1 => {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if`- and `while`-expressions - = note: as well as when nested within `&&` and parenthesis in those conditions - -error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:11:16 + --> $DIR/feature-gate.rs:10:16 | LL | () if (let 0 = 1) => {} | ^^^^^^^^^ @@ -188,7 +179,7 @@ LL | () if (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:15:18 + --> $DIR/feature-gate.rs:14:18 | LL | () if (((let 0 = 1))) => {} | ^^^^^^^^^ @@ -197,7 +188,7 @@ LL | () if (((let 0 = 1))) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:19:23 + --> $DIR/feature-gate.rs:18:23 | LL | () if true && let 0 = 1 => {} | ^^^^^^^^^ @@ -206,7 +197,7 @@ LL | () if true && let 0 = 1 => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:23:15 + --> $DIR/feature-gate.rs:22:15 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^ @@ -215,7 +206,7 @@ LL | () if let 0 = 1 && true => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:27:16 + --> $DIR/feature-gate.rs:26:16 | LL | () if (let 0 = 1) && true => {} | ^^^^^^^^^ @@ -224,7 +215,7 @@ LL | () if (let 0 = 1) && true => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:31:24 + --> $DIR/feature-gate.rs:30:24 | LL | () if true && (let 0 = 1) => {} | ^^^^^^^^^ @@ -233,7 +224,7 @@ LL | () if true && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:35:16 + --> $DIR/feature-gate.rs:34:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -242,7 +233,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:35:31 + --> $DIR/feature-gate.rs:34:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} | ^^^^^^^^^ @@ -251,7 +242,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:15 + --> $DIR/feature-gate.rs:40:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -260,7 +251,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:28 + --> $DIR/feature-gate.rs:40:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -269,7 +260,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:42 + --> $DIR/feature-gate.rs:40:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -278,7 +269,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:55 + --> $DIR/feature-gate.rs:40:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -287,7 +278,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:41:68 + --> $DIR/feature-gate.rs:40:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^ @@ -296,7 +287,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:53:15 + --> $DIR/feature-gate.rs:52:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -305,7 +296,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:69:16 + --> $DIR/feature-gate.rs:68:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ @@ -314,7 +305,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: as well as when nested within `&&` and parenthesis in those conditions error: `let` expressions are not supported here - --> $DIR/feature-gate.rs:72:16 + --> $DIR/feature-gate.rs:71:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ @@ -322,6 +313,6 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if`- and `while`-expressions = note: as well as when nested within `&&` and parenthesis in those conditions -error: aborting due to 36 previous errors +error: aborting due to 35 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2294-if-let-guard/run-pass.rs b/src/test/ui/rfc-2294-if-let-guard/run-pass.rs new file mode 100644 index 0000000000..a366300379 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/run-pass.rs @@ -0,0 +1,34 @@ +// run-pass + +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +enum Foo { + Bar, + Baz, + Qux(u8), +} + +fn bar(x: bool) -> Foo { + if x { Foo::Baz } else { Foo::Bar } +} + +fn baz(x: u8) -> Foo { + if x % 2 == 0 { Foo::Bar } else { Foo::Baz } +} + +fn qux(x: u8) -> Foo { + Foo::Qux(x.rotate_left(1)) +} + +fn main() { + match Some((true, 3)) { + Some((x, _)) if let Foo::Bar = bar(x) => panic!(), + Some((_, x)) if let Foo::Baz = baz(x) => {}, + _ => panic!(), + } + match Some(42) { + Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84), + _ => panic!(), + } +} diff --git a/src/test/ui/rfc-2294-if-let-guard/typeck.rs b/src/test/ui/rfc-2294-if-let-guard/typeck.rs new file mode 100644 index 0000000000..a4fc7f8cf2 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/typeck.rs @@ -0,0 +1,16 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +fn ok() -> Result, ()> { + Ok(Some(true)) +} + +fn main() { + match ok() { + Ok(x) if let Err(_) = x => {}, + //~^ ERROR mismatched types + Ok(x) if let 0 = x => {}, + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/src/test/ui/rfc-2294-if-let-guard/typeck.stderr b/src/test/ui/rfc-2294-if-let-guard/typeck.stderr new file mode 100644 index 0000000000..7ce93fe734 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/typeck.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/typeck.rs:10:22 + | +LL | Ok(x) if let Err(_) = x => {}, + | ^^^^^^ expected enum `Option`, found enum `std::result::Result` + | + = note: expected enum `Option` + found enum `std::result::Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/typeck.rs:12:22 + | +LL | Ok(x) if let 0 = x => {}, + | ^ expected enum `Option`, found integer + | + = note: expected enum `Option` + found type `{integer}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.rs b/src/test/ui/rfc-2294-if-let-guard/warns.rs new file mode 100644 index 0000000000..9691a12f45 --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/warns.rs @@ -0,0 +1,22 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +#[deny(irrefutable_let_patterns)] +fn irrefutable_let_guard() { + match Some(()) { + Some(x) if let () = x => {} + //~^ ERROR irrefutable if-let guard + _ => {} + } +} + +#[deny(unreachable_patterns)] +fn unreachable_pattern() { + match Some(()) { + x if let None | None = x => {} + //~^ ERROR unreachable pattern + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.stderr b/src/test/ui/rfc-2294-if-let-guard/warns.stderr new file mode 100644 index 0000000000..45720f9fbc --- /dev/null +++ b/src/test/ui/rfc-2294-if-let-guard/warns.stderr @@ -0,0 +1,26 @@ +error: irrefutable if-let guard + --> $DIR/warns.rs:7:24 + | +LL | Some(x) if let () = x => {} + | ^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:4:8 + | +LL | #[deny(irrefutable_let_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/warns.rs:16:25 + | +LL | x if let None | None = x => {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:13:8 + | +LL | #[deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs index 1217f89cb3..a547d09d04 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs @@ -8,8 +8,8 @@ extern "C" { #[allow(unused_mut)] a: i32, #[cfg(something)] b: i32, #[cfg_attr(something, cfg(nothing))] c: i32, - #[deny(unused_mut)] d: i32, - #[forbid(unused_mut)] #[warn(unused_mut)] ... + #[forbid(unused_mut)] d: i32, + #[deny(unused_mut)] #[warn(unused_mut)] ... ); } @@ -17,16 +17,16 @@ type FnType = fn( #[allow(unused_mut)] a: i32, #[cfg(something)] b: i32, #[cfg_attr(something, cfg(nothing))] c: i32, - #[deny(unused_mut)] d: i32, - #[forbid(unused_mut)] #[warn(unused_mut)] e: i32 + #[forbid(unused_mut)] d: i32, + #[deny(unused_mut)] #[warn(unused_mut)] e: i32 ); pub fn foo( #[allow(unused_mut)] a: i32, #[cfg(something)] b: i32, #[cfg_attr(something, cfg(nothing))] c: i32, - #[deny(unused_mut)] d: i32, - #[forbid(unused_mut)] #[warn(unused_mut)] _e: i32 + #[forbid(unused_mut)] d: i32, + #[deny(unused_mut)] #[warn(unused_mut)] _e: i32 ) {} // self diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs index bf09171c9a..6403b3f55c 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs @@ -3,7 +3,7 @@ extern "C" { /// Foo //~^ ERROR documentation comments cannot be applied to function #[test] a: i32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -19,7 +19,7 @@ type FnType = fn( /// Foo //~^ ERROR documentation comments cannot be applied to function #[test] a: u32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -34,7 +34,7 @@ pub fn foo( /// Foo //~^ ERROR documentation comments cannot be applied to function #[test] a: u32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -54,7 +54,7 @@ impl SelfStruct { /// Bar //~^ ERROR documentation comments cannot be applied to function #[test] a: i32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -69,7 +69,7 @@ impl SelfStruct { /// Foo //~^ ERROR documentation comments cannot be applied to function #[test] a: i32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -90,7 +90,7 @@ impl RefStruct { /// Bar //~^ ERROR documentation comments cannot be applied to function #[test] a: i32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -109,7 +109,7 @@ trait RefTrait { /// Bar //~^ ERROR documentation comments cannot be applied to function #[test] a: i32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -124,7 +124,7 @@ trait RefTrait { /// Foo //~^ ERROR documentation comments cannot be applied to function #[test] a: i32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -144,7 +144,7 @@ impl RefTrait for RefStruct { /// Bar //~^ ERROR documentation comments cannot be applied to function #[test] a: i32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Baz //~^ ERROR documentation comments cannot be applied to function #[must_use] @@ -161,7 +161,7 @@ fn main() { /// Foo //~^ ERROR documentation comments cannot be applied to function #[test] a: u32, - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro /// Bar //~^ ERROR documentation comments cannot be applied to function #[must_use] diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr index 4d0349e876..edca8cea68 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr @@ -1,62 +1,62 @@ -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:5:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:5:11 | LL | #[test] a: i32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:21:5 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:21:7 | LL | #[test] a: u32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:36:5 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:36:7 | LL | #[test] a: u32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:56:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:56:11 | LL | #[test] a: i32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:71:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:71:11 | LL | #[test] a: i32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:92:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:92:11 | LL | #[test] a: i32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:111:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:111:11 | LL | #[test] a: i32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:126:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:126:11 | LL | #[test] a: i32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:146:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:146:11 | LL | #[test] a: i32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/param-attrs-builtin-attrs.rs:163:9 +error: expected non-macro attribute, found attribute macro `test` + --> $DIR/param-attrs-builtin-attrs.rs:163:11 | LL | #[test] a: u32, - | ^^^^^^^ + | ^^^^ not a non-macro attribute error: documentation comments cannot be applied to function parameters --> $DIR/param-attrs-builtin-attrs.rs:3:9 diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs index be9085d587..fcfa610ec8 100644 --- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs +++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs @@ -8,58 +8,58 @@ use ident_mac::id; struct W(u8); extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); } -//~^ ERROR expected an inert attribute, found an attribute macro -//~| ERROR expected an inert attribute, found an attribute macro +//~^ ERROR expected non-macro attribute, found attribute macro +//~| ERROR expected non-macro attribute, found attribute macro unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {} -//~^ ERROR expected an inert attribute, found an attribute macro +//~^ ERROR expected non-macro attribute, found attribute macro type Alias = extern "C" fn(#[id] u8, #[id] ...); - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn free(#[id] arg1: u8) { - //~^ ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro let lam = |#[id] W(x), #[id] y: usize| (); - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro } impl W { fn inherent1(#[id] self, #[id] arg1: u8) {} - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn inherent2(#[id] &self, #[id] arg1: u8) {} - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {} - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn inherent4<'a>(#[id] self: Box, #[id] arg1: u8) {} - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {} - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro } trait A { fn trait1(#[id] self, #[id] arg1: u8); - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn trait2(#[id] &self, #[id] arg1: u8); - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8); - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn trait4<'a>(#[id] self: Box, #[id] arg1: u8, #[id] Vec); - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8); - //~^ ERROR expected an inert attribute, found an attribute macro - //~| ERROR expected an inert attribute, found an attribute macro + //~^ ERROR expected non-macro attribute, found attribute macro + //~| ERROR expected non-macro attribute, found attribute macro } fn main() {} diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr index 1cc3c3d822..38c5050f34 100644 --- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr +++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr @@ -1,176 +1,176 @@ -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:10:21 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:10:23 | LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); } - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:10:38 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:10:40 | LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); } - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:14:38 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:14:40 | LL | unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:17:28 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:17:30 | LL | type Alias = extern "C" fn(#[id] u8, #[id] ...); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:17:38 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:17:40 | LL | type Alias = extern "C" fn(#[id] u8, #[id] ...); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:21:9 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:21:11 | LL | fn free(#[id] arg1: u8) { - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:23:16 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:23:18 | LL | let lam = |#[id] W(x), #[id] y: usize| (); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:23:28 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:23:30 | LL | let lam = |#[id] W(x), #[id] y: usize| (); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:29:18 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:29:20 | LL | fn inherent1(#[id] self, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:29:30 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:29:32 | LL | fn inherent1(#[id] self, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:32:18 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:32:20 | LL | fn inherent2(#[id] &self, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:32:31 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:32:33 | LL | fn inherent2(#[id] &self, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:35:22 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:35:24 | LL | fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:35:42 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:35:44 | LL | fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:38:22 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:38:24 | LL | fn inherent4<'a>(#[id] self: Box, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:38:45 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:38:47 | LL | fn inherent4<'a>(#[id] self: Box, #[id] arg1: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:41:38 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:41:40 | LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:41:54 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:41:56 | LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {} - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:47:15 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:47:17 | LL | fn trait1(#[id] self, #[id] arg1: u8); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:47:27 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:47:29 | LL | fn trait1(#[id] self, #[id] arg1: u8); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:50:15 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:50:17 | LL | fn trait2(#[id] &self, #[id] arg1: u8); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:50:28 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:50:30 | LL | fn trait2(#[id] &self, #[id] arg1: u8); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:53:19 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:53:21 | LL | fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:53:39 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:53:41 | LL | fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:56:19 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:56:21 | LL | fn trait4<'a>(#[id] self: Box, #[id] arg1: u8, #[id] Vec); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:56:42 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:56:44 | LL | fn trait4<'a>(#[id] self: Box, #[id] arg1: u8, #[id] Vec); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:56:58 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:56:60 | LL | fn trait4<'a>(#[id] self: Box, #[id] arg1: u8, #[id] Vec); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:60:38 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:60:40 | LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8); - | ^^^^^ + | ^^ not a non-macro attribute -error: expected an inert attribute, found an attribute macro - --> $DIR/proc-macro-cannot-be-used.rs:60:54 +error: expected non-macro attribute, found attribute macro `id` + --> $DIR/proc-macro-cannot-be-used.rs:60:56 | LL | fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8); - | ^^^^^ + | ^^ not a non-macro attribute error: aborting due to 29 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs new file mode 100644 index 0000000000..6a511f4ed3 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs @@ -0,0 +1,27 @@ +//! Basic test for calling methods on generic type parameters in `const fn`. + +// check-pass + +#![feature(const_fn)] +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +struct S; + +impl const PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } +} + +const fn equals_self(t: &T) -> bool { + *t == *t +} + +const fn equals_self_wrapper(t: &T) -> bool { + equals_self(t) +} + +pub const EQ: bool = equals_self_wrapper(&S); + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs new file mode 100644 index 0000000000..b39d27779f --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(const_fn)] +#![feature(const_trait_impl)] +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +struct S; + +impl const PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } +} + +// This duplicate bound should not result in ambiguities. It should be equivalent to a single const +// bound. +const fn equals_self(t: &T) -> bool { + *t == *t +} + +pub const EQ: bool = equals_self(&S); + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs new file mode 100644 index 0000000000..6d4bfe722d --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -0,0 +1,11 @@ +#![feature(const_fn)] +#![feature(const_trait_impl)] +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +pub const fn equals_self(t: &T) -> bool { + *t == *t + //~^ ERROR calls in constant functions are limited to constant functions +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr new file mode 100644 index 0000000000..4b2fc56aaa --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr @@ -0,0 +1,9 @@ +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants + --> $DIR/call-generic-method-fail.rs:7:5 + | +LL | *t == *t + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs new file mode 100644 index 0000000000..f0e3214222 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(const_fn)] +#![feature(const_trait_impl)] +#![feature(const_trait_bound_opt_out)] +#![allow(incomplete_features)] + +struct S; + +impl PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } +} + +const fn equals_self(t: &T) -> bool { + true +} + +pub const EQ: bool = equals_self(&S); + +// Calling `equals_self` with a type that only has a non-const impl is fine, because we opted out. + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs new file mode 100644 index 0000000000..2c8f6354dc --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -0,0 +1,26 @@ +// FIXME(jschievink): this is not rejected correctly (only when the non-const impl is actually used) +// ignore-test + +#![feature(const_fn)] +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +struct S; + +impl PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } +} + +const fn equals_self(t: &T) -> bool { + true +} + +// Calling `equals_self` with something that has a non-const impl should throw an error, despite +// it not using the impl. + +pub const EQ: bool = equals_self(&S); +//~^ ERROR + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs new file mode 100644 index 0000000000..e968e6ec7b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs @@ -0,0 +1,23 @@ +//! Basic test for calling methods on generic type parameters in `const fn`. + +// check-pass + +#![feature(const_fn)] +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +struct S; + +impl const PartialEq for S { + fn eq(&self, _: &S) -> bool { + true + } +} + +const fn equals_self(t: &T) -> bool { + *t == *t +} + +pub const EQ: bool = equals_self(&S); + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs new file mode 100644 index 0000000000..936c90e88a --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs @@ -0,0 +1,13 @@ +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +struct Foo; + +const impl Foo { //~ ERROR: expected identifier, found keyword + fn bar() {} +} + +fn main() { + // shouldn't error here because we shouldn't have been able to recover above + Foo::bar(); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr new file mode 100644 index 0000000000..612511a479 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-norecover.rs:6:7 + | +LL | const impl Foo { + | ^^^^ expected identifier, found keyword + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs new file mode 100644 index 0000000000..fd3dd2cef9 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs @@ -0,0 +1,16 @@ +#![feature(const_trait_impl)] +#![allow(incomplete_features)] + +trait Foo {} + +const impl Foo for i32 {} //~ ERROR: expected identifier, found keyword + +trait Bar {} + +const impl Bar for T {} //~ ERROR: expected identifier, found keyword + +const fn still_implements() {} + +const _: () = still_implements::(); + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr new file mode 100644 index 0000000000..84fb619dc9 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr @@ -0,0 +1,24 @@ +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:6:7 + | +LL | const impl Foo for i32 {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL | impl const Foo for i32 {} + |-- ^^^^^ + +error: expected identifier, found keyword `impl` + --> $DIR/const-impl-recovery.rs:10:7 + | +LL | const impl Bar for T {} + | ^^^^ expected identifier, found keyword + | +help: you might have meant to write a const trait impl + | +LL | impl const Bar for T {} + |-- ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/rfcs/rfc-1014.rs b/src/test/ui/rfcs/rfc-1014.rs index 53b8fddcf3..c454dfa4eb 100644 --- a/src/test/ui/rfcs/rfc-1014.rs +++ b/src/test/ui/rfcs/rfc-1014.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -// ignore-cloudabi stdout does not map to file descriptor 1 by default // ignore-wasm32-bare no libc // ignore-sgx no libc diff --git a/src/test/ui/running-with-no-runtime.rs b/src/test/ui/running-with-no-runtime.rs index 3fc631be60..c321e86dc1 100644 --- a/src/test/ui/running-with-no-runtime.rs +++ b/src/test/ui/running-with-no-runtime.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported // ignore-sgx no processes diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs index 9439df266d..1542c7f311 100644 --- a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs +++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs @@ -2,7 +2,6 @@ // being run when compiling with new LLVM pass manager and ThinLTO. // Note: The issue occurred only on non-zero opt-level. // -// min-llvm-version: 9.0 // needs-sanitizer-support // needs-sanitizer-address // diff --git a/src/test/ui/shadowed/shadowed-lifetime.stderr b/src/test/ui/shadowed/shadowed-lifetime.stderr index 5ea3d92643..68cc505d36 100644 --- a/src/test/ui/shadowed/shadowed-lifetime.stderr +++ b/src/test/ui/shadowed/shadowed-lifetime.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> Foo<'a> { | -- first declared here LL | fn shadow_in_method<'a>(&'a self) -> &'a isize { - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error[E0496]: lifetime name `'b` shadows a lifetime name that is already in scope --> $DIR/shadowed-lifetime.rs:12:20 @@ -12,7 +12,7 @@ error[E0496]: lifetime name `'b` shadows a lifetime name that is already in scop LL | fn shadow_in_type<'b>(&'b self) -> &'b isize { | -- first declared here LL | let x: for<'b> fn(&'b isize) = panic!(); - | ^^ lifetime 'b already in scope + | ^^ lifetime `'b` already in scope error: aborting due to 2 previous errors diff --git a/src/test/ui/signal-alternate-stack-cleanup.rs b/src/test/ui/signal-alternate-stack-cleanup.rs index 8fef66eac8..15fcf78893 100644 --- a/src/test/ui/signal-alternate-stack-cleanup.rs +++ b/src/test/ui/signal-alternate-stack-cleanup.rs @@ -3,7 +3,6 @@ // main thread exit while still being in use by signal handlers. This test // triggers this situation by sending signal from atexit handler. // -// ignore-cloudabi no signal handling support // ignore-wasm32-bare no libc // ignore-windows // ignore-sgx no libc diff --git a/src/test/ui/signal-exit-status.rs b/src/test/ui/signal-exit-status.rs index bd34a21816..0963dcc80f 100644 --- a/src/test/ui/signal-exit-status.rs +++ b/src/test/ui/signal-exit-status.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes // ignore-windows diff --git a/src/test/ui/sigpipe-should-be-ignored.rs b/src/test/ui/sigpipe-should-be-ignored.rs index f472029b82..144eeca231 100644 --- a/src/test/ui/sigpipe-should-be-ignored.rs +++ b/src/test/ui/sigpipe-should-be-ignored.rs @@ -4,7 +4,6 @@ // Be sure that when a SIGPIPE would have been received that the entire process // doesn't die in a ball of fire, but rather it's gracefully handled. -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/simd-type-generic-monomorphisation.rs b/src/test/ui/simd-type-generic-monomorphisation.rs index fc5e23f498..0275f0ce4c 100644 --- a/src/test/ui/simd-type-generic-monomorphisation.rs +++ b/src/test/ui/simd-type-generic-monomorphisation.rs @@ -2,7 +2,9 @@ #![feature(repr_simd, platform_intrinsics)] -// error-pattern:monomorphising SIMD type `Simd2` with a non-machine element type `X` +// ignore-tidy-linelength + +// error-pattern:monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` struct X(Vec); #[repr(simd)] diff --git a/src/test/ui/simd-type-generic-monomorphisation.stderr b/src/test/ui/simd-type-generic-monomorphisation.stderr index 2a74506e80..7f23893ac8 100644 --- a/src/test/ui/simd-type-generic-monomorphisation.stderr +++ b/src/test/ui/simd-type-generic-monomorphisation.stderr @@ -1,4 +1,4 @@ -error: monomorphising SIMD type `Simd2` with a non-machine element type `X` +error: monomorphising SIMD type `Simd2` with a non-primitive-scalar (integer/float/pointer) element type `X` error: aborting due to previous error diff --git a/src/test/ui/simd-type.rs b/src/test/ui/simd-type.rs index 9e4b7e7656..a320df8513 100644 --- a/src/test/ui/simd-type.rs +++ b/src/test/ui/simd-type.rs @@ -1,10 +1,20 @@ #![feature(repr_simd)] #![allow(non_camel_case_types)] +// ignore-tidy-linelength + #[repr(simd)] struct empty; //~ ERROR SIMD vector cannot be empty #[repr(simd)] struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous +struct Foo; + +#[repr(simd)] +struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + +#[repr(simd)] +struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + fn main() {} diff --git a/src/test/ui/simd-type.stderr b/src/test/ui/simd-type.stderr index 0c4242f46b..23004c7859 100644 --- a/src/test/ui/simd-type.stderr +++ b/src/test/ui/simd-type.stderr @@ -1,16 +1,28 @@ error[E0075]: SIMD vector cannot be empty - --> $DIR/simd-type.rs:5:1 + --> $DIR/simd-type.rs:7:1 | LL | struct empty; | ^^^^^^^^^^^^^ error[E0076]: SIMD vector should be homogeneous - --> $DIR/simd-type.rs:8:1 + --> $DIR/simd-type.rs:10:1 | LL | struct i64f64(i64, f64); | ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type -error: aborting due to 2 previous errors +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/simd-type.rs:15:1 + | +LL | struct FooV(Foo, Foo); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/simd-type.rs:18:1 + | +LL | struct FooV2([Foo; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0075, E0076. +Some errors have detailed explanations: E0075, E0076, E0077. For more information about an error, try `rustc --explain E0075`. diff --git a/src/test/ui/simd/simd-array-trait.rs b/src/test/ui/simd/simd-array-trait.rs new file mode 100644 index 0000000000..d6ed5f61a0 --- /dev/null +++ b/src/test/ui/simd/simd-array-trait.rs @@ -0,0 +1,41 @@ +// Figuring out the size of a vector type that depends on traits doesn't ICE + +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd, platform_intrinsics, const_generics)] +#![allow(non_camel_case_types, incomplete_features)] + +pub trait Simd { + type Lane: Clone + Copy; + const SIZE: usize; +} + +pub struct i32x4; +impl Simd for i32x4 { + type Lane = i32; + const SIZE: usize = 4; +} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct T([S::Lane; S::SIZE]); +//~^ ERROR constant expression depends on a generic parameter + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut t = T::([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff --git a/src/test/ui/simd/simd-array-trait.stderr b/src/test/ui/simd/simd-array-trait.stderr new file mode 100644 index 0000000000..c100e020c5 --- /dev/null +++ b/src/test/ui/simd/simd-array-trait.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/simd-array-trait.rs:23:23 + | +LL | pub struct T([S::Lane; S::SIZE]); + | ^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/simd/simd-array-type.rs b/src/test/ui/simd/simd-array-type.rs new file mode 100644 index 0000000000..e84186a42a --- /dev/null +++ b/src/test/ui/simd/simd-array-type.rs @@ -0,0 +1,42 @@ +// run-pass +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd, platform_intrinsics, min_const_generics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct S([i32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct T([i32; N]); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut s = S([0; 4]); + + unsafe { + for i in 0_i32..4 { + s = simd_insert(s, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(s, i as u32)); + } + } + + let mut t = T::<4>([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff --git a/src/test/ui/simd/simd-generics.rs b/src/test/ui/simd/simd-generics.rs index ab6caee9d7..dedca6276c 100644 --- a/src/test/ui/simd/simd-generics.rs +++ b/src/test/ui/simd/simd-generics.rs @@ -1,9 +1,6 @@ // run-pass #![allow(non_camel_case_types)] - - - -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] use std::ops; @@ -11,6 +8,11 @@ use std::ops; #[derive(Copy, Clone)] struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct S([f32; N]); + + extern "platform-intrinsic" { fn simd_add(x: T, y: T) -> T; } @@ -23,10 +25,19 @@ impl ops::Add for f32x4 { type Output = f32x4; fn add(self, rhs: f32x4) -> f32x4 { - unsafe {simd_add(self, rhs)} + unsafe { simd_add(self, rhs) } } } +impl ops::Add for S<4> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe { simd_add(self, rhs) } + } +} + + pub fn main() { let lr = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); @@ -36,4 +47,11 @@ pub fn main() { assert_eq!(y, 4.0f32); assert_eq!(z, 6.0f32); assert_eq!(w, 8.0f32); + + let lr2 = S::<4>([1.0f32, 2.0f32, 3.0f32, 4.0f32]); + let [x, y, z, w] = add(lr2, lr2).0; + assert_eq!(x, 2.0f32); + assert_eq!(y, 4.0f32); + assert_eq!(z, 6.0f32); + assert_eq!(w, 8.0f32); } diff --git a/src/test/ui/simd/simd-intrinsic-float-minmax.rs b/src/test/ui/simd/simd-intrinsic-float-minmax.rs index 5f0aa11af5..d79be61f90 100644 --- a/src/test/ui/simd/simd-intrinsic-float-minmax.rs +++ b/src/test/ui/simd/simd-intrinsic-float-minmax.rs @@ -20,11 +20,11 @@ fn main() { let y = f32x4(2.0, 1.0, 4.0, 3.0); #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] - let nan = ::std::f32::NAN; + let nan = f32::NAN; // MIPS hardware treats f32::NAN as SNAN. Clear the signaling bit. // See https://github.com/rust-lang/rust/issues/52746. #[cfg(any(target_arch = "mips", target_arch = "mips64"))] - let nan = f32::from_bits(::std::f32::NAN.to_bits() - 1); + let nan = f32::from_bits(f32::NAN.to_bits() - 1); let n = f32x4(nan, nan, nan, nan); diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs index b7b3ec9978..4c459fa4bc 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs @@ -2,15 +2,15 @@ // ignore-emscripten #![allow(non_camel_case_types)] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct u32x4(pub u32, pub u32, pub u32, pub u32); #[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct i32x4(pub i32, pub i32, pub i32, pub i32); +#[derive(Copy, Clone)] +struct I32([i32; N]); extern "platform-intrinsic" { fn simd_saturating_add(x: T, y: T) -> T; @@ -51,41 +51,41 @@ fn main() { const MIN: i32 = i32::MIN; const MAX: i32 = i32::MAX; - let a = i32x4(1, 2, 3, 4); - let b = i32x4(2, 4, 6, 8); - let c = i32x4(-1, -2, -3, -4); - let d = i32x4(-2, -4, -6, -8); + let a = I32::<4>([1, 2, 3, 4]); + let b = I32::<4>([2, 4, 6, 8]); + let c = I32::<4>([-1, -2, -3, -4]); + let d = I32::<4>([-2, -4, -6, -8]); - let max = i32x4(MAX, MAX, MAX, MAX); - let max1 = i32x4(MAX - 1, MAX - 1, MAX - 1, MAX - 1); - let min = i32x4(MIN, MIN, MIN, MIN); - let min1 = i32x4(MIN + 1, MIN + 1, MIN + 1, MIN + 1); + let max = I32::<4>([MAX, MAX, MAX, MAX]); + let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); + let min = I32::<4>([MIN, MIN, MIN, MIN]); + let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); - let z = i32x4(0, 0, 0, 0); + let z = I32::<4>([0, 0, 0, 0]); unsafe { - assert_eq!(simd_saturating_add(z, z), z); - assert_eq!(simd_saturating_add(z, a), a); - assert_eq!(simd_saturating_add(b, z), b); - assert_eq!(simd_saturating_add(a, a), b); - assert_eq!(simd_saturating_add(a, max), max); - assert_eq!(simd_saturating_add(max, b), max); - assert_eq!(simd_saturating_add(max1, a), max); - assert_eq!(simd_saturating_add(min1, z), min1); - assert_eq!(simd_saturating_add(min, z), min); - assert_eq!(simd_saturating_add(min1, c), min); - assert_eq!(simd_saturating_add(min, c), min); - assert_eq!(simd_saturating_add(min1, d), min); - assert_eq!(simd_saturating_add(min, d), min); + assert_eq!(simd_saturating_add(z, z).0, z.0); + assert_eq!(simd_saturating_add(z, a).0, a.0); + assert_eq!(simd_saturating_add(b, z).0, b.0); + assert_eq!(simd_saturating_add(a, a).0, b.0); + assert_eq!(simd_saturating_add(a, max).0, max.0); + assert_eq!(simd_saturating_add(max, b).0, max.0); + assert_eq!(simd_saturating_add(max1, a).0, max.0); + assert_eq!(simd_saturating_add(min1, z).0, min1.0); + assert_eq!(simd_saturating_add(min, z).0, min.0); + assert_eq!(simd_saturating_add(min1, c).0, min.0); + assert_eq!(simd_saturating_add(min, c).0, min.0); + assert_eq!(simd_saturating_add(min1, d).0, min.0); + assert_eq!(simd_saturating_add(min, d).0, min.0); - assert_eq!(simd_saturating_sub(b, z), b); - assert_eq!(simd_saturating_sub(b, a), a); - assert_eq!(simd_saturating_sub(a, a), z); - assert_eq!(simd_saturating_sub(a, b), c); - assert_eq!(simd_saturating_sub(z, max), min1); - assert_eq!(simd_saturating_sub(min1, z), min1); - assert_eq!(simd_saturating_sub(min1, a), min); - assert_eq!(simd_saturating_sub(min1, b), min); + assert_eq!(simd_saturating_sub(b, z).0, b.0); + assert_eq!(simd_saturating_sub(b, a).0, a.0); + assert_eq!(simd_saturating_sub(a, a).0, z.0); + assert_eq!(simd_saturating_sub(a, b).0, c.0); + assert_eq!(simd_saturating_sub(z, max).0, min1.0); + assert_eq!(simd_saturating_sub(min1, z).0, min1.0); + assert_eq!(simd_saturating_sub(min1, a).0, min.0); + assert_eq!(simd_saturating_sub(min1, b).0, min.0); } } } diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs index b67c0ad1eb..5b0ff88432 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs @@ -3,7 +3,7 @@ // ignore-emscripten FIXME(#45351) hits an LLVM assert -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd, platform_intrinsics, min_const_generics)] #[repr(simd)] #[derive(Copy, Clone)] @@ -11,7 +11,7 @@ struct i32x4(pub i32, pub i32, pub i32, pub i32); #[repr(simd)] #[derive(Copy, Clone)] -struct u32x4(pub u32, pub u32, pub u32, pub u32); +struct U32([u32; N]); #[repr(simd)] #[derive(Copy, Clone)] @@ -25,6 +25,15 @@ macro_rules! all_eq { }} } +macro_rules! all_eq_ { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0); + }} +} + + extern "platform-intrinsic" { fn simd_add(x: T, y: T) -> T; fn simd_sub(x: T, y: T) -> T; @@ -40,81 +49,81 @@ extern "platform-intrinsic" { fn main() { let x1 = i32x4(1, 2, 3, 4); - let y1 = u32x4(1, 2, 3, 4); + let y1 = U32::<4>([1, 2, 3, 4]); let z1 = f32x4(1.0, 2.0, 3.0, 4.0); let x2 = i32x4(2, 3, 4, 5); - let y2 = u32x4(2, 3, 4, 5); + let y2 = U32::<4>([2, 3, 4, 5]); let z2 = f32x4(2.0, 3.0, 4.0, 5.0); unsafe { all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); - all_eq!(simd_add(y1, y2), u32x4(3, 5, 7, 9)); - all_eq!(simd_add(y2, y1), u32x4(3, 5, 7, 9)); + all_eq_!(simd_add(y1, y2), U32::<4>([3, 5, 7, 9])); + all_eq_!(simd_add(y2, y1), U32::<4>([3, 5, 7, 9])); all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); - all_eq!(simd_mul(y1, y2), u32x4(2, 6, 12, 20)); - all_eq!(simd_mul(y2, y1), u32x4(2, 6, 12, 20)); + all_eq_!(simd_mul(y1, y2), U32::<4>([2, 6, 12, 20])); + all_eq_!(simd_mul(y2, y1), U32::<4>([2, 6, 12, 20])); all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); - all_eq!(simd_sub(y2, y1), u32x4(1, 1, 1, 1)); - all_eq!(simd_sub(y1, y2), u32x4(!0, !0, !0, !0)); + all_eq_!(simd_sub(y2, y1), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_sub(y1, y2), U32::<4>([!0, !0, !0, !0])); all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); all_eq!(simd_div(x1, x1), i32x4(1, 1, 1, 1)); all_eq!(simd_div(i32x4(2, 4, 6, 8), i32x4(2, 2, 2, 2)), x1); - all_eq!(simd_div(y1, y1), u32x4(1, 1, 1, 1)); - all_eq!(simd_div(u32x4(2, 4, 6, 8), u32x4(2, 2, 2, 2)), y1); + all_eq_!(simd_div(y1, y1), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([2, 2, 2, 2])), y1); all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0)); all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0)); all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0)); all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0)); all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1)); - all_eq!(simd_rem(y1, y1), u32x4(0, 0, 0, 0)); - all_eq!(simd_rem(y2, y1), u32x4(0, 1, 1, 1)); + all_eq_!(simd_rem(y1, y1), U32::<4>([0, 0, 0, 0])); + all_eq_!(simd_rem(y2, y1), U32::<4>([0, 1, 1, 1])); all_eq!(simd_rem(z1, z1), f32x4(0.0, 0.0, 0.0, 0.0)); all_eq!(simd_rem(z1, z2), z1); all_eq!(simd_rem(z2, z1), f32x4(0.0, 1.0, 1.0, 1.0)); all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); - all_eq!(simd_shl(y1, y2), u32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); - all_eq!(simd_shl(y2, y1), u32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + all_eq_!(simd_shl(y1, y2), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq_!(simd_shl(y2, y1), U32::<4>([2 << 1, 3 << 2, 4 << 3, 5 << 4])); // test right-shift by assuming left-shift is correct all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); - all_eq!(simd_shr(simd_shl(y1, y2), y2), y1); - all_eq!(simd_shr(simd_shl(y2, y1), y1), y2); + all_eq_!(simd_shr(simd_shl(y1, y2), y2), y1); + all_eq_!(simd_shr(simd_shl(y2, y1), y1), y2); // ensure we get logical vs. arithmetic shifts correct let (a, b, c, d) = (-12, -123, -1234, -12345); all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); - all_eq!(simd_shr(u32x4(a as u32, b as u32, c as u32, d as u32), y1), - u32x4((a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4)); + all_eq_!(simd_shr(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), + U32::<4>([(a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4])); all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); - all_eq!(simd_and(y1, y2), u32x4(0, 2, 0, 4)); - all_eq!(simd_and(y2, y1), u32x4(0, 2, 0, 4)); + all_eq_!(simd_and(y1, y2), U32::<4>([0, 2, 0, 4])); + all_eq_!(simd_and(y2, y1), U32::<4>([0, 2, 0, 4])); all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); - all_eq!(simd_or(y1, y2), u32x4(3, 3, 7, 5)); - all_eq!(simd_or(y2, y1), u32x4(3, 3, 7, 5)); + all_eq_!(simd_or(y1, y2), U32::<4>([3, 3, 7, 5])); + all_eq_!(simd_or(y2, y1), U32::<4>([3, 3, 7, 5])); all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); - all_eq!(simd_xor(y1, y2), u32x4(3, 1, 7, 1)); - all_eq!(simd_xor(y2, y1), u32x4(3, 1, 7, 1)); + all_eq_!(simd_xor(y1, y2), U32::<4>([3, 1, 7, 1])); + all_eq_!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); } } diff --git a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs index 2b593e1c9b..103132c18a 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs @@ -4,8 +4,6 @@ #![feature(repr_simd, platform_intrinsics, concat_idents)] #![allow(non_camel_case_types)] -use std::f32::NAN; - #[repr(simd)] #[derive(Copy, Clone)] struct i32x4(i32, i32, i32, i32); @@ -94,7 +92,7 @@ fn main() { // NAN comparisons are special: // -11 (*) 13 // -5 -100 (*) - let f4 = f32x4(NAN, f1.1, NAN, f2.3); + let f4 = f32x4(f32::NAN, f1.1, f32::NAN, f2.3); unsafe { tests! { diff --git a/src/test/ui/single-primitive-inherent-impl.stderr b/src/test/ui/single-primitive-inherent-impl.stderr index d357afa3b3..50a0d5bef8 100644 --- a/src/test/ui/single-primitive-inherent-impl.stderr +++ b/src/test/ui/single-primitive-inherent-impl.stderr @@ -6,13 +6,7 @@ LL | | LL | | } | |_^ | -help: consider using a trait to implement these methods - --> $DIR/single-primitive-inherent-impl.rs:11:1 - | -LL | / impl str { -LL | | -LL | | } - | |_^ + = help: consider using a trait error: aborting due to previous error diff --git a/src/test/ui/span/issue-33884.rs b/src/test/ui/span/issue-33884.rs index cef123d697..5d927a5acc 100644 --- a/src/test/ui/span/issue-33884.rs +++ b/src/test/ui/span/issue-33884.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::net support - use std::net::TcpListener; use std::net::TcpStream; use std::io::{self, Read, Write}; diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr index 46f36679b8..473d36c2ab 100644 --- a/src/test/ui/span/issue-33884.stderr +++ b/src/test/ui/span/issue-33884.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-33884.rs:8:22 + --> $DIR/issue-33884.rs:6:22 | LL | stream.write_fmt(format!("message received")) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Arguments`, found struct `String` diff --git a/src/test/ui/span/issue-36530.rs b/src/test/ui/span/issue-36530.rs index 4776740d8d..70e04bf7ee 100644 --- a/src/test/ui/span/issue-36530.rs +++ b/src/test/ui/span/issue-36530.rs @@ -6,7 +6,7 @@ #[foo] mod foo { - #![foo] //~ ERROR non-builtin inner attributes are unstable + #![foo] //~ ERROR custom inner attributes are unstable } fn main() {} diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr index 79b12590fc..a998d7217a 100644 --- a/src/test/ui/span/issue-36530.stderr +++ b/src/test/ui/span/issue-36530.stderr @@ -1,8 +1,8 @@ -error[E0658]: non-builtin inner attributes are unstable - --> $DIR/issue-36530.rs:9:5 +error[E0658]: custom inner attributes are unstable + --> $DIR/issue-36530.rs:9:8 | LL | #![foo] - | ^^^^^^^ + | ^^^ | = note: see issue #54726 for more information = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.rs b/src/test/ui/span/issue-43927-non-ADT-derive.rs index 89b8eba1e9..8f1599a5ab 100644 --- a/src/test/ui/span/issue-43927-non-ADT-derive.rs +++ b/src/test/ui/span/issue-43927-non-ADT-derive.rs @@ -5,9 +5,6 @@ //~| ERROR cannot determine resolution for the derive macro `Debug` //~| ERROR cannot determine resolution for the derive macro `PartialEq` //~| ERROR cannot determine resolution for the derive macro `Eq` -//~| ERROR cannot determine resolution for the derive macro `Debug` -//~| ERROR cannot determine resolution for the derive macro `PartialEq` -//~| ERROR cannot determine resolution for the derive macro `Eq` struct DerivedOn; fn main() {} diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr index b160a4e587..85beac535c 100644 --- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr +++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr @@ -28,30 +28,6 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! | = note: import resolution is stuck, try simplifying macro imports -error: cannot determine resolution for the derive macro `Eq` - --> $DIR/issue-43927-non-ADT-derive.rs:3:29 - | -LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! - | ^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the derive macro `PartialEq` - --> $DIR/issue-43927-non-ADT-derive.rs:3:18 - | -LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! - | ^^^^^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: cannot determine resolution for the derive macro `Debug` - --> $DIR/issue-43927-non-ADT-derive.rs:3:11 - | -LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! - | ^^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/specialization/specialization-polarity.rs b/src/test/ui/specialization/specialization-polarity.rs index 17897d8b80..b3cd8255bb 100644 --- a/src/test/ui/specialization/specialization-polarity.rs +++ b/src/test/ui/specialization/specialization-polarity.rs @@ -1,6 +1,6 @@ // Make sure specialization cannot change impl polarity -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] #![feature(specialization)] //~ WARN the feature `specialization` is incomplete diff --git a/src/test/ui/sse2.rs b/src/test/ui/sse2.rs index 7726972b95..172f407982 100644 --- a/src/test/ui/sse2.rs +++ b/src/test/ui/sse2.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no std::env #![allow(stable_features)] #![feature(cfg_target_feature)] diff --git a/src/test/ui/issues/auxiliary/lint-stability.rs b/src/test/ui/stability-attribute/auxiliary/lint-stability.rs similarity index 100% rename from src/test/ui/issues/auxiliary/lint-stability.rs rename to src/test/ui/stability-attribute/auxiliary/lint-stability.rs diff --git a/src/test/ui/issues/issue-28075.rs b/src/test/ui/stability-attribute/issue-28075.rs similarity index 100% rename from src/test/ui/issues/issue-28075.rs rename to src/test/ui/stability-attribute/issue-28075.rs diff --git a/src/test/ui/issues/issue-28075.stderr b/src/test/ui/stability-attribute/issue-28075.stderr similarity index 100% rename from src/test/ui/issues/issue-28075.stderr rename to src/test/ui/stability-attribute/issue-28075.stderr diff --git a/src/test/ui/issues/issue-28388-3.rs b/src/test/ui/stability-attribute/issue-28388-3.rs similarity index 100% rename from src/test/ui/issues/issue-28388-3.rs rename to src/test/ui/stability-attribute/issue-28388-3.rs diff --git a/src/test/ui/issues/issue-28388-3.stderr b/src/test/ui/stability-attribute/issue-28388-3.stderr similarity index 100% rename from src/test/ui/issues/issue-28388-3.stderr rename to src/test/ui/stability-attribute/issue-28388-3.stderr diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs index abd603b356..0c40f8ae1c 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs @@ -63,7 +63,11 @@ fn multiple3() { } #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels pub const fn multiple4() { } -//~^ ERROR Invalid stability or deprecation version found +//~^ ERROR Invalid stability version found + +#[stable(feature = "a", since = "1.0.0")] +#[rustc_deprecated(since = "invalid", reason = "text")] +fn invalid_deprecation_version() {} //~ ERROR Invalid deprecation version found #[rustc_deprecated(since = "a", reason = "text")] fn deprecated_without_unstable_or_stable() { } diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index bf2436a535..ee9a93359f 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -96,19 +96,25 @@ error[E0544]: multiple stability levels LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Invalid stability or deprecation version found +error: Invalid stability version found --> $DIR/stability-attribute-sanity.rs:65:1 | LL | pub const fn multiple4() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: Invalid deprecation version found + --> $DIR/stability-attribute-sanity.rs:70:1 + | +LL | fn invalid_deprecation_version() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute - --> $DIR/stability-attribute-sanity.rs:68:1 + --> $DIR/stability-attribute-sanity.rs:72:1 | LL | #[rustc_deprecated(since = "a", reason = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: aborting due to 19 previous errors -Some errors have detailed explanations: E0539, E0541, E0550. +Some errors have detailed explanations: E0539, E0541, E0546, E0550. For more information about an error, try `rustc --explain E0539`. diff --git a/src/test/ui/std-backtrace.rs b/src/test/ui/std-backtrace.rs index 902a2b6f5a..b5e76666af 100644 --- a/src/test/ui/std-backtrace.rs +++ b/src/test/ui/std-backtrace.rs @@ -1,6 +1,5 @@ // run-pass // ignore-android FIXME #17520 -// ignore-cloudabi spawning processes is not supported // ignore-emscripten spawning processes is not supported // ignore-openbsd no support for libbacktrace without filename // ignore-sgx no processes diff --git a/src/test/ui/stdio-is-blocking.rs b/src/test/ui/stdio-is-blocking.rs index e96406e46b..4b67dbf79e 100644 --- a/src/test/ui/stdio-is-blocking.rs +++ b/src/test/ui/stdio-is-blocking.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/structs-enums/discrim-explicit-23030.rs b/src/test/ui/structs-enums/discrim-explicit-23030.rs index 211ca7e4e8..af7ab865e3 100644 --- a/src/test/ui/structs-enums/discrim-explicit-23030.rs +++ b/src/test/ui/structs-enums/discrim-explicit-23030.rs @@ -5,8 +5,6 @@ // See also compile-fail/overflow-discrim.rs, which shows what // happens if you leave the OhNo explicit cases out here. -use std::{i8,u8,i16,u16,i32,u32,i64,u64,isize,usize}; - fn f_i8() { #[repr(i8)] enum A { diff --git a/src/test/ui/structs-enums/nested-enum-same-names.rs b/src/test/ui/structs-enums/nested-enum-same-names.rs index dece3dcd54..111b9ba947 100644 --- a/src/test/ui/structs-enums/nested-enum-same-names.rs +++ b/src/test/ui/structs-enums/nested-enum-same-names.rs @@ -17,10 +17,10 @@ as it does not include the method name in the symbol name. pub struct Foo; impl Foo { pub fn foo() { - enum Panic { Common }; + enum Panic { Common } } pub fn bar() { - enum Panic { Common }; + enum Panic { Common } } } diff --git a/src/test/ui/structs-enums/rec-align-u64.rs b/src/test/ui/structs-enums/rec-align-u64.rs index b06e204d31..69544b1c06 100644 --- a/src/test/ui/structs-enums/rec-align-u64.rs +++ b/src/test/ui/structs-enums/rec-align-u64.rs @@ -32,7 +32,6 @@ struct Outer { #[cfg(any(target_os = "android", - target_os = "cloudabi", target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", diff --git a/src/test/ui/suffixed-literal-meta.rs b/src/test/ui/suffixed-literal-meta.rs index c3a4eabad7..319264aec9 100644 --- a/src/test/ui/suffixed-literal-meta.rs +++ b/src/test/ui/suffixed-literal-meta.rs @@ -1,27 +1,15 @@ -#![feature(rustc_attrs)] +#![feature(rustc_attrs, extended_key_value_attributes)] #[rustc_dummy = 1usize] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u8] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u16] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u32] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u64] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1isize] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i8] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i16] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i32] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i64] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes fn main() {} diff --git a/src/test/ui/suffixed-literal-meta.stderr b/src/test/ui/suffixed-literal-meta.stderr index 84fe91d662..5245ffead7 100644 --- a/src/test/ui/suffixed-literal-meta.stderr +++ b/src/test/ui/suffixed-literal-meta.stderr @@ -7,119 +7,23 @@ LL | #[rustc_dummy = 1usize] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:5:17 + --> $DIR/suffixed-literal-meta.rs:4:17 | LL | #[rustc_dummy = 1u8] | ^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:7:17 - | -LL | #[rustc_dummy = 1u16] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:9:17 - | -LL | #[rustc_dummy = 1u32] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:11:17 - | -LL | #[rustc_dummy = 1u64] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:13:17 - | -LL | #[rustc_dummy = 1isize] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:15:17 - | -LL | #[rustc_dummy = 1i8] - | ^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:17:17 - | -LL | #[rustc_dummy = 1i16] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:19:17 - | -LL | #[rustc_dummy = 1i32] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:21:17 - | -LL | #[rustc_dummy = 1i64] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:23:17 - | -LL | #[rustc_dummy = 1.0f32] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:25:17 - | -LL | #[rustc_dummy = 1.0f64] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:3:17 - | -LL | #[rustc_dummy = 1usize] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - error: suffixed literals are not allowed in attributes --> $DIR/suffixed-literal-meta.rs:5:17 | -LL | #[rustc_dummy = 1u8] - | ^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:7:17 - | LL | #[rustc_dummy = 1u16] | ^^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:9:17 + --> $DIR/suffixed-literal-meta.rs:6:17 | LL | #[rustc_dummy = 1u32] | ^^^^ @@ -127,7 +31,7 @@ LL | #[rustc_dummy = 1u32] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:11:17 + --> $DIR/suffixed-literal-meta.rs:7:17 | LL | #[rustc_dummy = 1u64] | ^^^^ @@ -135,7 +39,7 @@ LL | #[rustc_dummy = 1u64] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:13:17 + --> $DIR/suffixed-literal-meta.rs:8:17 | LL | #[rustc_dummy = 1isize] | ^^^^^^ @@ -143,7 +47,7 @@ LL | #[rustc_dummy = 1isize] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:15:17 + --> $DIR/suffixed-literal-meta.rs:9:17 | LL | #[rustc_dummy = 1i8] | ^^^ @@ -151,7 +55,7 @@ LL | #[rustc_dummy = 1i8] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:17:17 + --> $DIR/suffixed-literal-meta.rs:10:17 | LL | #[rustc_dummy = 1i16] | ^^^^ @@ -159,7 +63,7 @@ LL | #[rustc_dummy = 1i16] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:19:17 + --> $DIR/suffixed-literal-meta.rs:11:17 | LL | #[rustc_dummy = 1i32] | ^^^^ @@ -167,7 +71,7 @@ LL | #[rustc_dummy = 1i32] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:21:17 + --> $DIR/suffixed-literal-meta.rs:12:17 | LL | #[rustc_dummy = 1i64] | ^^^^ @@ -175,7 +79,7 @@ LL | #[rustc_dummy = 1i64] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:23:17 + --> $DIR/suffixed-literal-meta.rs:13:17 | LL | #[rustc_dummy = 1.0f32] | ^^^^^^ @@ -183,12 +87,12 @@ LL | #[rustc_dummy = 1.0f32] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:25:17 + --> $DIR/suffixed-literal-meta.rs:14:17 | LL | #[rustc_dummy = 1.0f64] | ^^^^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error: aborting due to 24 previous errors +error: aborting due to 12 previous errors diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs index a8ea3faefe..00638e04f5 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs +++ b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs @@ -8,12 +8,18 @@ trait T { fn main() { let _: usize = foo(_, _); - //~^ ERROR expected expression - //~| ERROR expected expression + //~^ ERROR `_` can only be used on the left-hand side of an assignment + //~| ERROR `_` can only be used on the left-hand side of an assignment + //~| ERROR destructuring assignments are unstable + //~| ERROR destructuring assignments are unstable let _: S = S(_, _); - //~^ ERROR expected expression - //~| ERROR expected expression + //~^ ERROR `_` can only be used on the left-hand side of an assignment + //~| ERROR `_` can only be used on the left-hand side of an assignment + //~| ERROR destructuring assignments are unstable + //~| ERROR destructuring assignments are unstable let _: usize = T::baz(_, _); - //~^ ERROR expected expression - //~| ERROR expected expression + //~^ ERROR `_` can only be used on the left-hand side of an assignment + //~| ERROR `_` can only be used on the left-hand side of an assignment + //~| ERROR destructuring assignments are unstable + //~| ERROR destructuring assignments are unstable } diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr index a6d1c4b859..248fa6b9c9 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr @@ -1,38 +1,93 @@ -error: expected expression, found reserved identifier `_` +error[E0658]: destructuring assignments are unstable --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24 | LL | let _: usize = foo(_, _); - | ^ expected expression + | ^ + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + +error[E0658]: destructuring assignments are unstable + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27 + | +LL | let _: usize = foo(_, _); + | ^ + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + +error[E0658]: destructuring assignments are unstable + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18 + | +LL | let _: S = S(_, _); + | ^ + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + +error[E0658]: destructuring assignments are unstable + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21 + | +LL | let _: S = S(_, _); + | ^ + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + +error[E0658]: destructuring assignments are unstable + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27 + | +LL | let _: usize = T::baz(_, _); + | ^ + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + +error[E0658]: destructuring assignments are unstable + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30 + | +LL | let _: usize = T::baz(_, _); + | ^ + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24 + | +LL | let _: usize = foo(_, _); + | ^ `_` not allowed here -error: expected expression, found reserved identifier `_` +error: in expressions, `_` can only be used on the left-hand side of an assignment --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27 | LL | let _: usize = foo(_, _); - | ^ expected expression + | ^ `_` not allowed here -error: expected expression, found reserved identifier `_` - --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:18 +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18 | LL | let _: S = S(_, _); - | ^ expected expression + | ^ `_` not allowed here -error: expected expression, found reserved identifier `_` - --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:21 +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21 | LL | let _: S = S(_, _); - | ^ expected expression + | ^ `_` not allowed here -error: expected expression, found reserved identifier `_` - --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:27 +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27 | LL | let _: usize = T::baz(_, _); - | ^ expected expression + | ^ `_` not allowed here -error: expected expression, found reserved identifier `_` - --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:30 +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30 | LL | let _: usize = T::baz(_, _); - | ^ expected expression + | ^ `_` not allowed here -error: aborting due to 6 previous errors +error: aborting due to 12 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs index d401328077..949b236007 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs @@ -39,6 +39,14 @@ fn bak(constraints: impl Iterator + std::fmt::Debug) { } } +#[rustfmt::skip] +fn baw<>(constraints: impl Iterator) { + for constraint in constraints { + qux(constraint); +//~^ ERROR `::Item` doesn't implement `Debug` + } +} + fn qux(_: impl std::fmt::Debug) {} fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr index 099eb1c9d0..0de3b9aec1 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -73,6 +73,21 @@ help: introduce a type parameter with a trait bound instead of using `impl Trait LL | fn bak(constraints: I) where ::Item: Debug { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0277]: `::Item` doesn't implement `Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:45:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn baw(constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs new file mode 100644 index 0000000000..3cd6d336e1 --- /dev/null +++ b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs @@ -0,0 +1,32 @@ +// Regression test: if we suggest replacing an `impl Trait` argument to an async +// fn with a named type parameter in order to add bounds, the suggested function +// signature should be well-formed. +// +// edition:2018 + +trait Foo { + type Bar; + fn bar(&self) -> Self::Bar; +} + +async fn run(_: &(), foo: impl Foo) -> std::io::Result<()> { + let bar = foo.bar(); + assert_is_send(&bar); +//~^ ERROR: `::Bar` cannot be sent between threads safely + + Ok(()) +} + +// Test our handling of cases where there is a generic parameter list in the +// source, but only synthetic generic parameters +async fn run2< >(_: &(), foo: impl Foo) -> std::io::Result<()> { + let bar = foo.bar(); + assert_is_send(&bar); +//~^ ERROR: `::Bar` cannot be sent between threads safely + + Ok(()) +} + +fn assert_is_send(_: &T) {} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr new file mode 100644 index 0000000000..9404c3bb58 --- /dev/null +++ b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr @@ -0,0 +1,33 @@ +error[E0277]: `::Bar` cannot be sent between threads safely + --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:14:20 + | +LL | assert_is_send(&bar); + | ^^^^ `::Bar` cannot be sent between threads safely +... +LL | fn assert_is_send(_: &T) {} + | ---- required by this bound in `assert_is_send` + | + = help: the trait `Send` is not implemented for `::Bar` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | async fn run(_: &(), foo: F) -> std::io::Result<()> where ::Bar: Send { + | ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `::Bar` cannot be sent between threads safely + --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:24:20 + | +LL | assert_is_send(&bar); + | ^^^^ `::Bar` cannot be sent between threads safely +... +LL | fn assert_is_send(_: &T) {} + | ---- required by this bound in `assert_is_send` + | + = help: the trait `Send` is not implemented for `::Bar` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | async fn run2(_: &(), foo: F) -> std::io::Result<()> where ::Bar: Send { + | ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 3c2226574e..df064f22f3 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -107,16 +107,12 @@ error[E0747]: type provided when a lifetime was expected | LL | struct Al<'a, T, M: OneWithLifetime> { | ^ - | - = note: lifetime arguments must be provided before type arguments error[E0747]: type provided when a lifetime was expected --> $DIR/suggest-move-types.rs:48:71 | LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^ - | - = note: lifetime arguments must be provided before type arguments error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:65:56 diff --git a/src/test/ui/symbol-names/const-generics.rs b/src/test/ui/symbol-names/const-generics.rs index ad87000228..823995e5be 100644 --- a/src/test/ui/symbol-names/const-generics.rs +++ b/src/test/ui/symbol-names/const-generics.rs @@ -19,11 +19,11 @@ // `i8` pub struct I8; - impl I8<{std::i8::MIN}> { + impl I8<{i8::MIN}> { pub fn foo() {} } - impl I8<{std::i8::MAX}> { + impl I8<{i8::MAX}> { pub fn foo() {} } @@ -34,7 +34,7 @@ // `i16` pub struct I16; - impl I16<{std::i16::MIN}> { + impl I16<{i16::MIN}> { pub fn foo() {} } @@ -45,7 +45,7 @@ // `i32` pub struct I32; - impl I32<{std::i32::MIN}> { + impl I32<{i32::MIN}> { pub fn foo() {} } @@ -56,7 +56,7 @@ // `i64` pub struct I64; - impl I64<{std::i64::MIN}> { + impl I64<{i64::MIN}> { pub fn foo() {} } @@ -67,7 +67,7 @@ // `i128` pub struct I128; - impl I128<{std::i128::MIN}> { + impl I128<{i128::MIN}> { pub fn foo() {} } diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 1ada54cc10..05bd98df00 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -6,7 +6,7 @@ //[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH" //[legacy]normalize-stderr-64bit: "h310ea0259fc3d32d" -> "SYMBOL_HASH" -#![feature(optin_builtin_traits, rustc_attrs)] +#![feature(auto_traits, rustc_attrs)] #![allow(dead_code)] mod foo { diff --git a/src/test/ui/tcp-stress.rs b/src/test/ui/tcp-stress.rs index 08b47dc531..1756636434 100644 --- a/src/test/ui/tcp-stress.rs +++ b/src/test/ui/tcp-stress.rs @@ -1,6 +1,5 @@ // run-pass // ignore-android needs extra network permissions -// ignore-cloudabi no global network namespace access // ignore-emscripten no threads or sockets support // ignore-netbsd system ulimit (Too many open files) // ignore-openbsd system ulimit (Too many open files) diff --git a/src/test/ui/test-panic-abort-nocapture.rs b/src/test/ui/test-panic-abort-nocapture.rs index 978732a9ec..af530cc1a0 100644 --- a/src/test/ui/test-panic-abort-nocapture.rs +++ b/src/test/ui/test-panic-abort-nocapture.rs @@ -4,6 +4,7 @@ // run-fail // check-run-results // exec-env:RUST_BACKTRACE=0 +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support diff --git a/src/test/ui/test-panic-abort-nocapture.run.stderr b/src/test/ui/test-panic-abort-nocapture.run.stderr index 3388813d5a..727e9691c5 100644 --- a/src/test/ui/test-panic-abort-nocapture.run.stderr +++ b/src/test/ui/test-panic-abort-nocapture.run.stderr @@ -1,9 +1,9 @@ thread 'main' panicked at 'assertion failed: `(left == right)` left: `2`, - right: `4`', $DIR/test-panic-abort-nocapture.rs:32:5 + right: `4`', $DIR/test-panic-abort-nocapture.rs:33:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'assertion failed: `(left == right)` left: `2`, - right: `4`', $DIR/test-panic-abort-nocapture.rs:26:5 + right: `4`', $DIR/test-panic-abort-nocapture.rs:27:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace testing321 diff --git a/src/test/ui/test-panic-abort-nocapture.run.stdout b/src/test/ui/test-panic-abort-nocapture.run.stdout index 87a246db5e..15b19676a7 100644 --- a/src/test/ui/test-panic-abort-nocapture.run.stdout +++ b/src/test/ui/test-panic-abort-nocapture.run.stdout @@ -19,5 +19,5 @@ failures: failures: it_fails -test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/test/ui/test-panic-abort.rs b/src/test/ui/test-panic-abort.rs index 21e7dc393f..931b7993c8 100644 --- a/src/test/ui/test-panic-abort.rs +++ b/src/test/ui/test-panic-abort.rs @@ -4,6 +4,7 @@ // run-fail // check-run-results // exec-env:RUST_BACKTRACE=0 +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support diff --git a/src/test/ui/test-panic-abort.run.stdout b/src/test/ui/test-panic-abort.run.stdout index 33ddd51903..467f834afe 100644 --- a/src/test/ui/test-panic-abort.run.stdout +++ b/src/test/ui/test-panic-abort.run.stdout @@ -18,7 +18,7 @@ testing123 testing321 thread 'main' panicked at 'assertion failed: `(left == right)` left: `2`, - right: `5`', $DIR/test-panic-abort.rs:33:5 + right: `5`', $DIR/test-panic-abort.rs:34:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace @@ -26,5 +26,5 @@ failures: it_exits it_fails -test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/test/ui/test-passed-wasm.rs b/src/test/ui/test-passed-wasm.rs new file mode 100644 index 0000000000..578aa4b176 --- /dev/null +++ b/src/test/ui/test-passed-wasm.rs @@ -0,0 +1,20 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --test-threads=1 +// run-pass +// check-run-results +// only-wasm32 + +// Tests the output of the test harness with only passed tests. + +#![cfg(test)] + +#[test] +fn it_works() { + assert_eq!(1 + 1, 2); +} + +#[test] +fn it_works_too() { + assert_eq!(1 * 0, 0); +} diff --git a/src/test/ui/test-passed-wasm.run.stdout b/src/test/ui/test-passed-wasm.run.stdout new file mode 100644 index 0000000000..c3005a7798 --- /dev/null +++ b/src/test/ui/test-passed-wasm.run.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test it_works ... ok +test it_works_too ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/ui/test-passed.rs b/src/test/ui/test-passed.rs new file mode 100644 index 0000000000..f65f000302 --- /dev/null +++ b/src/test/ui/test-passed.rs @@ -0,0 +1,21 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --test-threads=1 +// run-pass +// check-run-results +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// ignore-wasm32 no support for `Instant` + +// Tests the output of the test harness with only passed tests. + +#![cfg(test)] + +#[test] +fn it_works() { + assert_eq!(1 + 1, 2); +} + +#[test] +fn it_works_too() { + assert_eq!(1 * 0, 0); +} diff --git a/src/test/ui/test-passed.run.stdout b/src/test/ui/test-passed.run.stdout new file mode 100644 index 0000000000..17f70d6074 --- /dev/null +++ b/src/test/ui/test-passed.run.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test it_works ... ok +test it_works_too ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/ui/test-thread-capture.rs b/src/test/ui/test-thread-capture.rs index 6bec48cd81..edc972837a 100644 --- a/src/test/ui/test-thread-capture.rs +++ b/src/test/ui/test-thread-capture.rs @@ -3,6 +3,7 @@ // run-flags: --test-threads=1 // check-run-results // exec-env:RUST_BACKTRACE=0 +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" // ignore-emscripten no threads support #[test] diff --git a/src/test/ui/test-thread-capture.run.stdout b/src/test/ui/test-thread-capture.run.stdout index 1102aadab0..487cfb55eb 100644 --- a/src/test/ui/test-thread-capture.run.stdout +++ b/src/test/ui/test-thread-capture.run.stdout @@ -10,12 +10,12 @@ fee fie foe fum -thread 'main' panicked at 'explicit panic', $DIR/test-thread-capture.rs:30:5 +thread 'main' panicked at 'explicit panic', $DIR/test-thread-capture.rs:31:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: thready_fail -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/test/ui/test-thread-nocapture.rs b/src/test/ui/test-thread-nocapture.rs index 82df6e77cb..8e8e9bbfdf 100644 --- a/src/test/ui/test-thread-nocapture.rs +++ b/src/test/ui/test-thread-nocapture.rs @@ -3,6 +3,7 @@ // run-flags: --test-threads=1 --nocapture // check-run-results // exec-env:RUST_BACKTRACE=0 +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" // ignore-emscripten no threads support #[test] diff --git a/src/test/ui/test-thread-nocapture.run.stderr b/src/test/ui/test-thread-nocapture.run.stderr index 98bd96d0ab..06495681b3 100644 --- a/src/test/ui/test-thread-nocapture.run.stderr +++ b/src/test/ui/test-thread-nocapture.run.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:30:5 +thread 'main' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:31:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/src/test/ui/test-thread-nocapture.run.stdout b/src/test/ui/test-thread-nocapture.run.stdout index 77b42ed88d..9d2da50826 100644 --- a/src/test/ui/test-thread-nocapture.run.stdout +++ b/src/test/ui/test-thread-nocapture.run.stdout @@ -16,5 +16,5 @@ failures: failures: thready_fail -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/test/ui/threads-sendsync/sync-send-in-std.rs b/src/test/ui/threads-sendsync/sync-send-in-std.rs index 15e10dc250..b8ae214dc0 100644 --- a/src/test/ui/threads-sendsync/sync-send-in-std.rs +++ b/src/test/ui/threads-sendsync/sync-send-in-std.rs @@ -1,6 +1,5 @@ // run-pass -// ignore-cloudabi networking not available // ignore-wasm32-bare networking not available // ignore-sgx ToSocketAddrs cannot be used for DNS Resolution diff --git a/src/test/ui/threads-sendsync/task-stderr.rs b/src/test/ui/threads-sendsync/task-stderr.rs index bc4bedac19..78145e337d 100644 --- a/src/test/ui/threads-sendsync/task-stderr.rs +++ b/src/test/ui/threads-sendsync/task-stderr.rs @@ -1,33 +1,21 @@ // run-pass // ignore-emscripten no threads support -#![feature(box_syntax, set_stdio)] +#![feature(internal_output_capture)] -use std::io::prelude::*; use std::io; use std::str; use std::sync::{Arc, Mutex}; use std::thread; -struct Sink(Arc>>); -impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} -impl io::LocalOutput for Sink { - fn clone_box(&self) -> Box { - Box::new(Sink(self.0.clone())) - } -} - fn main() { let data = Arc::new(Mutex::new(Vec::new())); - let sink = Sink(data.clone()); - let res = thread::Builder::new().spawn(move|| -> () { - io::set_panic(Some(Box::new(sink))); - panic!("Hello, world!") + let res = thread::Builder::new().spawn({ + let data = data.clone(); + move || { + io::set_output_capture(Some(data)); + panic!("Hello, world!") + } }).unwrap().join(); assert!(res.is_err()); diff --git a/src/test/ui/traits/issue-79458.rs b/src/test/ui/traits/issue-79458.rs new file mode 100644 index 0000000000..a41add6a1c --- /dev/null +++ b/src/test/ui/traits/issue-79458.rs @@ -0,0 +1,10 @@ +// Negative implementations should not be shown in trait suggestions. +// This is a regression test of #79458. + +#[derive(Clone)] +struct Foo<'a, T> { + bar: &'a mut T + //~^ ERROR the trait bound `&mut T: Clone` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/traits/issue-79458.stderr b/src/test/ui/traits/issue-79458.stderr new file mode 100644 index 0000000000..54947b57c0 --- /dev/null +++ b/src/test/ui/traits/issue-79458.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&mut T: Clone` is not satisfied + --> $DIR/issue-79458.rs:6:5 + | +LL | bar: &'a mut T + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&mut T` + | + = help: the following implementations were found: + <&T as Clone> + = note: `Clone` is implemented for `&T`, but not for `&mut T` + = note: required by `clone` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs new file mode 100644 index 0000000000..3e33693393 --- /dev/null +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs @@ -0,0 +1,53 @@ +// This tests issue #79683: note in the error message that the trait is +// explicitely unimplemented instead of suggesting to implement it. + +#![feature(negative_impls)] + +struct Qux; +//~^ NOTE method `clone` not found for this +//~^^ NOTE method `foo` not found for this + +impl !Clone for Qux {} + +trait Bar { + fn bar(&self); +} + +impl !Bar for u32 {} + +trait Foo { + fn foo(&self); +} +//~^^^ NOTE `Foo` defines an item `foo`, perhaps you need to implement it + +trait FooBar { + fn foo(&self); +} + +impl !Foo for Qux {} + +impl !FooBar for Qux {} + +impl !FooBar for u32 {} + +fn main() { + Qux.clone(); + //~^ ERROR no method named `clone` found for struct `Qux` + //~| NOTE method not found in `Qux` + //~| NOTE `Clone` defines an item `clone`, but is explicitely unimplemented + + 0_u32.bar(); + //~^ ERROR no method named `bar` found for type `u32` + //~| NOTE method not found in `u32` + //~| NOTE `Bar` defines an item `bar`, but is explicitely unimplemented + + Qux.foo(); + //~^ ERROR no method named `foo` found for struct `Qux` + //~| NOTE method not found in `Qux` + //~| NOTE the following traits define an item `foo`, but are explicitely unimplemented + + 0_u32.foo(); + //~^ ERROR no method named `foo` found for type `u32` + //~| NOTE method not found in `u32` + //~| NOTE `FooBar` defines an item `foo`, but is explicitely unimplemented +} diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr new file mode 100644 index 0000000000..d39daaba20 --- /dev/null +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr @@ -0,0 +1,60 @@ +error[E0599]: no method named `clone` found for struct `Qux` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:34:9 + | +LL | struct Qux; + | ----------- method `clone` not found for this +... +LL | Qux.clone(); + | ^^^^^ method not found in `Qux` + | + ::: $SRC_DIR/core/src/clone.rs:LL:COL + | +LL | fn clone(&self) -> Self; + | ----- + | | + | the method is available for `Arc` here + | the method is available for `Rc` here + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the trait `Clone` defines an item `clone`, but is explicitely unimplemented + +error[E0599]: no method named `bar` found for type `u32` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:39:11 + | +LL | 0_u32.bar(); + | ^^^ method not found in `u32` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the trait `Bar` defines an item `bar`, but is explicitely unimplemented + +error[E0599]: no method named `foo` found for struct `Qux` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:44:9 + | +LL | struct Qux; + | ----------- method `foo` not found for this +... +LL | Qux.foo(); + | ^^^ method not found in `Qux` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `foo`, but are explicitely unimplemented: + Foo + FooBar + +error[E0599]: no method named `foo` found for type `u32` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:49:11 + | +LL | 0_u32.foo(); + | ^^^ method not found in `u32` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/explicitly-unimplemented-error-message.rs:18:1 + | +LL | trait Foo { + | ^^^^^^^^^ + = note: the trait `FooBar` defines an item `foo`, but is explicitely unimplemented + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/traits/trait-object-vs-lifetime.stderr b/src/test/ui/traits/trait-object-vs-lifetime.stderr index ff3fc2a197..8958547e82 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime.stderr @@ -27,8 +27,6 @@ error[E0747]: type provided when a lifetime was expected | LL | let _: S; | ^^^^^^^^^^^^^ - | - = note: lifetime arguments must be provided before type arguments error: aborting due to 5 previous errors diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.rs b/src/test/ui/traits/traits-inductive-overflow-supertrait-auto-trait.rs similarity index 60% rename from src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.rs rename to src/test/ui/traits/traits-inductive-overflow-supertrait-auto-trait.rs index 571f934fc5..5fea47a1be 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-auto-trait.rs @@ -1,8 +1,8 @@ -// OIBIT-based version of #29859, supertrait version. Test that using -// a simple OIBIT `..` impl alone still doesn't allow arbitrary bounds +// Auto-trait-based version of #29859, supertrait version. Test that using +// a simple auto trait `..` impl alone still doesn't allow arbitrary bounds // to be synthesized. -#![feature(optin_builtin_traits)] +#![feature(auto_traits)] #![feature(negative_impls)] auto trait Magic: Copy {} //~ ERROR E0568 diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait-auto-trait.stderr similarity index 85% rename from src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr rename to src/test/ui/traits/traits-inductive-overflow-supertrait-auto-trait.stderr index c11234ee48..140ffa4b07 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-auto-trait.stderr @@ -1,5 +1,5 @@ error[E0568]: auto traits cannot have super traits - --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:8:19 + --> $DIR/traits-inductive-overflow-supertrait-auto-trait.rs:8:19 | LL | auto trait Magic: Copy {} | ----- ^^^^ help: remove the super traits @@ -7,7 +7,7 @@ LL | auto trait Magic: Copy {} | auto trait cannot have super traits error[E0277]: the trait bound `NoClone: Copy` is not satisfied - --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:16:23 + --> $DIR/traits-inductive-overflow-supertrait-auto-trait.rs:16:23 | LL | fn copy(x: T) -> (T, T) { (x, x) } | ----- required by this bound in `copy` diff --git a/src/test/ui/try-is-identifier-edition2015.rs b/src/test/ui/try-is-identifier-edition2015.rs index dfb05599be..90f56d5fa7 100644 --- a/src/test/ui/try-is-identifier-edition2015.rs +++ b/src/test/ui/try-is-identifier-edition2015.rs @@ -5,7 +5,7 @@ fn main() { let try = 2; - struct try { try: u32 }; + struct try { try: u32 } let try: try = try { try }; assert_eq!(try.try, 2); } diff --git a/src/test/ui/try-operator-on-main.rs b/src/test/ui/try-operator-on-main.rs index a8a99a150c..e1b6cfbe5a 100644 --- a/src/test/ui/try-operator-on-main.rs +++ b/src/test/ui/try-operator-on-main.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::fs support - #![feature(try_trait)] use std::ops::Try; diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr index f2e17812ae..be17de2fe7 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-operator-on-main.stderr @@ -1,5 +1,5 @@ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-operator-on-main.rs:9:5 + --> $DIR/try-operator-on-main.rs:7:5 | LL | / fn main() { LL | | // error for a `Try` type on a non-`Try` fn @@ -15,7 +15,7 @@ LL | | } = note: required by `from_error` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/try-operator-on-main.rs:12:5 + --> $DIR/try-operator-on-main.rs:10:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` @@ -24,7 +24,7 @@ LL | ()?; = note: required by `into_result` error[E0277]: the trait bound `(): Try` is not satisfied - --> $DIR/try-operator-on-main.rs:15:25 + --> $DIR/try-operator-on-main.rs:13:25 | LL | try_trait_generic::<()>(); | ^^ the trait `Try` is not implemented for `()` @@ -33,7 +33,7 @@ LL | fn try_trait_generic() -> T { | --- required by this bound in `try_trait_generic` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/try-operator-on-main.rs:22:5 + --> $DIR/try-operator-on-main.rs:20:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` diff --git a/src/test/ui/try-operator.rs b/src/test/ui/try-operator.rs index 9118e8e713..516ae4c409 100644 --- a/src/test/ui/try-operator.rs +++ b/src/test/ui/try-operator.rs @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] -// ignore-cloudabi no std::fs use std::fs::File; use std::io::{Read, self}; diff --git a/src/test/ui/try-wait.rs b/src/test/ui/try-wait.rs index d8a07c55cf..692197210b 100644 --- a/src/test/ui/try-wait.rs +++ b/src/test/ui/try-wait.rs @@ -1,7 +1,6 @@ // run-pass #![allow(stable_features)] -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes diff --git a/src/test/ui/type/ascription/issue-34255-1.rs b/src/test/ui/type/ascription/issue-34255-1.rs index c0d39c5901..3aad085f08 100644 --- a/src/test/ui/type/ascription/issue-34255-1.rs +++ b/src/test/ui/type/ascription/issue-34255-1.rs @@ -7,7 +7,7 @@ impl Reactor { input_cells: Vec::new() //~^ ERROR cannot find value `input_cells` in this scope //~| ERROR parenthesized type parameters may only be used with a `Fn` trait - //~| ERROR wrong number of type arguments: expected 1, found 0 + //~| ERROR wrong number of type arguments: expected at least 1, found 0 } } diff --git a/src/test/ui/type/ascription/issue-34255-1.stderr b/src/test/ui/type/ascription/issue-34255-1.stderr index 7895cf77fc..402e54d2a9 100644 --- a/src/test/ui/type/ascription/issue-34255-1.stderr +++ b/src/test/ui/type/ascription/issue-34255-1.stderr @@ -10,11 +10,11 @@ error[E0214]: parenthesized type parameters may only be used with a `Fn` trait LL | input_cells: Vec::new() | ^^^^^ only `Fn` traits may use parentheses -error[E0107]: wrong number of type arguments: expected 1, found 0 +error[E0107]: wrong number of type arguments: expected at least 1, found 0 --> $DIR/issue-34255-1.rs:7:22 | LL | input_cells: Vec::new() - | ^^^^^^^^^^ expected 1 type argument + | ^^^^^^^^^^ expected at least 1 type argument error: aborting due to 3 previous errors diff --git a/src/test/ui/typeck/auxiliary/tdticc_coherence_lib.rs b/src/test/ui/typeck/auxiliary/tdticc_coherence_lib.rs index d00025b770..ef2cd415fc 100644 --- a/src/test/ui/typeck/auxiliary/tdticc_coherence_lib.rs +++ b/src/test/ui/typeck/auxiliary/tdticc_coherence_lib.rs @@ -1,4 +1,4 @@ -#![feature(optin_builtin_traits, core)] +#![feature(auto_traits, core)] #![crate_type = "rlib"] pub auto trait DefaultedTrait { } diff --git a/src/test/ui/typeck/issue-80207-unsized-return.rs b/src/test/ui/typeck/issue-80207-unsized-return.rs new file mode 100644 index 0000000000..75430da148 --- /dev/null +++ b/src/test/ui/typeck/issue-80207-unsized-return.rs @@ -0,0 +1,20 @@ +// check-pass + +trait Foo { + fn do_stuff() -> Self; +} + +trait Bar { + type Output; +} + +impl Foo for dyn Bar +where + Self: Sized, +{ + fn do_stuff() -> Self { + todo!() + } +} + +fn main() {} diff --git a/src/test/ui/union/union-transmute.rs b/src/test/ui/union/union-transmute.rs index ac7dede98a..be8062f627 100644 --- a/src/test/ui/union/union-transmute.rs +++ b/src/test/ui/union/union-transmute.rs @@ -1,8 +1,5 @@ // run-pass -extern crate core; -use core::f32; - union U { a: (u8, u8), b: u16, diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 10f0c46756..6adf0ac59b 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,4 +1,6 @@ +#![feature(untagged_unions)] use std::mem::ManuallyDrop; +use std::cell::RefCell; union U1 { a: u8 @@ -16,9 +18,28 @@ union U4 { a: T } +union URef { + p: &'static mut i32, +} + +union URefCell { // field that does not drop but is not `Copy`, either + a: (RefCell, i32), +} + +fn deref_union_field(mut u: URef) { + // Not an assignment but an access to the union field! + *(u.p) = 13; //~ ERROR access to union field is unsafe +} + +fn assign_noncopy_union_field(mut u: URefCell) { + u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping + u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping + u.a.1 = 1; // OK +} + fn generic_noncopy() { let mut u3 = U3 { a: ManuallyDrop::new(T::default()) }; - u3.a = ManuallyDrop::new(T::default()); //~ ERROR assignment to non-`Copy` union field is unsafe + u3.a = ManuallyDrop::new(T::default()); // OK (assignment does not drop) *u3.a = T::default(); //~ ERROR access to union field is unsafe } @@ -41,7 +62,7 @@ fn main() { // let U1 { .. } = u1; // OK let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK - u2.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union + u2.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop) *u2.a = String::from("new"); //~ ERROR access to union field is unsafe let mut u3 = U3 { a: ManuallyDrop::new(0) }; // OK @@ -49,6 +70,6 @@ fn main() { *u3.a = 1; //~ ERROR access to union field is unsafe let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK - u3.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union + u3.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop) *u3.a = String::from("new"); //~ ERROR access to union field is unsafe } diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index b50d9e1750..a25c09144f 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,13 +1,29 @@ -error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:21:5 +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:31:5 + | +LL | *(u.p) = 13; + | ^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:35:5 | -LL | u3.a = ManuallyDrop::new(T::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field +LL | u.a = (RefCell::new(0), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping + | + = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized + +error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:36:5 + | +LL | u.a.0 = RefCell::new(0); + | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:22:6 + --> $DIR/union-unsafe.rs:43:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -15,7 +31,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:28:6 + --> $DIR/union-unsafe.rs:49:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -23,7 +39,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:36:13 + --> $DIR/union-unsafe.rs:57:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -31,7 +47,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:39:14 + --> $DIR/union-unsafe.rs:60:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -39,23 +55,15 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:20 + --> $DIR/union-unsafe.rs:61:20 | LL | if let U1 { a: 12 } = u1 {} | ^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:44:5 - | -LL | u2.a = ManuallyDrop::new(String::from("new")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:45:6 + --> $DIR/union-unsafe.rs:66:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -63,23 +71,15 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:49:6 + --> $DIR/union-unsafe.rs:70:6 | LL | *u3.a = 1; | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:52:5 - | -LL | u3.a = ManuallyDrop::new(String::from("new")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:6 + --> $DIR/union-unsafe.rs:74:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 2e23ddd905..09cbb87533 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -22,7 +22,7 @@ LL | fn clone(&self) -> Self; | LL | / pub struct Box< LL | | T: ?Sized, -LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique, A); | |________________- doesn't satisfy `Box: Clone` | diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index d533724a00..bc08102418 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -19,7 +19,7 @@ LL | fn clone(&self) -> Self; | LL | / pub struct Box< LL | | T: ?Sized, -LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique, A); | |________________- doesn't satisfy `Box: Clone` | diff --git a/src/test/ui/issues/issue-30730.rs b/src/test/ui/unused/issue-30730.rs similarity index 100% rename from src/test/ui/issues/issue-30730.rs rename to src/test/ui/unused/issue-30730.rs diff --git a/src/test/ui/issues/issue-30730.stderr b/src/test/ui/unused/issue-30730.stderr similarity index 100% rename from src/test/ui/issues/issue-30730.stderr rename to src/test/ui/unused/issue-30730.stderr diff --git a/src/test/ui/issues/issue-46576.rs b/src/test/ui/unused/issue-46576.rs similarity index 91% rename from src/test/ui/issues/issue-46576.rs rename to src/test/ui/unused/issue-46576.rs index 821d2724bc..15f458f384 100644 --- a/src/test/ui/issues/issue-46576.rs +++ b/src/test/ui/unused/issue-46576.rs @@ -1,5 +1,3 @@ -// ignore-cloudabi no std::fs support - #![allow(dead_code)] #![deny(unused_imports)] diff --git a/src/test/ui/issues/issue-46576.stderr b/src/test/ui/unused/issue-46576.stderr similarity index 80% rename from src/test/ui/issues/issue-46576.stderr rename to src/test/ui/unused/issue-46576.stderr index 1e5e730ee6..6f4d97068b 100644 --- a/src/test/ui/issues/issue-46576.stderr +++ b/src/test/ui/unused/issue-46576.stderr @@ -1,11 +1,11 @@ error: unused import: `BufRead` - --> $DIR/issue-46576.rs:7:15 + --> $DIR/issue-46576.rs:5:15 | LL | use std::io::{BufRead, BufReader, Read}; | ^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-46576.rs:4:9 + --> $DIR/issue-46576.rs:2:9 | LL | #![deny(unused_imports)] | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-59896.rs b/src/test/ui/unused/issue-59896.rs similarity index 100% rename from src/test/ui/issues/issue-59896.rs rename to src/test/ui/unused/issue-59896.rs diff --git a/src/test/ui/issues/issue-59896.stderr b/src/test/ui/unused/issue-59896.stderr similarity index 100% rename from src/test/ui/issues/issue-59896.stderr rename to src/test/ui/unused/issue-59896.stderr diff --git a/src/test/ui/issues/issue-70041.rs b/src/test/ui/unused/issue-70041.rs similarity index 100% rename from src/test/ui/issues/issue-70041.rs rename to src/test/ui/unused/issue-70041.rs diff --git a/src/test/ui/issues/issue-70041.stderr b/src/test/ui/unused/issue-70041.stderr similarity index 100% rename from src/test/ui/issues/issue-70041.stderr rename to src/test/ui/unused/issue-70041.stderr diff --git a/src/test/ui/use-module-level-int-consts.rs b/src/test/ui/use-module-level-int-consts.rs index 758fb414ea..200f742d77 100644 --- a/src/test/ui/use-module-level-int-consts.rs +++ b/src/test/ui/use-module-level-int-consts.rs @@ -2,6 +2,7 @@ // Make sure the module level constants are still there and accessible even after // the corresponding associated constants have been added, and later stabilized. +#![allow(deprecated, deprecated_in_future)] use std::{u16, f32}; fn main() { diff --git a/src/test/ui/utf8.rs b/src/test/ui/utf8.rs deleted file mode 100644 index 75b6ddf789..0000000000 --- a/src/test/ui/utf8.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -pub fn main() { - let yen: char = 'Â¥'; // 0xa5 - let c_cedilla: char = 'ç'; // 0xe7 - let thorn: char = 'þ'; // 0xfe - let y_diaeresis: char = 'ÿ'; // 0xff - let pi: char = 'Π'; // 0x3a0 - - assert_eq!(yen as isize, 0xa5); - assert_eq!(c_cedilla as isize, 0xe7); - assert_eq!(thorn as isize, 0xfe); - assert_eq!(y_diaeresis as isize, 0xff); - assert_eq!(pi as isize, 0x3a0); - - assert_eq!(pi as isize, '\u{3a0}' as isize); - assert_eq!('\x0a' as isize, '\n' as isize); - - let bhutan: String = "འབྲུག་ཡུལ།".to_string(); - let japan: String = "日本".to_string(); - let uzbekistan: String = "Ўзбекистон".to_string(); - let austria: String = "Österreich".to_string(); - - let bhutan_e: String = - "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); - let japan_e: String = "\u{65e5}\u{672c}".to_string(); - let uzbekistan_e: String = - "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); - let austria_e: String = "\u{d6}sterreich".to_string(); - - let oo: char = 'Ö'; - assert_eq!(oo as isize, 0xd6); - - fn check_str_eq(a: String, b: String) { - let mut i: isize = 0; - for ab in a.bytes() { - println!("{}", i); - println!("{}", ab); - let bb: u8 = b.as_bytes()[i as usize]; - println!("{}", bb); - assert_eq!(ab, bb); - i += 1; - } - } - - check_str_eq(bhutan, bhutan_e); - check_str_eq(japan, japan_e); - check_str_eq(uzbekistan, uzbekistan_e); - check_str_eq(austria, austria_e); -} diff --git a/src/test/ui/utf8_chars.rs b/src/test/ui/utf8_chars.rs deleted file mode 100644 index d764509813..0000000000 --- a/src/test/ui/utf8_chars.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -use std::str; - -pub fn main() { - // Chars of 1, 2, 3, and 4 bytes - let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; - let s: String = chs.iter().cloned().collect(); - let schs: Vec = s.chars().collect(); - - assert_eq!(s.len(), 10); - assert_eq!(s.chars().count(), 4); - assert_eq!(schs.len(), 4); - assert_eq!(schs.iter().cloned().collect::(), s); - - assert!((str::from_utf8(s.as_bytes()).is_ok())); - // invalid prefix - assert!((!str::from_utf8(&[0x80]).is_ok())); - // invalid 2 byte prefix - assert!((!str::from_utf8(&[0xc0]).is_ok())); - assert!((!str::from_utf8(&[0xc0, 0x10]).is_ok())); - // invalid 3 byte prefix - assert!((!str::from_utf8(&[0xe0]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); - // invalid 4 byte prefix - assert!((!str::from_utf8(&[0xf0]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); -} diff --git a/src/test/ui/wait-forked-but-failed-child.rs b/src/test/ui/wait-forked-but-failed-child.rs index 08b16c0e9c..2683590775 100644 --- a/src/test/ui/wait-forked-but-failed-child.rs +++ b/src/test/ui/wait-forked-but-failed-child.rs @@ -1,5 +1,4 @@ // run-pass -// ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes // ignore-vxworks no 'ps' diff --git a/src/test/ui/weird-exprs.rs b/src/test/ui/weird-exprs.rs index 916cabbfb8..2d7ebbf1d5 100644 --- a/src/test/ui/weird-exprs.rs +++ b/src/test/ui/weird-exprs.rs @@ -1,6 +1,7 @@ // run-pass #![feature(generators)] +#![feature(destructuring_assignment)] #![allow(non_camel_case_types)] #![allow(dead_code)] @@ -159,6 +160,11 @@ fn match_nested_if() { assert!(val); } +fn monkey_barrel() { + let val = ()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=(); + assert_eq!(val, ()); +} + pub fn main() { strange(); funny(); @@ -177,4 +183,5 @@ pub fn main() { r#match(); i_yield(); match_nested_if(); + monkey_barrel(); } diff --git a/src/test/ui/wrapping-int-api.rs b/src/test/ui/wrapping-int-api.rs deleted file mode 100644 index ecdd742fb4..0000000000 --- a/src/test/ui/wrapping-int-api.rs +++ /dev/null @@ -1,228 +0,0 @@ -// run-pass -// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}. - -// Don't warn about overflowing ops on 32-bit platforms -#![cfg_attr(target_pointer_width = "32", allow(const_err))] - -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; - -fn main() { - assert_eq!( i8::MAX.wrapping_add(1), i8::MIN); - assert_eq!( i16::MAX.wrapping_add(1), i16::MIN); - assert_eq!( i32::MAX.wrapping_add(1), i32::MIN); - assert_eq!( i64::MAX.wrapping_add(1), i64::MIN); - assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); - - assert_eq!( i8::MIN.wrapping_sub(1), i8::MAX); - assert_eq!( i16::MIN.wrapping_sub(1), i16::MAX); - assert_eq!( i32::MIN.wrapping_sub(1), i32::MAX); - assert_eq!( i64::MIN.wrapping_sub(1), i64::MAX); - assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); - - assert_eq!( u8::MAX.wrapping_add(1), u8::MIN); - assert_eq!( u16::MAX.wrapping_add(1), u16::MIN); - assert_eq!( u32::MAX.wrapping_add(1), u32::MIN); - assert_eq!( u64::MAX.wrapping_add(1), u64::MIN); - assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); - - assert_eq!( u8::MIN.wrapping_sub(1), u8::MAX); - assert_eq!( u16::MIN.wrapping_sub(1), u16::MAX); - assert_eq!( u32::MIN.wrapping_sub(1), u32::MAX); - assert_eq!( u64::MIN.wrapping_sub(1), u64::MAX); - assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); - - assert_eq!((0xfe_u8 as i8).wrapping_mul(16), - (0xe0_u8 as i8)); - assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), - (0xedc0_u16 as i16)); - assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), - (0xedcb_a980_u32 as i32)); - assert_eq!((0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as i64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), - (0xedcb_a980_u32 as isize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as isize)); - } - } - - assert_eq!((0xfe as u8).wrapping_mul(16), - (0xe0 as u8)); - assert_eq!((0xfedc as u16).wrapping_mul(16), - (0xedc0 as u16)); - assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), - (0xedcb_a980 as u32)); - assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), - (0xedcb_a987_6543_2170 as u64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), - (0xedcb_a980 as usize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), - (0xedcb_a987_6543_2170 as usize)); - } - } - - macro_rules! check_mul_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), ($e) * $f); } - } - macro_rules! check_mul_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), $e); } - } - - check_mul_no_wrap!(0xfe_u8 as i8, -1); - check_mul_no_wrap!(0xfedc_u16 as i16, -1); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_mul_no_wrap!(0xfe_u8 as i8, -2); - check_mul_no_wrap!(0xfedc_u16 as i16, -2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); - - check_mul_no_wrap!(0xfe_u8 as i8, 2); - check_mul_no_wrap!(0xfedc_u16 as i16, 2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); - - check_mul_wraps!(0x80_u8 as i8, -1); - check_mul_wraps!(0x8000_u16 as i16, -1); - check_mul_wraps!(0x8000_0000_u32 as i32, -1); - check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_mul_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_div_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), ($e) / $f); } - } - macro_rules! check_div_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), $e); } - } - - check_div_no_wrap!(0xfe_u8 as i8, -1); - check_div_no_wrap!(0xfedc_u16 as i16, -1); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_div_no_wrap!(0xfe_u8 as i8, -2); - check_div_no_wrap!(0xfedc_u16 as i16, -2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_div_no_wrap!(0xfe_u8 as i8, 2); - check_div_no_wrap!(0xfedc_u16 as i16, 2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_div_wraps!(-128 as i8, -1); - check_div_wraps!(0x8000_u16 as i16, -1); - check_div_wraps!(0x8000_0000_u32 as i32, -1); - check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_div_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - - macro_rules! check_rem_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), ($e) % $f); } - } - macro_rules! check_rem_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), 0); } - } - - check_rem_no_wrap!(0xfe_u8 as i8, -1); - check_rem_no_wrap!(0xfedc_u16 as i16, -1); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_rem_no_wrap!(0xfe_u8 as i8, -2); - check_rem_no_wrap!(0xfedc_u16 as i16, -2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_rem_no_wrap!(0xfe_u8 as i8, 2); - check_rem_no_wrap!(0xfedc_u16 as i16, 2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_rem_wraps!(0x80_u8 as i8, -1); - check_rem_wraps!(0x8000_u16 as i16, -1); - check_rem_wraps!(0x8000_0000_u32 as i32, -1); - check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_rem_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_neg_no_wrap { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), -($e)); } - } - macro_rules! check_neg_wraps { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), ($e)); } - } - - check_neg_no_wrap!(0xfe_u8 as i8); - check_neg_no_wrap!(0xfedc_u16 as i16); - check_neg_no_wrap!(0xfedc_ba98_u32 as i32); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); - - check_neg_wraps!(0x80_u8 as i8); - check_neg_wraps!(0x8000_u16 as i16); - check_neg_wraps!(0x8000_0000_u32 as i32); - check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_neg_wraps!(0x8000_0000_u32 as isize); - } - #[cfg(target_pointer_width = "64")] - () => { - check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); - } - } - -} diff --git a/src/test/ui/x86stdcall.rs b/src/test/ui/x86stdcall.rs index 32a4df87fb..e1136807b3 100644 --- a/src/test/ui/x86stdcall.rs +++ b/src/test/ui/x86stdcall.rs @@ -24,7 +24,6 @@ pub fn main() { } #[cfg(any(target_os = "android", - target_os = "cloudabi", target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", diff --git a/src/test/ui/zero-sized/zero-size-type-destructors.rs b/src/test/ui/zero-sized/zero-size-type-destructors.rs index 98b5a439c8..fb87d8ea0b 100644 --- a/src/test/ui/zero-sized/zero-size-type-destructors.rs +++ b/src/test/ui/zero-sized/zero-size-type-destructors.rs @@ -10,7 +10,7 @@ pub fn foo() { fn drop(&mut self) { unsafe { destructions -= 1 }; } - }; + } let _x = [Foo, Foo, Foo]; } diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 687354dc6a..73a4cbd079 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -57,7 +57,6 @@ static TARGETS: &[&str] = &[ "aarch64-fuchsia", "aarch64-linux-android", "aarch64-pc-windows-msvc", - "aarch64-unknown-cloudabi", "aarch64-unknown-hermit", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", @@ -143,7 +142,6 @@ static TARGETS: &[&str] = &[ "x86_64-rumprun-netbsd", "x86_64-sun-solaris", "x86_64-pc-solaris", - "x86_64-unknown-cloudabi", "x86_64-unknown-freebsd", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", @@ -301,6 +299,7 @@ impl Builder { let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets); package("rustc", HOSTS); package("rustc-dev", HOSTS); + package("reproducible-artifacts", HOSTS); package("rustc-docs", HOSTS); package("cargo", HOSTS); package("rust-mingw", MINGW); diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 8aabe077cf..0a6bac48eb 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -36,7 +36,7 @@ const TEST_REPOS: &[Test] = &[ Test { name: "xsv", repo: "https://github.com/BurntSushi/xsv", - sha: "66956b6bfd62d6ac767a6b6499c982eae20a2c9f", + sha: "3de6c04269a7d315f7e9864b9013451cd9580a08", lock: None, packages: &[], }, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 24ef98cd78..80fbb06b94 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -17,6 +17,7 @@ pub enum Mode { DebugInfo, Codegen, Rustdoc, + RustdocJson, CodegenUnits, Incremental, RunMake, @@ -48,6 +49,7 @@ impl FromStr for Mode { "debuginfo" => Ok(DebugInfo), "codegen" => Ok(Codegen), "rustdoc" => Ok(Rustdoc), + "rustdoc-json" => Ok(RustdocJson), "codegen-units" => Ok(CodegenUnits), "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), @@ -70,6 +72,7 @@ impl fmt::Display for Mode { DebugInfo => "debuginfo", Codegen => "codegen", Rustdoc => "rustdoc", + RustdocJson => "rustdoc-json", CodegenUnits => "codegen-units", Incremental => "incremental", RunMake => "run-make", @@ -124,6 +127,8 @@ pub enum CompareMode { Nll, Polonius, Chalk, + SplitDwarf, + SplitDwarfSingle, } impl CompareMode { @@ -132,6 +137,8 @@ impl CompareMode { CompareMode::Nll => "nll", CompareMode::Polonius => "polonius", CompareMode::Chalk => "chalk", + CompareMode::SplitDwarf => "split-dwarf", + CompareMode::SplitDwarfSingle => "split-dwarf-single", } } @@ -140,6 +147,8 @@ impl CompareMode { "nll" => CompareMode::Nll, "polonius" => CompareMode::Polonius, "chalk" => CompareMode::Chalk, + "split-dwarf" => CompareMode::SplitDwarf, + "split-dwarf-single" => CompareMode::SplitDwarfSingle, x => panic!("unknown --compare-mode option: {}", x), } } @@ -324,6 +333,9 @@ pub struct Config { /// created in `//rustfix_missing_coverage.txt` pub rustfix_coverage: bool, + /// whether to run `tidy` when a rustdoc test fails + pub has_tidy: bool, + // Configuration for various run-make tests frobbing things like C compilers // or querying about various LLVM component information. pub cc: String, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 59f64e7df0..a1be0a19f6 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -852,6 +852,8 @@ impl Config { Some(CompareMode::Nll) => name == "compare-mode-nll", Some(CompareMode::Polonius) => name == "compare-mode-polonius", Some(CompareMode::Chalk) => name == "compare-mode-chalk", + Some(CompareMode::SplitDwarf) => name == "compare-mode-split-dwarf", + Some(CompareMode::SplitDwarfSingle) => name == "compare-mode-split-dwarf-single", None => false, } || (cfg!(debug_assertions) && name == "debug") || diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 19aec0ea59..8d23227fdb 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -153,11 +153,14 @@ fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> if serde_json::from_str::(line).is_ok() { vec![] } else { - proc_res.fatal(Some(&format!( - "failed to decode compiler output as json: \ + proc_res.fatal( + Some(&format!( + "failed to decode compiler output as json: \ `{}`\nline: {}\noutput: {}", - error, line, output - ))); + error, line, output + )), + || (), + ); } } } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 2b167ac8e9..c63bbaf70d 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -14,7 +14,7 @@ use std::ffi::OsString; use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use std::time::SystemTime; use test::ColorConfig; use tracing::*; @@ -43,6 +43,10 @@ fn main() { panic!("Can't find Valgrind to run Valgrind tests"); } + if !config.has_tidy && config.mode == Mode::Rustdoc { + eprintln!("warning: `tidy` is not installed; generated diffs will be harder to read"); + } + log_config(&config); run_tests(config); } @@ -68,7 +72,7 @@ pub fn parse_config(args: Vec) -> Config { "mode", "which sort of compile tests to run", "compile-fail | run-fail | run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", ) .reqopt( "", @@ -189,6 +193,11 @@ pub fn parse_config(args: Vec) -> Config { let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); + let has_tidy = Command::new("tidy") + .arg("--version") + .stdout(Stdio::null()) + .status() + .map_or(false, |status| status.success()); Config { bless: matches.opt_present("bless"), compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), @@ -244,6 +253,7 @@ pub fn parse_config(args: Vec) -> Config { remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse), rustfix_coverage: matches.opt_present("rustfix-coverage"), + has_tidy, cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), @@ -379,7 +389,7 @@ pub fn run_tests(config: Config) { } Err(e) => { // We don't know if tests passed or not, but if there was an error - // during testing we don't want to just suceeed (we may not have + // during testing we don't want to just succeed (we may not have // tested something), so fail. // // This should realistically "never" happen, so don't try to make @@ -508,8 +518,6 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp.add_path(&rustdoc_path); stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); } - // FIXME(richkadel): Do I need to add an `if let Some(rust_demangler_path) contribution to the - // stamp here as well? // Compiletest itself. stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index d46f905e6c..828c4e89f0 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2,7 +2,7 @@ use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT}; use crate::common::{output_base_dir, output_base_name, output_testname_unique}; -use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, Ui}; +use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui}; use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{CompileFail, Pretty, RunFail, RunPassValgrind}; @@ -287,6 +287,7 @@ pub fn compute_stamp_hash(config: &Config) -> String { format!("{:x}", hash.finish()) } +#[derive(Copy, Clone)] struct TestCx<'test> { config: &'test Config, props: &'test TestProps, @@ -341,6 +342,7 @@ impl<'test> TestCx<'test> { DebugInfo => self.run_debuginfo_test(), Codegen => self.run_codegen_test(), Rustdoc => self.run_rustdoc_test(), + RustdocJson => self.run_rustdoc_json_test(), CodegenUnits => self.run_codegen_units_test(), Incremental => self.run_incremental_test(), RunMake => self.run_rmake_test(), @@ -977,7 +979,8 @@ impl<'test> TestCx<'test> { script_str.push_str("set print pretty off\n"); // Add the pretty printer directory to GDB's source-file search path - script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)); + script_str + .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\"))); // Load the target executable script_str @@ -1598,6 +1601,10 @@ impl<'test> TestCx<'test> { .arg(&self.testpaths.file) .args(&self.props.compile_flags); + if self.config.mode == RustdocJson { + rustdoc.arg("--output-format").arg("json"); + } + if let Some(ref linker) = self.config.linker { rustdoc.arg(format!("-Clinker={}", linker)); } @@ -1728,7 +1735,7 @@ impl<'test> TestCx<'test> { self.config.target.contains("vxworks") && !self.is_vxworks_pure_static() } - fn compose_and_run_compiler(&self, mut rustc: Command, input: Option) -> ProcRes { + fn build_all_auxiliary(&self, rustc: &mut Command) -> PathBuf { let aux_dir = self.aux_output_dir_name(); if !self.props.aux_builds.is_empty() { @@ -1747,6 +1754,11 @@ impl<'test> TestCx<'test> { rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name)); } + aux_dir + } + + fn compose_and_run_compiler(&self, mut rustc: Command, input: Option) -> ProcRes { + let aux_dir = self.build_all_auxiliary(&mut rustc); self.props.unset_rustc_env.clone().iter().fold(&mut rustc, |rustc, v| rustc.env_remove(v)); rustc.envs(self.props.rustc_env.clone()); self.compose_and_run( @@ -1783,8 +1795,7 @@ impl<'test> TestCx<'test> { let (dylib, crate_type) = if aux_props.no_prefer_dynamic { (true, None) - } else if self.config.target.contains("cloudabi") - || self.config.target.contains("emscripten") + } else if self.config.target.contains("emscripten") || (self.config.target.contains("musl") && !aux_props.force_host && !self.config.host.contains("musl")) @@ -1881,7 +1892,9 @@ impl<'test> TestCx<'test> { } fn is_rustdoc(&self) -> bool { - self.config.src_base.ends_with("rustdoc-ui") || self.config.src_base.ends_with("rustdoc-js") + self.config.src_base.ends_with("rustdoc-ui") + || self.config.src_base.ends_with("rustdoc-js") + || self.config.src_base.ends_with("rustdoc-json") } fn make_compile_args( @@ -1962,8 +1975,8 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } - RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RunMake - | CodegenUnits | JsDocTest | Assembly => { + RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson + | RunMake | CodegenUnits | JsDocTest | Assembly => { // do not use JSON output } } @@ -2004,6 +2017,12 @@ impl<'test> TestCx<'test> { Some(CompareMode::Chalk) => { rustc.args(&["-Zchalk"]); } + Some(CompareMode::SplitDwarf) => { + rustc.args(&["-Zsplit-dwarf=split"]); + } + Some(CompareMode::SplitDwarfSingle) => { + rustc.args(&["-Zsplit-dwarf=single"]); + } None => {} } @@ -2208,7 +2227,17 @@ impl<'test> TestCx<'test> { fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! { self.error(err); - proc_res.fatal(None); + proc_res.fatal(None, || ()); + } + + fn fatal_proc_rec_with_ctx( + &self, + err: &str, + proc_res: &ProcRes, + on_failure: impl FnOnce(Self), + ) -> ! { + self.error(err); + proc_res.fatal(None, || on_failure(*self)); } // codegen tests (using FileCheck) @@ -2325,12 +2354,166 @@ impl<'test> TestCx<'test> { let res = self.cmd2procres( Command::new(&self.config.docck_python) .arg(root.join("src/etc/htmldocck.py")) - .arg(out_dir) + .arg(&out_dir) .arg(&self.testpaths.file), ); if !res.status.success() { - self.fatal_proc_rec("htmldocck failed!", &res); + self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| { + this.compare_to_default_rustdoc(&out_dir) + }); + } + } + } + + fn compare_to_default_rustdoc(&mut self, out_dir: &Path) { + println!("info: generating a diff against nightly rustdoc"); + + let suffix = + self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly"); + let compare_dir = output_base_dir(self.config, self.testpaths, Some(&suffix)); + // Don't give an error if the directory didn't already exist + let _ = fs::remove_dir_all(&compare_dir); + create_dir_all(&compare_dir).unwrap(); + + // We need to create a new struct for the lifetimes on `config` to work. + let new_rustdoc = TestCx { + config: &Config { + // FIXME: use beta or a user-specified rustdoc instead of + // hardcoding the default toolchain + rustdoc_path: Some("rustdoc".into()), + // Needed for building auxiliary docs below + rustc_path: "rustc".into(), + ..self.config.clone() + }, + ..*self + }; + + let output_file = TargetLocation::ThisDirectory(new_rustdoc.aux_output_dir_name()); + let mut rustc = new_rustdoc.make_compile_args( + &new_rustdoc.testpaths.file, + output_file, + EmitMetadata::No, + AllowUnused::Yes, + ); + rustc.arg("-L").arg(&new_rustdoc.aux_output_dir_name()); + new_rustdoc.build_all_auxiliary(&mut rustc); + + let proc_res = new_rustdoc.document(&compare_dir); + if !proc_res.status.success() { + eprintln!("failed to run nightly rustdoc"); + return; + } + + #[rustfmt::skip] + let tidy_args = [ + "--indent", "yes", + "--indent-spaces", "2", + "--wrap", "0", + "--show-warnings", "no", + "--markup", "yes", + "--quiet", "yes", + "-modify", + ]; + let tidy_dir = |dir| { + for entry in walkdir::WalkDir::new(dir) { + let entry = entry.expect("failed to read file"); + if entry.file_type().is_file() + && entry.path().extension().and_then(|p| p.to_str()) == Some("html".into()) + { + let status = + Command::new("tidy").args(&tidy_args).arg(entry.path()).status().unwrap(); + // `tidy` returns 1 if it modified the file. + assert!(status.success() || status.code() == Some(1)); + } } + }; + if self.config.has_tidy { + tidy_dir(out_dir); + tidy_dir(&compare_dir); + } + + let pager = { + let output = Command::new("git").args(&["config", "--get", "core.pager"]).output().ok(); + output.and_then(|out| { + if out.status.success() { + Some(String::from_utf8(out.stdout).expect("invalid UTF8 in git pager")) + } else { + None + } + }) + }; + let mut diff = Command::new("diff"); + // diff recursively, showing context, and excluding .css files + diff.args(&["-u", "-r", "-x", "*.css"]).args(&[&compare_dir, out_dir]); + + let output = if let Some(pager) = pager { + let diff_pid = diff.stdout(Stdio::piped()).spawn().expect("failed to run `diff`"); + let pager = pager.trim(); + if self.config.verbose { + eprintln!("using pager {}", pager); + } + let output = Command::new(pager) + // disable paging; we want this to be non-interactive + .env("PAGER", "") + .stdin(diff_pid.stdout.unwrap()) + // Capture output and print it explicitly so it will in turn be + // captured by libtest. + .output() + .unwrap(); + assert!(output.status.success()); + output + } else { + eprintln!("warning: no pager configured, falling back to `diff --color`"); + eprintln!( + "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`" + ); + let output = diff.arg("--color").output().unwrap(); + assert!(output.status.success() || output.status.code() == Some(1)); + output + }; + println!("{}", String::from_utf8_lossy(&output.stdout)); + eprintln!("{}", String::from_utf8_lossy(&output.stderr)); + } + + fn run_rustdoc_json_test(&self) { + //FIXME: Add bless option. + + assert!(self.revision.is_none(), "revisions not relevant here"); + + let out_dir = self.output_base_dir(); + let _ = fs::remove_dir_all(&out_dir); + create_dir_all(&out_dir).unwrap(); + + let proc_res = self.document(&out_dir); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + + let root = self.config.find_rust_src_root().unwrap(); + let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); + json_out.set_extension("json"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/check_missing_items.py")) + .arg(&json_out), + ); + + if !res.status.success() { + self.fatal_proc_rec("check_missing_items failed!", &res); + } + + let mut expected = self.testpaths.file.clone(); + expected.set_extension("expected"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/compare.py")) + .arg(&expected) + .arg(&json_out) + .arg(&expected.parent().unwrap()), + ); + + if !res.status.success() { + self.fatal_proc_rec("compare failed!", &res); } } @@ -3590,7 +3773,7 @@ pub struct ProcRes { } impl ProcRes { - pub fn fatal(&self, err: Option<&str>) -> ! { + pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! { if let Some(e) = err { println!("\nerror: {}", e); } @@ -3612,6 +3795,7 @@ impl ProcRes { json::extract_rendered(&self.stdout), json::extract_rendered(&self.stderr), ); + on_failure(); // Use resume_unwind instead of panic!() to prevent a panic message + backtrace from // compiletest, which is unnecessary noise. std::panic::resume_unwind(Box::new(())); diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 1a727fc2b8..4f77e719fb 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -12,7 +12,6 @@ mod tests; const OS_TABLE: &[(&str, &str)] = &[ ("android", "android"), ("androideabi", "android"), - ("cloudabi", "cloudabi"), ("cuda", "cuda"), ("darwin", "macos"), ("dragonfly", "dragonfly"), diff --git a/src/tools/expand-yaml-anchors/src/main.rs b/src/tools/expand-yaml-anchors/src/main.rs index f7ff64036a..f8cf18a930 100644 --- a/src/tools/expand-yaml-anchors/src/main.rs +++ b/src/tools/expand-yaml-anchors/src/main.rs @@ -87,7 +87,8 @@ impl App { let content = std::fs::read_to_string(source) .with_context(|| format!("failed to read {}", self.path(source)))?; - let mut buf = HEADER_MESSAGE.replace("{source}", &self.path(source).to_string()); + let mut buf = + HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/")); let documents = YamlLoader::load_from_str(&content) .with_context(|| format!("failed to parse {}", self.path(source)))?; diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index f213944e0a..dcfe1bb803 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -14,6 +14,8 @@ //! A few exceptions are allowed as there's known bugs in rustdoc, but this //! should catch the majority of "broken link" cases. +#![feature(str_split_once)] + use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; use std::env; @@ -232,11 +234,12 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti { return; } - let mut parts = url.splitn(2, '#'); - let url = parts.next().unwrap(); - let fragment = parts.next(); - let mut parts = url.splitn(2, '?'); - let url = parts.next().unwrap(); + let (url, fragment) = match url.split_once('#') { + None => (url, None), + Some((url, fragment)) => (url, Some(fragment)), + }; + // NB: the `splitn` always succeeds, even if the delimiter is not present. + let url = url.splitn(2, '?').next().unwrap(); // Once we've plucked out the URL, parse it using our base url and // then try to extract a file path. diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 6b32ebdc28..0a69b18a33 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -1,11 +1,11 @@ -use crate::Lint; +use crate::{Lint, LintExtractor}; use std::collections::{BTreeMap, BTreeSet}; use std::error::Error; use std::fmt::Write; use std::fs; -use std::path::Path; use std::process::Command; +/// Descriptions of rustc lint groups. static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("unused", "Lints that detect things being declared but not used, or excess syntax"), ("rustdoc", "Rustdoc-specific lints"), @@ -15,100 +15,123 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), ]; -/// Updates the documentation of lint groups. -pub(crate) fn generate_group_docs( - lints: &[Lint], - rustc: crate::Rustc<'_>, - out_path: &Path, -) -> Result<(), Box> { - let groups = collect_groups(rustc)?; - let groups_path = out_path.join("groups.md"); - let contents = fs::read_to_string(&groups_path) - .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; - let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?); - // Delete the output because rustbuild uses hard links in its copies. - let _ = fs::remove_file(&groups_path); - fs::write(&groups_path, new_contents) - .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?; - Ok(()) -} - type LintGroups = BTreeMap>; -/// Collects the group names from rustc. -fn collect_groups(rustc: crate::Rustc<'_>) -> Result> { - let mut result = BTreeMap::new(); - let mut cmd = Command::new(rustc.path); - cmd.arg("-Whelp"); - let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; - if !output.status.success() { - return Err(format!( - "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n", - output.status, - std::str::from_utf8(&output.stderr).unwrap(), - std::str::from_utf8(&output.stdout).unwrap(), - ) - .into()); +impl<'a> LintExtractor<'a> { + /// Updates the documentation of lint groups. + pub(crate) fn generate_group_docs(&self, lints: &[Lint]) -> Result<(), Box> { + let groups = self.collect_groups()?; + let groups_path = self.out_path.join("groups.md"); + let contents = fs::read_to_string(&groups_path) + .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; + let new_contents = + contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&groups_path); + fs::write(&groups_path, new_contents) + .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?; + Ok(()) } - let stdout = std::str::from_utf8(&output.stdout).unwrap(); - let lines = stdout.lines(); - let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1); - let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1); - for line in table_start { - if line.is_empty() { - break; + + /// Collects the group names from rustc. + fn collect_groups(&self) -> Result> { + let mut result = BTreeMap::new(); + let mut cmd = Command::new(self.rustc_path); + cmd.arg("-Whelp"); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + if !output.status.success() { + return Err(format!( + "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n", + output.status, + std::str::from_utf8(&output.stderr).unwrap(), + std::str::from_utf8(&output.stdout).unwrap(), + ) + .into()); } - let mut parts = line.trim().splitn(2, ' '); - let name = parts.next().expect("name in group"); - if name == "warnings" { - // This is special. - continue; + let stdout = std::str::from_utf8(&output.stdout).unwrap(); + let lines = stdout.lines(); + let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1); + let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1); + for line in table_start { + if line.is_empty() { + break; + } + let mut parts = line.trim().splitn(2, ' '); + let name = parts.next().expect("name in group"); + if name == "warnings" { + // This is special. + continue; + } + let lints = parts + .next() + .ok_or_else(|| format!("expected lints following name, got `{}`", line))?; + let lints = lints.split(',').map(|l| l.trim().to_string()).collect(); + assert!(result.insert(name.to_string(), lints).is_none()); } - let lints = - parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?; - let lints = lints.split(',').map(|l| l.trim().to_string()).collect(); - assert!(result.insert(name.to_string(), lints).is_none()); - } - if result.is_empty() { - return Err( - format!("expected at least one group in -Whelp output, got:\n{}", stdout).into() - ); + if result.is_empty() { + return Err( + format!("expected at least one group in -Whelp output, got:\n{}", stdout).into() + ); + } + Ok(result) } - Ok(result) -} -fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result> { - let mut result = String::new(); - let mut to_link = Vec::new(); - result.push_str("| Group | Description | Lints |\n"); - result.push_str("|-------|-------------|-------|\n"); - result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n"); - for (group_name, group_lints) in groups { - let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) - .ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))? - .1; - to_link.extend(group_lints); - let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect(); - write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap(); - } - result.push('\n'); - result.push_str("[warn-by-default]: listing/warn-by-default.md\n"); - for lint_name in to_link { - let lint_def = - lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| { - format!( - "`rustc -W help` defined lint `{}` but that lint does not appear to exist", - lint_name - ) - })?; - write!( - result, - "[{}]: listing/{}#{}\n", - lint_name, - lint_def.level.doc_filename(), - lint_name - ) - .unwrap(); + fn make_groups_table( + &self, + lints: &[Lint], + groups: &LintGroups, + ) -> Result> { + let mut result = String::new(); + let mut to_link = Vec::new(); + result.push_str("| Group | Description | Lints |\n"); + result.push_str("|-------|-------------|-------|\n"); + result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n"); + for (group_name, group_lints) in groups { + let description = match GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) { + Some((_, desc)) => desc, + None if self.validate => { + return Err(format!( + "lint group `{}` does not have a description, \ + please update the GROUP_DESCRIPTIONS list in \ + src/tools/lint-docs/src/groups.rs", + group_name + ) + .into()); + } + None => { + eprintln!( + "warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n\ + If this is a new lint group, please update the GROUP_DESCRIPTIONS in \ + src/tools/lint-docs/src/groups.rs", + group_name + ); + continue; + } + }; + to_link.extend(group_lints); + let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect(); + write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")) + .unwrap(); + } + result.push('\n'); + result.push_str("[warn-by-default]: listing/warn-by-default.md\n"); + for lint_name in to_link { + let lint_def = + lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| { + format!( + "`rustc -W help` defined lint `{}` but that lint does not appear to exist", + lint_name + ) + })?; + write!( + result, + "[{}]: listing/{}#{}\n", + lint_name, + lint_def.level.doc_filename(), + lint_name + ) + .unwrap(); + } + Ok(result) } - Ok(result) } diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 6ca71dcaf3..ea54a351e0 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -7,6 +7,22 @@ use walkdir::WalkDir; mod groups; +pub struct LintExtractor<'a> { + /// Path to the `src` directory, where it will scan for `.rs` files to + /// find lint declarations. + pub src_path: &'a Path, + /// Path where to save the output. + pub out_path: &'a Path, + /// Path to the `rustc` executable. + pub rustc_path: &'a Path, + /// The target arch to build the docs for. + pub rustc_target: &'a str, + /// Verbose output. + pub verbose: bool, + /// Validate the style and the code example. + pub validate: bool, +} + struct Lint { name: String, doc: Vec, @@ -26,6 +42,28 @@ impl Lint { .filter(|line| line.starts_with("```rust")) .all(|line| line.contains(",ignore")) } + + /// Checks the doc style of the lint. + fn check_style(&self) -> Result<(), Box> { + for &expected in &["### Example", "### Explanation", "{{produces}}"] { + if expected == "{{produces}}" && self.is_ignored() { + continue; + } + if !self.doc_contains(expected) { + return Err(format!("lint docs should contain the line `{}`", expected).into()); + } + } + if let Some(first) = self.doc.first() { + if !first.starts_with(&format!("The `{}` lint", self.name)) { + return Err(format!( + "lint docs should start with the text \"The `{}` lint\" to introduce the lint", + self.name + ) + .into()); + } + } + Ok(()) + } } #[derive(Clone, Copy, PartialEq)] @@ -45,382 +83,396 @@ impl Level { } } -#[derive(Copy, Clone)] -pub struct Rustc<'a> { - pub path: &'a Path, - pub target: &'a str, -} - -/// Collects all lints, and writes the markdown documentation at the given directory. -pub fn extract_lint_docs( - src_path: &Path, - out_path: &Path, - rustc: Rustc<'_>, - verbose: bool, -) -> Result<(), Box> { - let mut lints = gather_lints(src_path)?; - for lint in &mut lints { - generate_output_example(lint, rustc, verbose).map_err(|e| { - format!( - "failed to test example in lint docs for `{}` in {}:{}: {}", - lint.name, - lint.path.display(), - lint.lineno, - e - ) - })?; +impl<'a> LintExtractor<'a> { + /// Collects all lints, and writes the markdown documentation at the given directory. + pub fn extract_lint_docs(&self) -> Result<(), Box> { + let mut lints = self.gather_lints()?; + for lint in &mut lints { + self.generate_output_example(lint).map_err(|e| { + format!( + "failed to test example in lint docs for `{}` in {}:{}: {}", + lint.name, + lint.path.display(), + lint.lineno, + e + ) + })?; + } + self.save_lints_markdown(&lints)?; + self.generate_group_docs(&lints)?; + Ok(()) } - save_lints_markdown(&lints, &out_path.join("listing"))?; - groups::generate_group_docs(&lints, rustc, out_path)?; - Ok(()) -} -/// Collects all lints from all files in the given directory. -fn gather_lints(src_path: &Path) -> Result, Box> { - let mut lints = Vec::new(); - for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) { - if !entry.path().extension().map_or(false, |ext| ext == "rs") { - continue; + /// Collects all lints from all files in the given directory. + fn gather_lints(&self) -> Result, Box> { + let mut lints = Vec::new(); + for entry in WalkDir::new(self.src_path).into_iter().filter_map(|e| e.ok()) { + if !entry.path().extension().map_or(false, |ext| ext == "rs") { + continue; + } + lints.extend(self.lints_from_file(entry.path())?); } - lints.extend(lints_from_file(entry.path())?); - } - if lints.is_empty() { - return Err("no lints were found!".into()); + if lints.is_empty() { + return Err("no lints were found!".into()); + } + Ok(lints) } - Ok(lints) -} -/// Collects all lints from the given file. -fn lints_from_file(path: &Path) -> Result, Box> { - let mut lints = Vec::new(); - let contents = fs::read_to_string(path) - .map_err(|e| format!("could not read {}: {}", path.display(), e))?; - let mut lines = contents.lines().enumerate(); - loop { - // Find a lint declaration. - let lint_start = loop { - match lines.next() { - Some((lineno, line)) => { - if line.trim().starts_with("declare_lint!") { - break lineno + 1; + /// Collects all lints from the given file. + fn lints_from_file(&self, path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + let contents = fs::read_to_string(path) + .map_err(|e| format!("could not read {}: {}", path.display(), e))?; + let mut lines = contents.lines().enumerate(); + 'outer: loop { + // Find a lint declaration. + let lint_start = loop { + match lines.next() { + Some((lineno, line)) => { + if line.trim().starts_with("declare_lint!") { + break lineno + 1; + } + } + None => return Ok(lints), + } + }; + // Read the lint. + let mut doc_lines = Vec::new(); + let (doc, name) = loop { + match lines.next() { + Some((lineno, line)) => { + let line = line.trim(); + if let Some(text) = line.strip_prefix("/// ") { + doc_lines.push(text.to_string()); + } else if line == "///" { + doc_lines.push("".to_string()); + } else if line.starts_with("// ") { + // Ignore comments. + continue; + } else { + let name = lint_name(line).map_err(|e| { + format!( + "could not determine lint name in {}:{}: {}, line was `{}`", + path.display(), + lineno, + e, + line + ) + })?; + if doc_lines.is_empty() { + if self.validate { + return Err(format!( + "did not find doc lines for lint `{}` in {}", + name, + path.display() + ) + .into()); + } else { + eprintln!( + "warning: lint `{}` in {} does not define any doc lines, \ + these are required for the lint documentation", + name, + path.display() + ); + continue 'outer; + } + } + break (doc_lines, name); + } + } + None => { + return Err(format!( + "unexpected EOF for lint definition at {}:{}", + path.display(), + lint_start + ) + .into()); } } - None => return Ok(lints), + }; + // These lints are specifically undocumented. This should be reserved + // for internal rustc-lints only. + if name == "deprecated_in_future" { + continue; } - }; - // Read the lint. - let mut doc_lines = Vec::new(); - let (doc, name) = loop { - match lines.next() { - Some((lineno, line)) => { - let line = line.trim(); - if line.starts_with("/// ") { - doc_lines.push(line.trim()[4..].to_string()); - } else if line.starts_with("///") { - doc_lines.push("".to_string()); - } else if line.starts_with("// ") { - // Ignore comments. - continue; - } else { - let name = lint_name(line).map_err(|e| { - format!( - "could not determine lint name in {}:{}: {}, line was `{}`", - path.display(), - lineno, - e, - line - ) - })?; - if doc_lines.is_empty() { + // Read the level. + let level = loop { + match lines.next() { + // Ignore comments. + Some((_, line)) if line.trim().starts_with("// ") => {} + Some((lineno, line)) => match line.trim() { + "Allow," => break Level::Allow, + "Warn," => break Level::Warn, + "Deny," => break Level::Deny, + _ => { return Err(format!( - "did not find doc lines for lint `{}` in {}", - name, - path.display() + "unexpected lint level `{}` in {}:{}", + line, + path.display(), + lineno ) .into()); } - break (doc_lines, name); - } - } - None => { - return Err(format!( - "unexpected EOF for lint definition at {}:{}", - path.display(), - lint_start - ) - .into()); - } - } - }; - // These lints are specifically undocumented. This should be reserved - // for internal rustc-lints only. - if name == "deprecated_in_future" { - continue; - } - // Read the level. - let level = loop { - match lines.next() { - // Ignore comments. - Some((_, line)) if line.trim().starts_with("// ") => {} - Some((lineno, line)) => match line.trim() { - "Allow," => break Level::Allow, - "Warn," => break Level::Warn, - "Deny," => break Level::Deny, - _ => { + }, + None => { return Err(format!( - "unexpected lint level `{}` in {}:{}", - line, + "expected lint level in {}:{}, got EOF", path.display(), - lineno + lint_start ) .into()); } - }, - None => { - return Err(format!( - "expected lint level in {}:{}, got EOF", - path.display(), - lint_start - ) - .into()); } - } - }; - // The rest of the lint definition is ignored. - assert!(!doc.is_empty()); - lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start }); - } -} - -/// Extracts the lint name (removing the visibility modifier, and checking validity). -fn lint_name(line: &str) -> Result { - // Skip over any potential `pub` visibility. - match line.trim().split(' ').next_back() { - Some(name) => { - if !name.ends_with(',') { - return Err("lint name should end with comma"); - } - let name = &name[..name.len() - 1]; - if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() { - return Err("lint name did not have expected format"); - } - Ok(name.to_lowercase().to_string()) + }; + // The rest of the lint definition is ignored. + assert!(!doc.is_empty()); + lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start }); } - None => Err("could not find lint name"), - } -} - -/// Mutates the lint definition to replace the `{{produces}}` marker with the -/// actual output from the compiler. -fn generate_output_example( - lint: &mut Lint, - rustc: Rustc<'_>, - verbose: bool, -) -> Result<(), Box> { - // Explicit list of lints that are allowed to not have an example. Please - // try to avoid adding to this list. - if matches!( - lint.name.as_str(), - "unused_features" // broken lint - | "unstable_features" // deprecated - ) { - return Ok(()); - } - if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { - // Rustdoc lints are documented in the rustdoc book, don't check these. - return Ok(()); } - check_style(lint)?; - // Unfortunately some lints have extra requirements that this simple test - // setup can't handle (like extern crates). An alternative is to use a - // separate test suite, and use an include mechanism such as mdbook's - // `{{#rustdoc_include}}`. - if !lint.is_ignored() { - replace_produces(lint, rustc, verbose)?; - } - Ok(()) -} -/// Checks the doc style of the lint. -fn check_style(lint: &Lint) -> Result<(), Box> { - for &expected in &["### Example", "### Explanation", "{{produces}}"] { - if expected == "{{produces}}" && lint.is_ignored() { - continue; + /// Mutates the lint definition to replace the `{{produces}}` marker with the + /// actual output from the compiler. + fn generate_output_example(&self, lint: &mut Lint) -> Result<(), Box> { + // Explicit list of lints that are allowed to not have an example. Please + // try to avoid adding to this list. + if matches!( + lint.name.as_str(), + "unused_features" // broken lint + | "unstable_features" // deprecated + ) { + return Ok(()); } - if !lint.doc_contains(expected) { - return Err(format!("lint docs should contain the line `{}`", expected).into()); + if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { + // Rustdoc lints are documented in the rustdoc book, don't check these. + return Ok(()); } - } - if let Some(first) = lint.doc.first() { - if !first.starts_with(&format!("The `{}` lint", lint.name)) { - return Err(format!( - "lint docs should start with the text \"The `{}` lint\" to introduce the lint", - lint.name - ) - .into()); + if self.validate { + lint.check_style()?; + } + // Unfortunately some lints have extra requirements that this simple test + // setup can't handle (like extern crates). An alternative is to use a + // separate test suite, and use an include mechanism such as mdbook's + // `{{#rustdoc_include}}`. + if !lint.is_ignored() { + if let Err(e) = self.replace_produces(lint) { + if self.validate { + return Err(e); + } + eprintln!( + "warning: the code example in lint `{}` in {} failed to \ + generate the expected output: {}", + lint.name, + lint.path.display(), + e + ); + } } + Ok(()) } - Ok(()) -} -/// Mutates the lint docs to replace the `{{produces}}` marker with the actual -/// output from the compiler. -fn replace_produces( - lint: &mut Lint, - rustc: Rustc<'_>, - verbose: bool, -) -> Result<(), Box> { - let mut lines = lint.doc.iter_mut(); - loop { - // Find start of example. - let options = loop { - match lines.next() { - Some(line) if line.starts_with("```rust") => { - break line[7..].split(',').collect::>(); + /// Mutates the lint docs to replace the `{{produces}}` marker with the actual + /// output from the compiler. + fn replace_produces(&self, lint: &mut Lint) -> Result<(), Box> { + let mut lines = lint.doc.iter_mut(); + loop { + // Find start of example. + let options = loop { + match lines.next() { + Some(line) if line.starts_with("```rust") => { + break line[7..].split(',').collect::>(); + } + Some(line) if line.contains("{{produces}}") => { + return Err("lint marker {{{{produces}}}} found, \ + but expected to immediately follow a rust code block" + .into()); + } + Some(_) => {} + None => return Ok(()), } - Some(line) if line.contains("{{produces}}") => { - return Err("lint marker {{{{produces}}}} found, \ - but expected to immediately follow a rust code block" + }; + // Find the end of example. + let mut example = Vec::new(); + loop { + match lines.next() { + Some(line) if line == "```" => break, + Some(line) => example.push(line), + None => { + return Err(format!( + "did not find end of example triple ticks ```, docs were:\n{:?}", + lint.doc + ) .into()); - } - Some(_) => {} - None => return Ok(()), - } - }; - // Find the end of example. - let mut example = Vec::new(); - loop { - match lines.next() { - Some(line) if line == "```" => break, - Some(line) => example.push(line), - None => { - return Err(format!( - "did not find end of example triple ticks ```, docs were:\n{:?}", - lint.doc - ) - .into()); + } } } - } - // Find the {{produces}} line. - loop { - match lines.next() { - Some(line) if line.is_empty() => {} - Some(line) if line == "{{produces}}" => { - let output = - generate_lint_output(&lint.name, &example, &options, rustc, verbose)?; - line.replace_range( - .., - &format!( - "This will produce:\n\ - \n\ - ```text\n\ - {}\ - ```", - output - ), - ); - break; + // Find the {{produces}} line. + loop { + match lines.next() { + Some(line) if line.is_empty() => {} + Some(line) if line == "{{produces}}" => { + let output = self.generate_lint_output(&lint.name, &example, &options)?; + line.replace_range( + .., + &format!( + "This will produce:\n\ + \n\ + ```text\n\ + {}\ + ```", + output + ), + ); + break; + } + // No {{produces}} after example, find next example. + Some(_line) => break, + None => return Ok(()), } - // No {{produces}} after example, find next example. - Some(_line) => break, - None => return Ok(()), } } } -} -/// Runs the compiler against the example, and extracts the output. -fn generate_lint_output( - name: &str, - example: &[&mut String], - options: &[&str], - rustc: Rustc<'_>, - verbose: bool, -) -> Result> { - if verbose { - eprintln!("compiling lint {}", name); - } - let tempdir = tempfile::TempDir::new()?; - let tempfile = tempdir.path().join("lint_example.rs"); - let mut source = String::new(); - let needs_main = !example.iter().any(|line| line.contains("fn main")); - // Remove `# ` prefix for hidden lines. - let unhidden = - example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); - let mut lines = unhidden.peekable(); - while let Some(line) = lines.peek() { - if line.starts_with("#!") { + /// Runs the compiler against the example, and extracts the output. + fn generate_lint_output( + &self, + name: &str, + example: &[&mut String], + options: &[&str], + ) -> Result> { + if self.verbose { + eprintln!("compiling lint {}", name); + } + let tempdir = tempfile::TempDir::new()?; + let tempfile = tempdir.path().join("lint_example.rs"); + let mut source = String::new(); + let needs_main = !example.iter().any(|line| line.contains("fn main")); + // Remove `# ` prefix for hidden lines. + let unhidden = example.iter().map(|line| line.strip_prefix("# ").unwrap_or(line)); + let mut lines = unhidden.peekable(); + while let Some(line) = lines.peek() { + if line.starts_with("#!") { + source.push_str(line); + source.push('\n'); + lines.next(); + } else { + break; + } + } + if needs_main { + source.push_str("fn main() {\n"); + } + for line in lines { source.push_str(line); - source.push('\n'); - lines.next(); + source.push('\n') + } + if needs_main { + source.push_str("}\n"); + } + fs::write(&tempfile, source) + .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; + let mut cmd = Command::new(self.rustc_path); + if options.contains(&"edition2015") { + cmd.arg("--edition=2015"); } else { - break; + cmd.arg("--edition=2018"); + } + cmd.arg("--error-format=json"); + cmd.arg("--target").arg(self.rustc_target); + if options.contains(&"test") { + cmd.arg("--test"); + } + cmd.arg("lint_example.rs"); + cmd.current_dir(tempdir.path()); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let msgs = stderr + .lines() + .filter(|line| line.starts_with('{')) + .map(serde_json::from_str) + .collect::, _>>()?; + match msgs + .iter() + .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + match msgs.iter().find( + |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), + ) { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}\n{}", + name, + non_json.join("\n"), + rendered.join("\n") + ) + .into()) + } + } + } } } - if needs_main { - source.push_str("fn main() {\n"); - } - for line in lines { - source.push_str(line); - source.push('\n') - } - if needs_main { - source.push_str("}\n"); - } - fs::write(&tempfile, source) - .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; - let mut cmd = Command::new(rustc.path); - if options.contains(&"edition2015") { - cmd.arg("--edition=2015"); - } else { - cmd.arg("--edition=2018"); - } - cmd.arg("--error-format=json"); - cmd.arg("--target").arg(rustc.target); - if options.contains(&"test") { - cmd.arg("--test"); + + /// Saves the mdbook lint chapters at the given path. + fn save_lints_markdown(&self, lints: &[Lint]) -> Result<(), Box> { + self.save_level(lints, Level::Allow, ALLOWED_MD)?; + self.save_level(lints, Level::Warn, WARN_MD)?; + self.save_level(lints, Level::Deny, DENY_MD)?; + Ok(()) } - cmd.arg("lint_example.rs"); - cmd.current_dir(tempdir.path()); - let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; - let stderr = std::str::from_utf8(&output.stderr).unwrap(); - let msgs = stderr - .lines() - .filter(|line| line.starts_with('{')) - .map(serde_json::from_str) - .collect::, _>>()?; - match msgs - .iter() - .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) - { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) + + fn save_level(&self, lints: &[Lint], level: Level, header: &str) -> Result<(), Box> { + let mut result = String::new(); + result.push_str(header); + let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); + these_lints.sort_unstable_by_key(|lint| &lint.name); + for lint in &these_lints { + write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); } - None => { - match msgs.iter().find( - |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), - ) { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - let rendered: Vec<&str> = - msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); - let non_json: Vec<&str> = - stderr.lines().filter(|line| !line.starts_with('{')).collect(); - Err(format!( - "did not find lint `{}` in output of example, got:\n{}\n{}", - name, - non_json.join("\n"), - rendered.join("\n") - ) - .into()) - } + result.push('\n'); + for lint in &these_lints { + write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); + for line in &lint.doc { + result.push_str(line); + result.push('\n'); + } + result.push('\n'); + } + let out_path = self.out_path.join("listing").join(level.doc_filename()); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&out_path); + fs::write(&out_path, result) + .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; + Ok(()) + } +} + +/// Extracts the lint name (removing the visibility modifier, and checking validity). +fn lint_name(line: &str) -> Result { + // Skip over any potential `pub` visibility. + match line.trim().split(' ').next_back() { + Some(name) => { + if !name.ends_with(',') { + return Err("lint name should end with comma"); } + let name = &name[..name.len() - 1]; + if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() { + return Err("lint name did not have expected format"); + } + Ok(name.to_lowercase().to_string()) } + None => Err("could not find lint name"), } } @@ -442,41 +494,3 @@ static DENY_MD: &str = r#"# Deny-by-default lints These lints are all set to the 'deny' level by default. "#; - -/// Saves the mdbook lint chapters at the given path. -fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box> { - save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?; - save_level(lints, Level::Warn, out_dir, WARN_MD)?; - save_level(lints, Level::Deny, out_dir, DENY_MD)?; - Ok(()) -} - -fn save_level( - lints: &[Lint], - level: Level, - out_dir: &Path, - header: &str, -) -> Result<(), Box> { - let mut result = String::new(); - result.push_str(header); - let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); - these_lints.sort_unstable_by_key(|lint| &lint.name); - for lint in &these_lints { - write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); - } - result.push('\n'); - for lint in &these_lints { - write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); - for line in &lint.doc { - result.push_str(line); - result.push('\n'); - } - result.push('\n'); - } - let out_path = out_dir.join(level.doc_filename()); - // Delete the output because rustbuild uses hard links in its copies. - let _ = fs::remove_file(&out_path); - fs::write(&out_path, result) - .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; - Ok(()) -} diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 5db49007d3..2055fed2b4 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -3,7 +3,20 @@ use std::path::PathBuf; fn main() { if let Err(e) = doit() { - println!("error: {}", e); + eprintln!("error: {}", e); + eprintln!( + " +This error was generated by the lint-docs tool. +This tool extracts documentation for lints from the source code and places +them in the rustc book. See the declare_lint! documentation +https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/macro.declare_lint.html +for an example of the format of documentation this tool expects. + +To re-run these tests, run: ./x.py test --keep-stage=0 src/tools/lint-docs +The --keep-stage flag should be used if you have already built the compiler +and are only modifying the doc comments to avoid rebuilding the compiler. +" + ); std::process::exit(1); } } @@ -15,6 +28,7 @@ fn doit() -> Result<(), Box> { let mut rustc_path = None; let mut rustc_target = None; let mut verbose = false; + let mut validate = false; while let Some(arg) = args.next() { match arg.as_str() { "--src" => { @@ -42,6 +56,7 @@ fn doit() -> Result<(), Box> { }; } "-v" | "--verbose" => verbose = true, + "--validate" => validate = true, s => return Err(format!("unexpected argument `{}`", s).into()), } } @@ -57,13 +72,13 @@ fn doit() -> Result<(), Box> { if rustc_target.is_none() { return Err("--rustc-target must be specified to the rustc target".into()); } - lint_docs::extract_lint_docs( - &src_path.unwrap(), - &out_path.unwrap(), - lint_docs::Rustc { - path: rustc_path.as_deref().unwrap(), - target: rustc_target.as_deref().unwrap(), - }, + let le = lint_docs::LintExtractor { + src_path: &src_path.unwrap(), + out_path: &out_path.unwrap(), + rustc_path: &rustc_path.unwrap(), + rustc_target: &rustc_target.unwrap(), verbose, - ) + validate, + }; + le.extract_lint_docs() } diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 7586f5aa3b..0d4a755551 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -28,7 +28,7 @@ MAINTAINERS = { 'rls': {'Xanewok'}, 'rustfmt': {'topecongiro', 'calebcartwright'}, 'book': {'carols10cents', 'steveklabnik'}, - 'nomicon': {'frewsxcv', 'Gankra'}, + 'nomicon': {'frewsxcv', 'Gankra', 'JohnTitor'}, 'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'}, 'rust-by-example': {'steveklabnik', 'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'}, diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index f5e5c0867b..8e17f29190 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -7,8 +7,9 @@ edition = "2018" [dependencies] clap = "2.25.0" +env_logger = "0.7.1" [dependencies.mdbook] -version = "0.4.3" +version = "0.4.5" default-features = false features = ["search"] diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index c87c64540a..63d84ae973 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -9,6 +9,7 @@ use mdbook::errors::Result as Result3; use mdbook::MDBook; fn main() { + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); let d_message = "-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'"; let dir_message = "[dir] diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 337d65e4da..1cde0e25ce 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -64,6 +64,9 @@ features = [ byteorder = { version = "1", features = ['default', 'std'] } curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } crossbeam-utils = { version = "0.7.2", features = ["nightly"] } +libc = { version = "0.2.79", features = ["align"] } +# Ensure default features of libz-sys, which are disabled in some scenarios. +libz-sys = { version = "1.1.2" } proc-macro2 = { version = "1", features = ["default"] } quote = { version = "1", features = ["default"] } serde = { version = "1.0.82", features = ['derive'] } diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 139e6f73f4..63f2d2f5d2 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -190,6 +190,30 @@ function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { return content; } +function contentToDiffLine(key, value) { + return `"${key}": "${value}",`; +} + +// This function is only called when no matching result was found and therefore will only display +// the diff between the two items. +function betterLookingDiff(entry, data) { + let output = ' {\n'; + let spaces = ' '; + for (let key in entry) { + if (!entry.hasOwnProperty(key)) { + continue; + } + let value = data[key]; + if (value !== entry[key]) { + output += '-' + spaces + contentToDiffLine(key, entry[key]) + '\n'; + output += '+' + spaces + contentToDiffLine(key, value) + '\n'; + } else { + output += spaces + contentToDiffLine(key, value) + '\n'; + } + } + return output + ' }'; +} + function lookForEntry(entry, data) { for (var i = 0; i < data.length; ++i) { var allGood = true; @@ -281,6 +305,13 @@ function runSearch(query, expected, index, loaded, loadedFile, queryName) { if (entry_pos === null) { error_text.push(queryName + "==> Result not found in '" + key + "': '" + JSON.stringify(entry[i]) + "'"); + // By default, we just compare the two first items. + let item_to_diff = 0; + if ((ignore_order === false || exact_check === true) && i < results[key].length) { + item_to_diff = i; + } + error_text.push("Diff of first error:\n" + + betterLookingDiff(entry[i], results[key][item_to_diff])); } else if (exact_check === true && prev_pos + 1 !== entry_pos) { error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) + ": expected '" + JSON.stringify(entry[i]) + "' but found '" + diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index 7bdd78a91e..e06616a59f 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -59,11 +59,10 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { break; } - let mut parts = line.splitn(2, '='); - let krate = parts.next().unwrap().trim(); - if parts.next().is_none() { - continue; - } + let krate = match line.split_once('=') { + None => continue, + Some((krate, _)) => krate.trim(), + }; // Don't worry about depending on core/std while not writing `extern crate // core/std` -- that's intentional. diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 057b0884e2..4b521985ca 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -104,6 +104,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "getopts", "getrandom", "gimli", + "gsgdt", "hashbrown", "hermit-abi", "humantime", @@ -214,12 +215,12 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { for (name, license) in EXCEPTIONS { // Check that the package actually exists. if !metadata.packages.iter().any(|p| p.name == *name) { - println!( + tidy_error!( + bad, "could not find exception package `{}`\n\ Remove from EXCEPTIONS list if it is no longer used.", name ); - *bad = true; } // Check that the license hasn't changed. for pkg in metadata.packages.iter().filter(|p| p.name == *name) { @@ -232,11 +233,11 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { } match &pkg.license { None => { - println!( + tidy_error!( + bad, "dependency exception `{}` does not declare a license expression", pkg.id ); - *bad = true; } Some(pkg_license) => { if pkg_license.as_str() != *license { @@ -273,8 +274,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { let license = match &pkg.license { Some(license) => license, None => { - println!("dependency `{}` does not define a license expression", pkg.id,); - *bad = true; + tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); continue; } }; @@ -286,8 +286,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { // general, these should never be added. continue; } - println!("invalid license `{}` in `{}`", license, pkg.id); - *bad = true; + tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); } } } @@ -300,12 +299,12 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) { // Check that the PERMITTED_DEPENDENCIES does not have unused entries. for name in PERMITTED_DEPENDENCIES { if !metadata.packages.iter().any(|p| p.name == *name) { - println!( + tidy_error!( + bad, "could not find allowed package `{}`\n\ Remove from PERMITTED_DEPENDENCIES list if it is no longer used.", name ); - *bad = true; } } // Get the list in a convenient form. @@ -322,11 +321,10 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) { } if !unapproved.is_empty() { - println!("Dependencies not explicitly permitted:"); + tidy_error!(bad, "Dependencies not explicitly permitted:"); for dep in unapproved { println!("* {}", dep); } - *bad = true; } } @@ -381,16 +379,17 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect(); match matches.len() { 0 => { - println!( + tidy_error!( + bad, "crate `{}` is missing, update `check_crate_duplicate` \ if it is no longer used", name ); - *bad = true; } 1 => {} _ => { - println!( + tidy_error!( + bad, "crate `{}` is duplicated in `Cargo.lock`, \ it is too expensive to build multiple times, \ so make sure only one version appears across all dependencies", @@ -399,7 +398,6 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { for pkg in matches { println!(" * {}", pkg.id); } - *bad = true; } } } diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 82a5234ac5..a7199fdfce 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -85,47 +85,61 @@ fn extract_error_codes( for line in f.lines() { let s = line.trim(); if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") { - if let Some(err_code) = s.splitn(2, ':').next() { - let err_code = err_code.to_owned(); - if !error_codes.contains_key(&err_code) { - error_codes.insert(err_code.clone(), false); - } - // Now we extract the tests from the markdown file! - let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1)); - let md_file_name = some_or_continue!(md.splitn(2, "\")").next()); - let path = some_or_continue!(path.parent()) - .join(md_file_name) - .canonicalize() - .expect("failed to canonicalize error explanation file path"); - match read_to_string(&path) { - Ok(content) => { - if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) - && !check_if_error_code_is_test_in_explanation(&content, &err_code) - { - errors.push(format!( - "`{}` doesn't use its own error code in compile_fail example", - path.display(), - )); - } - if check_error_code_explanation(&content, error_codes, err_code) { - errors.push(format!( - "`{}` uses invalid tag `compile-fail` instead of `compile_fail`", - path.display(), - )); - } + let err_code = s + .split_once(':') + .expect( + format!( + "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} without a `:` delimiter", + s, + ).as_str() + ) + .0 + .to_owned(); + if !error_codes.contains_key(&err_code) { + error_codes.insert(err_code.clone(), false); + } + // Now we extract the tests from the markdown file! + let md_file_name = match s.split_once("include_str!(\"") { + None => continue, + Some((_, md)) => match md.split_once("\")") { + None => continue, + Some((file_name, _)) => file_name, + }, + }; + let path = some_or_continue!(path.parent()) + .join(md_file_name) + .canonicalize() + .expect("failed to canonicalize error explanation file path"); + match read_to_string(&path) { + Ok(content) => { + if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) + && !check_if_error_code_is_test_in_explanation(&content, &err_code) + { + errors.push(format!( + "`{}` doesn't use its own error code in compile_fail example", + path.display(), + )); } - Err(e) => { - eprintln!("Couldn't read `{}`: {}", path.display(), e); + if check_error_code_explanation(&content, error_codes, err_code) { + errors.push(format!( + "`{}` uses invalid tag `compile-fail` instead of `compile_fail`", + path.display(), + )); } } + Err(e) => { + eprintln!("Couldn't read `{}`: {}", path.display(), e); + } } } else if reached_no_explanation && s.starts_with('E') { - if let Some(err_code) = s.splitn(2, ',').next() { - let err_code = err_code.to_owned(); - if !error_codes.contains_key(&err_code) { - // this check should *never* fail! - error_codes.insert(err_code, false); - } + let err_code = match s.split_once(',') { + None => s, + Some((err_code, _)) => err_code, + } + .to_string(); + if !error_codes.contains_key(&err_code) { + // this check should *never* fail! + error_codes.insert(err_code, false); } } else if s == ";" { reached_no_explanation = true; @@ -137,12 +151,15 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap continue, + Some((err_code, _)) => match err_code.split_once('[') { + None => continue, + Some((_, err_code)) => err_code, + }, + }; + let nb = error_codes.entry(err_code.to_owned()).or_insert(false); + *nb = true; } } } diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 1cf0d24e26..aad57cacbb 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -23,12 +23,11 @@ pub fn check(root: &Path, bad: &mut bool) { } // Extract source value. - let source = line.splitn(2, '=').nth(1).unwrap().trim(); + let source = line.split_once('=').unwrap().1.trim(); // Ensure source is allowed. if !ALLOWED_SOURCES.contains(&&*source) { - println!("invalid source: {}", source); - *bad = true; + tidy_error!(bad, "invalid source: {}", source); } } } diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d8029ea04f..d78af2cd61 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -112,6 +112,7 @@ pub fn check( let gate_test_str = "gate-test-"; let feature_name = match line.find(gate_test_str) { + // NB: the `splitn` always succeeds, even if the delimiter is not present. Some(i) => line[i + gate_test_str.len()..].splitn(2, ' ').next().unwrap(), None => continue, }; @@ -329,7 +330,6 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { if level == Status::Unstable && !next_feature_omits_tracking_issue { - *bad = true; tidy_error!( bad, "{}:{}: no tracking issue for feature {}", diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index cc4c43f046..d282d240d8 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -3,6 +3,8 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. +#![feature(str_split_once)] + use std::fs::File; use std::io::Read; use walkdir::{DirEntry, WalkDir}; @@ -26,6 +28,10 @@ macro_rules! t { } macro_rules! tidy_error { + ($bad:expr, $fmt:expr) => ({ + *$bad = true; + eprintln!("tidy error: {}", $fmt); + }); ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ *$bad = true; eprint!("tidy error: "); diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index e1525f8e1b..080e163162 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,9 +35,12 @@ fn main() { // Checks that only make sense for the std libs. pal::check(&library_path, &mut bad); - unit_tests::check(&library_path, &mut bad); // Checks that need to be done for both the compiler and std libraries. + unit_tests::check(&src_path, &mut bad); + unit_tests::check(&compiler_path, &mut bad); + unit_tests::check(&library_path, &mut bad); + bins::check(&src_path, &output_directory, &mut bad); bins::check(&compiler_path, &output_directory, &mut bad); bins::check(&library_path, &output_directory, &mut bad); diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index bce3cf06b0..6697fbd1be 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -173,7 +173,6 @@ pub fn check(path: &Path, bad: &mut bool) { // parser to tidy. !file.ancestors().any(|a| { a.ends_with("src/test") || - a.ends_with("library/std/src/sys/cloudabi") || a.ends_with("src/doc/book") }); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 47b328dae4..d8d2b449fe 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -1,9 +1,51 @@ -//! Tidy check to ensure that there are no stray `.stderr` files in UI test directories. +//! Tidy check to ensure below in UI test directories: +//! - the number of entries in each directory must be less than `ENTRY_LIMIT` +//! - there are no stray `.stderr` files use std::fs; use std::path::Path; +const ENTRY_LIMIT: usize = 1000; +// FIXME: The following limits should be reduced eventually. +const ROOT_ENTRY_LIMIT: usize = 1580; +const ISSUES_ENTRY_LIMIT: usize = 2830; + +fn check_entries(path: &Path, bad: &mut bool) { + let dirs = walkdir::WalkDir::new(&path.join("test/ui")) + .into_iter() + .filter_entry(|e| e.file_type().is_dir()); + for dir in dirs { + if let Ok(dir) = dir { + let dir_path = dir.path(); + + // Use special values for these dirs. + let is_root = path.join("test/ui") == dir_path; + let is_issues_dir = path.join("test/ui/issues") == dir_path; + let limit = if is_root { + ROOT_ENTRY_LIMIT + } else if is_issues_dir { + ISSUES_ENTRY_LIMIT + } else { + ENTRY_LIMIT + }; + + let count = std::fs::read_dir(dir_path).unwrap().count(); + if count >= limit { + tidy_error!( + bad, + "following path contains more than {} entries, \ + you should move the test to some relevant subdirectory (current: {}): {}", + limit, + count, + dir_path.display() + ); + } + } + } +} + pub fn check(path: &Path, bad: &mut bool) { + check_entries(&path, bad); for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] { super::walk_no_read(path, &mut |_| false, &mut |entry| { let file_path = entry.path(); @@ -19,23 +61,18 @@ pub fn check(path: &Path, bad: &mut bool) { // // For now, just make sure that there is a corresponding // `$testname.rs` file. - let testname = file_path - .file_name() - .unwrap() - .to_str() - .unwrap() - .splitn(2, '.') - .next() - .unwrap(); + // + // NB: We do not use file_stem() as some file names have multiple `.`s and we + // must strip all of them. + let testname = + file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; if !file_path.with_file_name(testname).with_extension("rs").exists() { - println!("Stray file with UI testing output: {:?}", file_path); - *bad = true; + tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); } if let Ok(metadata) = fs::metadata(file_path) { if metadata.len() == 0 { - println!("Empty file with UI testing output: {:?}", file_path); - *bad = true; + tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); } } } diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs index 04f2bbaa0d..f675b78651 100644 --- a/src/tools/tidy/src/unit_tests.rs +++ b/src/tools/tidy/src/unit_tests.rs @@ -31,8 +31,6 @@ pub fn check(root_path: &Path, bad: &mut bool) { // UI tests with different names || path.ends_with("src/thread/local/dynamic_tests.rs") || path.ends_with("src/sync/mpsc/sync_tests.rs") - // Has copyright banner - || path.ends_with("src/sys/cloudabi/abi/cloudabi.rs") } }; diff --git a/src/tools/x/README.md b/src/tools/x/README.md index 3b3cf2847c..80bf02e8a0 100644 --- a/src/tools/x/README.md +++ b/src/tools/x/README.md @@ -1,3 +1,10 @@ # x `x` invokes `x.py` from any subdirectory. + +To install, run the following commands: + +``` +$ cd rust/src/tools/x/ +$ cargo install --path . +``` diff --git a/src/version b/src/version index 7f3a46a841..5a5c7211dc 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.49.0 +1.50.0 diff --git a/vendor/addr2line/.cargo-checksum.json b/vendor/addr2line/.cargo-checksum.json index 8c036a8f9d..0783e9a143 100644 --- a/vendor/addr2line/.cargo-checksum.json +++ b/vendor/addr2line/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"598dad538748eb803afc8dd4c6a1c3b8af9f560510e583f684989e4545a8d0e9","Cargo.lock":"8fdbc320fd1cf2c6dee88378b268ef1946c3f5a8d90fce176af519731c49323a","Cargo.toml":"ba2b050f4fdbbda62af7337089431d548d8a878bafacf595271e743bd312b7fd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"0d1090019193c11715a619c9602dc6f82b65cb2b3f22bbdda7ad964ff6963dc7","bench.plot.r":"6a5d7a4d36ed6b3d9919be703a479bef47698bf947818b483ff03951df2d4e01","benchmark.sh":"7b00323c126f6249ccff9b1824b7a8a237d623af202418d764df195c01e16272","coverage":"4f6b504b55aa623f5d1e8213e7c27683e901b981c621efdf146485c34e0fc963","examples/addr2line.rs":"0f4a857672d175761589b3a66e2ecbf19296ced7e4d4d0a167a2ddfdb7cabbfa","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/lazy.rs":"14ec61761369c21d426673f549c21394221533f444b68cd2a8370952eb19f345","src/lib.rs":"1d3645d1484fd0c60d6138b29882d1fe7f7e6656a11ee1d8f1bc8210e3780553","tests/correctness.rs":"c9325ffdec577bf5e56f5dd72fdff4927153d0a4c34c0fda5aefaeb44a8d26fd","tests/output_equivalence.rs":"bdfb3a26d690f63feda36f517c0520442bd6ddab7f6b780150a47a19fb7f0cc5","tests/parse.rs":"187e3d9377d9294aca569557fd55b5f1153608395f701c897e2a7f2e0cc159c6"},"package":"1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"} \ No newline at end of file +{"files":{"CHANGELOG.md":"6a0fd5291935caf64fa59deb27cf2fd8c59e1a48b184c29b37117a86981fc64b","Cargo.lock":"7978ec083868a1a0bd9dd28e8d490e290118940a74c6a021d1b5388f32a11995","Cargo.toml":"e024cf87a29249d693a94a6f5a8a64293e2ba041a1580ad471c98062d9ecd70e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"0d1090019193c11715a619c9602dc6f82b65cb2b3f22bbdda7ad964ff6963dc7","bench.plot.r":"6a5d7a4d36ed6b3d9919be703a479bef47698bf947818b483ff03951df2d4e01","benchmark.sh":"7b00323c126f6249ccff9b1824b7a8a237d623af202418d764df195c01e16272","coverage":"4f6b504b55aa623f5d1e8213e7c27683e901b981c621efdf146485c34e0fc963","examples/addr2line.rs":"84758ab26ae68b464d65c6de81a417fb564bb73b5b43ffb97ad02cedd49aec74","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/lazy.rs":"14ec61761369c21d426673f549c21394221533f444b68cd2a8370952eb19f345","src/lib.rs":"168a4abe96ae669218513e9b22c27d59438fe42173d9eb0f1a34dbea67641111","tests/correctness.rs":"c9325ffdec577bf5e56f5dd72fdff4927153d0a4c34c0fda5aefaeb44a8d26fd","tests/output_equivalence.rs":"38d7b585b7a2ca43b07eef6b34c11f489d1deae138a010123c33188dfb881c11","tests/parse.rs":"187e3d9377d9294aca569557fd55b5f1153608395f701c897e2a7f2e0cc159c6"},"package":"7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423"} \ No newline at end of file diff --git a/vendor/addr2line/CHANGELOG.md b/vendor/addr2line/CHANGELOG.md index 370372f793..eabdb9396a 100644 --- a/vendor/addr2line/CHANGELOG.md +++ b/vendor/addr2line/CHANGELOG.md @@ -1,3 +1,21 @@ +## 0.14.0 (2020/10/27) + +### Breaking changes + +* Updated `gimli` and `object` dependencies. + +### Fixed + +* Handle units that only have line information. + [#188](https://github.com/gimli-rs/addr2line/pull/188) + +* Handle DWARF units with version <= 4 and no `DW_AT_name`. + [#191](https://github.com/gimli-rs/addr2line/pull/191) + +* Fix handling of `DW_FORM_ref_addr`. + [#193](https://github.com/gimli-rs/addr2line/pull/193) + + ## 0.13.0 (2020/07/07) ### Breaking changes diff --git a/vendor/addr2line/Cargo.lock b/vendor/addr2line/Cargo.lock index d239c934ce..9b14f7d05c 100644 --- a/vendor/addr2line/Cargo.lock +++ b/vendor/addr2line/Cargo.lock @@ -4,419 +4,423 @@ name = "addr2line" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602d785912f476e480434627e8732e6766b760c045bbf897d9dfaa9f4fbd399c" dependencies = [ - "gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gimli 0.21.0", ] [[package]] name = "addr2line" -version = "0.13.0" +version = "0.14.0" dependencies = [ - "backtrace 0.3.49 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "cpp_demangle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "findshlibs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gimli 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "object 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-alloc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-test 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "clap", + "compiler_builtins", + "cpp_demangle", + "fallible-iterator", + "findshlibs", + "gimli 0.23.0", + "memmap", + "object 0.22.0", + "rustc-demangle", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "rustc-test", + "smallvec", ] [[package]] name = "adler" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc9a9dd069569f212bc4330af9f17c4afb5e8ce185e83dbb14f1349dda18b10" [[package]] name = "adler32" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9", ] [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi 0.3.9", ] [[package]] name = "backtrace" version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" dependencies = [ - "addr2line 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "object 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "addr2line 0.12.2", + "cfg-if", + "libc", + "miniz_oxide 0.3.7", + "object 0.20.0", + "rustc-demangle", ] [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "clap" version = "2.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", ] [[package]] name = "compiler_builtins" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" [[package]] name = "cpp_demangle" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad49cad3673b9d586bc50cd92fdc0e9205ecd162d4206073d9774c4fe13a8fde" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "glob", ] [[package]] name = "crc32fast" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "fallible-iterator" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "findshlibs" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00acd5e75443244c1f42fb330b8493d30b44da5b61565d8b8fbf4ecc9dda2a1" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "libc", ] [[package]] name = "flate2" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide 0.4.0", ] [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "gimli" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" [[package]] name = "gimli" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" dependencies = [ - "compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-alloc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins", + "fallible-iterator", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "stable_deref_trait", ] [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hermit-abi" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" [[package]] name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi 0.3.9", ] [[package]] name = "miniz_oxide" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" dependencies = [ - "adler32 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32", ] [[package]] name = "miniz_oxide" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" dependencies = [ - "adler 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "adler", ] [[package]] name = "object" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" + +[[package]] +name = "object" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ - "flate2 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.57.0 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2", + "wasmparser", ] [[package]] name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" [[package]] name = "rustc-serialize" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" [[package]] name = "rustc-std-workspace-alloc" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" [[package]] name = "rustc-std-workspace-core" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" [[package]] name = "rustc-test" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc74abd96aeb3d5f68702101c903c661869fba4867f2ddf4836032f018ad4728" dependencies = [ - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts", + "libc", + "rustc-serialize", + "rustc_version", + "term", + "time", ] [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "smallvec" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" [[package]] name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "term" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "winapi 0.2.8", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi 0.3.9", ] [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "wasmparser" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum addr2line 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602d785912f476e480434627e8732e6766b760c045bbf897d9dfaa9f4fbd399c" -"checksum adler 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc9a9dd069569f212bc4330af9f17c4afb5e8ce185e83dbb14f1349dda18b10" -"checksum adler32 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum backtrace 0.3.49 (registry+https://github.com/rust-lang/crates.io-index)" = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" -"checksum compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" -"checksum cpp_demangle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad49cad3673b9d586bc50cd92fdc0e9205ecd162d4206073d9774c4fe13a8fde" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -"checksum findshlibs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a00acd5e75443244c1f42fb330b8493d30b44da5b61565d8b8fbf4ecc9dda2a1" -"checksum flate2 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" -"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" -"checksum gimli 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" -"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" -"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum miniz_oxide 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -"checksum miniz_oxide 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" -"checksum object 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc-std-workspace-alloc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" -"checksum rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" -"checksum rustc-test 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc74abd96aeb3d5f68702101c903c661869fba4867f2ddf4836032f018ad4728" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" -"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -"checksum wasmparser 0.57.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/addr2line/Cargo.toml b/vendor/addr2line/Cargo.toml index a5c4c39de4..faf916e75b 100644 --- a/vendor/addr2line/Cargo.toml +++ b/vendor/addr2line/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "addr2line" -version = "0.13.0" +version = "0.14.0" authors = ["Nick Fitzgerald ", "Philip Craig ", "Jon Gjengset ", "Noah Bergbauer "] exclude = ["/benches/*", "/fixtures/*"] description = "A cross-platform symbolication library written in Rust, using `gimli`" @@ -70,12 +70,12 @@ optional = true default-features = false [dependencies.gimli] -version = "0.22" +version = "0.23" features = ["read"] default-features = false [dependencies.object] -version = "0.20" +version = "0.22" features = ["read"] optional = true default-features = false diff --git a/vendor/addr2line/examples/addr2line.rs b/vendor/addr2line/examples/addr2line.rs index a0db324bd5..8f4559e7a2 100644 --- a/vendor/addr2line/examples/addr2line.rs +++ b/vendor/addr2line/examples/addr2line.rs @@ -211,7 +211,7 @@ fn main() { if !printed_anything { if do_functions { - if let Some(name) = symbols.get(probe).and_then(|x| x.name()) { + if let Some(name) = symbols.get(probe).map(|x| x.name()) { print_function(name, None, demangle); } else { print!("??"); diff --git a/vendor/addr2line/src/lib.rs b/vendor/addr2line/src/lib.rs index bbd4b9d453..59d5004fcc 100644 --- a/vendor/addr2line/src/lib.rs +++ b/vendor/addr2line/src/lib.rs @@ -100,7 +100,7 @@ impl Context> { /// /// Performance sensitive applications may want to use `Context::from_sections` /// with a more specialised `gimli::Reader` implementation. - pub fn new<'data, 'file, O: object::Object<'data, 'file>>( + pub fn new<'data: 'file, 'file, O: object::Object<'data, 'file>>( file: &'file O, ) -> Result { let endian = if file.is_little_endian() { @@ -109,7 +109,7 @@ impl Context> { gimli::RunTimeEndian::Big }; - fn load_section<'data, 'file, O, S, Endian>(file: &'file O, endian: Endian) -> S + fn load_section<'data: 'file, 'file, O, S, Endian>(file: &'file O, endian: Endian) -> S where O: object::Object<'data, 'file>, S: gimli::Section>, @@ -179,6 +179,7 @@ impl Context { default_section.clone().into(), ), ranges: gimli::RangeLists::new(debug_ranges, debug_rnglists), + file_type: gimli::DwarfFileType::Main, }) } @@ -189,7 +190,10 @@ impl Context { let mut units = sections.units(); while let Some(header) = units.next()? { let unit_id = res_units.len(); - let offset = header.offset(); + let offset = match header.offset().as_debug_info_offset() { + Some(offset) => offset, + None => continue, + }; let dw_unit = match sections.unit(header) { Ok(dw_unit) => dw_unit, Err(_) => continue, @@ -272,11 +276,17 @@ impl Context { &self.sections } - // Finds the CU for the function address given. - // The index in the CU's function address table (`Functions::addresses`) - // is also returned because this is calculated here to ensure the function - // address actually resides in the functions of the CU. - fn find_unit_and_address(&self, probe: u64) -> Option<(&ResUnit, usize)> { + /// Finds the CUs for the function address given. + /// + /// There might be multiple CUs whose range contains this address. + /// Weak symbols have shown up in the wild which cause this to happen + /// but otherwise this can happen if the CU has non-contiguous functions + /// but only reports a single range. + /// + /// Consequently we return an iterator for all CUs which may contain the + /// address, and the caller must check if there is actually a function or + /// location in the CU for that address. + fn find_units(&self, probe: u64) -> impl Iterator> { // First up find the position in the array which could have our function // address. let pos = match self @@ -294,60 +304,50 @@ impl Context { // Once we have our index we iterate backwards from that position // looking for a matching CU. - for i in self.unit_ranges[..pos].iter().rev() { - // We know that this CU's start is beneath the probe already because - // of our sorted array. - debug_assert!(i.range.begin <= probe); - - // Each entry keeps track of the maximum end address seen so far, - // starting from the beginning of the array of unit ranges. We're - // iterating in reverse so if our probe is beyond the maximum range - // of this entry, then it's guaranteed to not fit in any prior - // entries, so we break out. - if probe > i.max_end { - break; - } - - // If this CU doesn't actually contain this address, move to the - // next CU. - if probe > i.range.end { - continue; - } - - // There might be multiple CUs whose range contains this address. - // Weak symbols have shown up in the wild which cause this to happen - // but otherwise this happened in rust-lang/backtrace-rs#327 too. In - // any case we assume that might happen, and as a result we need to - // find a CU which actually contains this function. - // - // Consequently we consult the function address table here, and only - // if there's actually a function in this CU which contains this - // address do we return this unit. - let unit = &self.units[i.unit_id]; - let funcs = match unit.parse_functions(&self.sections) { - Ok(func) => func, - Err(_) => continue, - }; - if let Some(addr) = funcs.find_address(probe) { - return Some((unit, addr)); - } - } - - None + self.unit_ranges[..pos] + .iter() + .rev() + .take_while(move |i| { + // We know that this CU's start is beneath the probe already because + // of our sorted array. + debug_assert!(i.range.begin <= probe); + + // Each entry keeps track of the maximum end address seen so far, + // starting from the beginning of the array of unit ranges. We're + // iterating in reverse so if our probe is beyond the maximum range + // of this entry, then it's guaranteed to not fit in any prior + // entries, so we break out. + probe <= i.max_end + }) + .filter_map(move |i| { + // If this CU doesn't actually contain this address, move to the + // next CU. + if probe > i.range.end { + return None; + } + Some(&self.units[i.unit_id]) + }) } /// Find the DWARF unit corresponding to the given virtual memory address. pub fn find_dwarf_unit(&self, probe: u64) -> Option<&gimli::Unit> { - self.find_unit_and_address(probe) - .map(|(unit, _)| &unit.dw_unit) + for unit in self.find_units(probe) { + match unit.find_function_or_location(probe, &self.sections, &self.units) { + Ok((Some(_), _)) | Ok((_, Some(_))) => return Some(&unit.dw_unit), + _ => {} + } + } + None } /// Find the source file and line corresponding to the given virtual memory address. pub fn find_location(&self, probe: u64) -> Result>, Error> { - match self.find_unit_and_address(probe) { - Some((unit, _)) => unit.find_location(probe, &self.sections), - None => Ok(None), + for unit in self.find_units(probe) { + if let Some(location) = unit.find_location(probe, &self.sections)? { + return Ok(Some(location)); + } } + Ok(None) } /// Return an iterator for the function frames corresponding to the given virtual @@ -360,60 +360,25 @@ impl Context { /// to the innermost inline function. Subsequent frames contain the caller and call /// location, until an non-inline caller is reached. pub fn find_frames(&self, probe: u64) -> Result, Error> { - let (unit, address) = match self.find_unit_and_address(probe) { - Some(x) => x, - None => return Ok(FrameIter(FrameIterState::Empty)), - }; - - let loc = unit.find_location(probe, &self.sections)?; - let functions = unit.parse_functions(&self.sections)?; - let function_index = functions.addresses[address].function; - let function = &functions.functions[function_index]; - let function = function - .1 - .borrow_with(|| Function::parse(function.0, &unit.dw_unit, &self.sections, &self.units)) - .as_ref() - .map_err(Error::clone)?; - - // Build the list of inlined functions that contain `probe`. - // `inlined_functions` is ordered from outside to inside. - let mut inlined_functions = maybe_small::Vec::new(); - let mut inlined_addresses = &function.inlined_addresses[..]; - loop { - let current_depth = inlined_functions.len(); - // Look up (probe, current_depth) in inline_ranges. - // `inlined_addresses` is sorted in "breadth-first traversal order", i.e. - // by `call_depth` first, and then by `range.begin`. See the comment at - // the sort call for more information about why. - let search = inlined_addresses.binary_search_by(|range| { - if range.call_depth > current_depth { - Ordering::Greater - } else if range.call_depth < current_depth { - Ordering::Less - } else if range.range.begin > probe { - Ordering::Greater - } else if range.range.end <= probe { - Ordering::Less - } else { - Ordering::Equal + for unit in self.find_units(probe) { + match unit.find_function_or_location(probe, &self.sections, &self.units)? { + (Some(function), location) => { + let inlined_functions = function.find_inlined_functions(probe); + return Ok(FrameIter(FrameIterState::Frames(FrameIterFrames { + unit, + sections: &self.sections, + function, + inlined_functions, + next: location, + }))); } - }); - if let Ok(index) = search { - let function_index = inlined_addresses[index].function; - inlined_functions.push(&function.inlined_functions[function_index]); - inlined_addresses = &inlined_addresses[index + 1..]; - } else { - break; + (None, Some(location)) => { + return Ok(FrameIter(FrameIterState::Location(Some(location)))); + } + _ => {} } } - - Ok(FrameIter(FrameIterState::Frames(FrameIterFrames { - unit, - sections: &self.sections, - function, - inlined_functions: inlined_functions.into_iter().rev(), - next: loc, - }))) + Ok(FrameIter(FrameIterState::Empty)) } /// Initialize all line data structures. This is used for benchmarks. @@ -529,8 +494,12 @@ where sequences.sort_by_key(|x| x.start); let mut files = Vec::new(); - let mut index = 0; let header = ilnp.header(); + match header.file(0) { + Some(file) => files.push(self.render_file(file, header, sections)?), + None => files.push(String::from("")), // DWARF version <= 4 may not have 0th index + } + let mut index = 1; while let Some(file) = header.file(index) { files.push(self.render_file(file, header, sections)?); index += 1; @@ -612,6 +581,34 @@ where })) } + fn find_function_or_location( + &self, + probe: u64, + sections: &gimli::Dwarf, + units: &[ResUnit], + ) -> Result<(Option<&Function>, Option>), Error> { + let functions = self.parse_functions(sections)?; + if functions.is_empty() { + // If there are no functions, then this unit may have line information only, + // so check for a location. + let location = self.find_location(probe, sections)?; + return Ok((None, location)); + } + let address = match functions.find_address(probe) { + Some(function) => function, + None => return Ok((None, None)), + }; + let function_index = functions.addresses[address].function; + let function = &functions.functions[function_index]; + let function = function + .1 + .borrow_with(|| Function::parse(function.0, &self.dw_unit, sections, units)) + .as_ref() + .map_err(Error::clone)?; + let location = self.find_location(probe, sections)?; + Ok((Some(function), location)) + } + fn render_file( &self, file: &gimli::FileEntry, @@ -657,7 +654,7 @@ fn path_push(path: &mut String, p: &str) { } } -fn name_attr<'abbrev, 'unit, R>( +fn name_attr( attr: gimli::AttributeValue, unit: &gimli::Unit, sections: &gimli::Dwarf, @@ -671,20 +668,23 @@ where return Ok(None); } - let mut entries = match attr { - gimli::AttributeValue::UnitRef(offset) => unit.entries_raw(Some(offset))?, + let (unit, offset) = match attr { + gimli::AttributeValue::UnitRef(offset) => (unit, offset), gimli::AttributeValue::DebugInfoRef(dr) => { - let unit = match units.binary_search_by_key(&dr.0, |unit| unit.offset.0) { + let res_unit = match units.binary_search_by_key(&dr.0, |unit| unit.offset.0) { // There is never a DIE at the unit offset or before the first unit. Ok(_) | Err(0) => return Err(gimli::Error::NoEntryAtGivenOffset), Err(i) => &units[i - 1], }; - unit.dw_unit - .entries_raw(Some(gimli::UnitOffset(dr.0 - unit.offset.0)))? + ( + &res_unit.dw_unit, + gimli::UnitOffset(dr.0 - res_unit.offset.0), + ) } _ => return Ok(None), }; + let mut entries = unit.entries_raw(Some(offset))?; let abbrev = if let Some(abbrev) = entries.read_abbreviation()? { abbrev } else { @@ -774,6 +774,10 @@ struct InlinedFunction { } impl Functions { + fn is_empty(&self) -> bool { + self.functions.is_empty() + } + fn parse(unit: &gimli::Unit, sections: &gimli::Dwarf) -> Result, Error> { let mut functions = Vec::new(); let mut addresses = Vec::new(); @@ -1035,6 +1039,44 @@ impl Function { } Ok(()) } + + /// Build the list of inlined functions that contain `probe`. + fn find_inlined_functions( + &self, + probe: u64, + ) -> iter::Rev>> { + // `inlined_functions` is ordered from outside to inside. + let mut inlined_functions = maybe_small::Vec::new(); + let mut inlined_addresses = &self.inlined_addresses[..]; + loop { + let current_depth = inlined_functions.len(); + // Look up (probe, current_depth) in inline_ranges. + // `inlined_addresses` is sorted in "breadth-first traversal order", i.e. + // by `call_depth` first, and then by `range.begin`. See the comment at + // the sort call for more information about why. + let search = inlined_addresses.binary_search_by(|range| { + if range.call_depth > current_depth { + Ordering::Greater + } else if range.call_depth < current_depth { + Ordering::Less + } else if range.range.begin > probe { + Ordering::Greater + } else if range.range.end <= probe { + Ordering::Less + } else { + Ordering::Equal + } + }); + if let Ok(index) = search { + let function_index = inlined_addresses[index].function; + inlined_functions.push(&self.inlined_functions[function_index]); + inlined_addresses = &inlined_addresses[index + 1..]; + } else { + break; + } + } + inlined_functions.into_iter().rev() + } } impl InlinedFunction { @@ -1192,6 +1234,7 @@ where R: gimli::Reader + 'ctx, { Empty, + Location(Option>), Frames(FrameIterFrames<'ctx, R>), } @@ -1214,6 +1257,16 @@ where pub fn next(&mut self) -> Result>, Error> { let frames = match &mut self.0 { FrameIterState::Empty => return Ok(None), + FrameIterState::Location(location) => { + // We can't move out of a mutable reference, so use `take` instead. + let location = location.take(); + self.0 = FrameIterState::Empty; + return Ok(Some(Frame { + dw_die_offset: None, + function: None, + location, + })); + } FrameIterState::Frames(frames) => frames, }; diff --git a/vendor/addr2line/tests/output_equivalence.rs b/vendor/addr2line/tests/output_equivalence.rs index 882ba0d486..9dc3666720 100644 --- a/vendor/addr2line/tests/output_equivalence.rs +++ b/vendor/addr2line/tests/output_equivalence.rs @@ -76,10 +76,9 @@ fn run_test(flags: Option<&str>) { let theirs = run_cmd("addr2line", &me, flags, addr); let ours = run_cmd(&exe, &me, flags, addr); - // HACK: GNU addr2line does not tidy up paths properly, causing double slashes to be printed - // for for inlined frames from /src/libpanic_unwind/lib.rs + // HACK: GNU addr2line does not tidy up paths properly, causing double slashes to be printed. // We consider our behavior to be correct, so we fix their output to match ours. - let theirs = theirs.replace("//src", "/src"); + let theirs = theirs.replace("//", "/"); assert!( theirs == ours, diff --git a/vendor/cc/.cargo-checksum.json b/vendor/cc/.cargo-checksum.json index 38ef094639..5abc7a731d 100644 --- a/vendor/cc/.cargo-checksum.json +++ b/vendor/cc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"b0b1a4de783164db718b9ada8f0bd4015e1b03ec7fc26e9c059aa2f3e02005e7","Cargo.toml":"c311fea03845624f712b11b46008a6dfe0de8534f17837729d06d5c9aa0325c0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"51405d284d2e0620db62c655c652fc0ec84f20c1cb30529227355c9575a9e6dd","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"b29f0dc4edb47d42e977f2b3cdda4273c0b62ad01b467740a856896811bacf2c","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d"} \ No newline at end of file +{"files":{"Cargo.lock":"06f6ff39f6f48f7524621e64948869c5280c180914fb57716893e9d5606b1159","Cargo.toml":"35e42408819c62cd58badcbac994e7639a4907d1b54097f706c9e068f03f86ae","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"51405d284d2e0620db62c655c652fc0ec84f20c1cb30529227355c9575a9e6dd","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"db91b5cbe314c76da13fbf29639e9d3233f7d9a57566ccc98f943870b9491cb7","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"} \ No newline at end of file diff --git a/vendor/cc/Cargo.lock b/vendor/cc/Cargo.lock index 14a998403c..f0a0fba62e 100644 --- a/vendor/cc/Cargo.lock +++ b/vendor/cc/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "cc" -version = "1.0.61" +version = "1.0.62" dependencies = [ "jobserver", "tempfile", @@ -36,15 +36,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.77" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "ppv-lite86" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "rand" diff --git a/vendor/cc/Cargo.toml b/vendor/cc/Cargo.toml index f716eb4621..1f45e9a0f4 100644 --- a/vendor/cc/Cargo.toml +++ b/vendor/cc/Cargo.toml @@ -13,9 +13,9 @@ [package] edition = "2018" name = "cc" -version = "1.0.61" +version = "1.0.62" authors = ["Alex Crichton "] -exclude = ["/.travis.yml", "/appveyor.yml"] +exclude = ["/.github", "/.travis.yml", "/appveyor.yml"] description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" homepage = "https://github.com/alexcrichton/cc-rs" documentation = "https://docs.rs/cc" diff --git a/vendor/cc/src/lib.rs b/vendor/cc/src/lib.rs index d3a09258a9..0fdc705e54 100644 --- a/vendor/cc/src/lib.rs +++ b/vendor/cc/src/lib.rs @@ -1459,6 +1459,14 @@ impl Build { cmd.args .push(format!("--target={}-apple-darwin", arch).into()); } + } else if target.contains("macabi") { + if let Some(arch) = + map_darwin_target_from_rust_to_compiler_architecture(target) + { + let ios = if arch == "arm64" { "ios" } else { "ios13.0" }; + cmd.args + .push(format!("--target={}-apple-{}-macabi", arch, ios).into()); + } } else { cmd.args.push(format!("--target={}", target).into()); } @@ -1881,6 +1889,7 @@ impl Build { enum ArchSpec { Device(&'static str), Simulator(&'static str), + Catalyst(&'static str), } let target = self.get_target()?; @@ -1890,18 +1899,38 @@ impl Build { "Unknown architecture for iOS target.", ) })?; - let arch = match arch { - "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), - "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), - "arm64e" => ArchSpec::Device("arm64e"), - "arm64" | "aarch64" => ArchSpec::Device("arm64"), - "i386" | "i686" => ArchSpec::Simulator("-m32"), - "x86_64" => ArchSpec::Simulator("-m64"), - _ => { - return Err(Error::new( - ErrorKind::ArchitectureInvalid, - "Unknown architecture for iOS target.", - )); + + let is_catalyst = match target.split('-').nth(3) { + Some(v) => v == "macabi", + None => false, + }; + + let arch = if is_catalyst { + match arch { + "arm64e" => ArchSpec::Catalyst("arm64e"), + "arm64" | "aarch64" => ArchSpec::Catalyst("arm64"), + "x86_64" => ArchSpec::Catalyst("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )); + } + } + } else { + match arch { + "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), + "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), + "arm64e" => ArchSpec::Device("arm64e"), + "arm64" | "aarch64" => ArchSpec::Device("arm64"), + "i386" | "i686" => ArchSpec::Simulator("-m32"), + "x86_64" => ArchSpec::Simulator("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )); + } } }; @@ -1922,6 +1951,7 @@ impl Build { .push(format!("-mios-simulator-version-min={}", min_version).into()); "iphonesimulator" } + ArchSpec::Catalyst(_) => "macosx", }; self.print(&format!("Detecting iOS SDK path for {}", sdk)); @@ -2124,9 +2154,8 @@ impl Build { fn envflags(&self, name: &str) -> Vec { self.get_var(name) .unwrap_or(String::new()) - .split(|c: char| c.is_whitespace()) - .filter(|s| !s.is_empty()) - .map(|s| s.to_string()) + .split_ascii_whitespace() + .map(|slice| slice.to_string()) .collect() } @@ -2526,14 +2555,13 @@ impl Build { return Ok(ret.clone()); } - let sdk_path = self - .cmd("xcrun") - .arg("--show-sdk-path") - .arg("--sdk") - .arg(sdk) - .stderr(Stdio::inherit()) - .output()? - .stdout; + let sdk_path = run_output( + self.cmd("xcrun") + .arg("--show-sdk-path") + .arg("--sdk") + .arg(sdk), + "xcrun", + )?; let sdk_path = match String::from_utf8(sdk_path) { Ok(p) => p, diff --git a/vendor/cfg-if/.cargo-checksum.json b/vendor/cfg-if/.cargo-checksum.json new file mode 100644 index 0000000000..93e07c191b --- /dev/null +++ b/vendor/cfg-if/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"5b2a8f6e5256957c029cf3a8912d51438e7faa5891c5c102c312f6d4599c1f00","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"2406e83ee174e30aa67f8ab266836fa78545012b196395aff37c152321e2c713","src/lib.rs":"54b0f108b0dc48a077c52c0bcd22b64ef4de083e5e2b7d405e50ae4d78224f1b","tests/xcrate.rs":"c0734dae6e63beafcd60bf53546115a2320735b51035c9e2387fdf9301580934"},"package":"baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"} \ No newline at end of file diff --git a/vendor/cfg-if/Cargo.toml b/vendor/cfg-if/Cargo.toml new file mode 100644 index 0000000000..13a32ba204 --- /dev/null +++ b/vendor/cfg-if/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "cfg-if" +version = "1.0.0" +authors = ["Alex Crichton "] +description = "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n" +homepage = "https://github.com/alexcrichton/cfg-if" +documentation = "https://docs.rs/cfg-if" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cfg-if" +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[features] +rustc-dep-of-std = ["core", "compiler_builtins"] +[badges.travis-ci] +repository = "alexcrichton/cfg-if" diff --git a/vendor/object-0.20.0/LICENSE-APACHE b/vendor/cfg-if/LICENSE-APACHE similarity index 100% rename from vendor/object-0.20.0/LICENSE-APACHE rename to vendor/cfg-if/LICENSE-APACHE diff --git a/vendor/cfg-if/LICENSE-MIT b/vendor/cfg-if/LICENSE-MIT new file mode 100644 index 0000000000..39e0ed6602 --- /dev/null +++ b/vendor/cfg-if/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/cfg-if/README.md b/vendor/cfg-if/README.md new file mode 100644 index 0000000000..50b5e3b2dc --- /dev/null +++ b/vendor/cfg-if/README.md @@ -0,0 +1,47 @@ +# cfg-if + +[Documentation](https://docs.rs/cfg-if) + +A macro to ergonomically define an item depending on a large number of #[cfg] +parameters. Structured like an if-else chain, the first matching branch is the +item that gets emitted. + +```toml +[dependencies] +cfg-if = "0.1" +``` + +## Example + +```rust +cfg_if::cfg_if! { + if #[cfg(unix)] { + fn foo() { /* unix specific functionality */ } + } else if #[cfg(target_pointer_width = "32")] { + fn foo() { /* non-unix, 32-bit functionality */ } + } else { + fn foo() { /* fallback implementation */ } + } +} + +fn main() { + foo(); +} +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `cfg-if` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/vendor/cfg-if/src/lib.rs b/vendor/cfg-if/src/lib.rs new file mode 100644 index 0000000000..52bbbe0f37 --- /dev/null +++ b/vendor/cfg-if/src/lib.rs @@ -0,0 +1,176 @@ +//! A macro for defining `#[cfg]` if-else statements. +//! +//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C +//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases, +//! emitting the implementation which matches first. +//! +//! This allows you to conveniently provide a long list `#[cfg]`'d blocks of code +//! without having to rewrite each clause multiple times. +//! +//! # Example +//! +//! ``` +//! cfg_if::cfg_if! { +//! if #[cfg(unix)] { +//! fn foo() { /* unix specific functionality */ } +//! } else if #[cfg(target_pointer_width = "32")] { +//! fn foo() { /* non-unix, 32-bit functionality */ } +//! } else { +//! fn foo() { /* fallback implementation */ } +//! } +//! } +//! +//! # fn main() {} +//! ``` + +#![no_std] +#![doc(html_root_url = "https://docs.rs/cfg-if")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +/// The main macro provided by this crate. See crate documentation for more +/// information. +#[macro_export] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($meta:meta)] { $($tokens:tt)* } + ) else * else { + $($tokens2:tt)* + }) => { + $crate::cfg_if! { + @__items + () ; + $( ( ($meta) ($($tokens)*) ), )* + ( () ($($tokens2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($i_met:meta)] { $($i_tokens:tt)* } + $( + else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } + )* + ) => { + $crate::cfg_if! { + @__items + () ; + ( ($i_met) ($($i_tokens)*) ), + $( ( ($e_met) ($($e_tokens)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + #[cfg(all($($m,)* not(any($($not),*))))] $crate::cfg_if! { @__identity $($tokens)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + $crate::cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to make __apply work out right for different match types, + // because of how macros matching/expand stuff. + (@__identity $($tokens:tt)*) => { + $($tokens)* + }; +} + +#[cfg(test)] +mod tests { + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option2; + fn works1() -> Option2 { Some(1) } + } else { + fn works1() -> Option { None } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works2() -> bool { false } + } else if #[cfg(test)] { + fn works2() -> bool { true } + } else { + fn works2() -> bool { false } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works3() -> bool { false } + } else { + fn works3() -> bool { true } + } + } + + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option3; + fn works4() -> Option3 { Some(1) } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works5() -> bool { false } + } else if #[cfg(test)] { + fn works5() -> bool { true } + } + } + + #[test] + fn it_works() { + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); + } + + #[test] + #[allow(clippy::assertions_on_constants)] + fn test_usage_within_a_function() { + cfg_if! {if #[cfg(debug_assertions)] { + // we want to put more than one thing here to make sure that they + // all get configured properly. + assert!(cfg!(debug_assertions)); + assert_eq!(4, 2+2); + } else { + assert!(works1().is_some()); + assert_eq!(10, 5+5); + }} + } + + trait Trait { + fn blah(&self); + } + + #[allow(dead_code)] + struct Struct; + + impl Trait for Struct { + cfg_if! { + if #[cfg(feature = "blah")] { + fn blah(&self) { + unimplemented!(); + } + } else { + fn blah(&self) { + unimplemented!(); + } + } + } + } +} diff --git a/vendor/cfg-if/tests/xcrate.rs b/vendor/cfg-if/tests/xcrate.rs new file mode 100644 index 0000000000..e7b4a362ad --- /dev/null +++ b/vendor/cfg-if/tests/xcrate.rs @@ -0,0 +1,14 @@ +cfg_if::cfg_if! { + if #[cfg(foo)] { + fn works() -> bool { false } + } else if #[cfg(test)] { + fn works() -> bool { true } + } else { + fn works() -> bool { false } + } +} + +#[test] +fn smoke() { + assert!(works()); +} diff --git a/vendor/crc32fast/.cargo-checksum.json b/vendor/crc32fast/.cargo-checksum.json index 7c08c96555..ce77fd1b4e 100644 --- a/vendor/crc32fast/.cargo-checksum.json +++ b/vendor/crc32fast/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c85c0241394119d8887c5e5624aba9a1a1fd21578f1a1e3f2a0d50d95d752cff","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"61d383b05b87d78f94d2937e2580cce47226d17823c0430fbcad09596537efcf","README.md":"c0891c7ff327441bf16da593b0e721951f9f6d10bb26f9356aba6a7b0b0c4575","benches/bench.rs":"9a45a7ebc8fecf7f9976bea0e3c00c13731c0b3566536b0bc83788986e801770","build.rs":"4ccc50c3da67eb27f0b622440d2b7aee2f73fa9c71884571f3c041122231d105","src/baseline.rs":"bbe8fe49ceccbf9749052fa9c2756cf95f0fc79a063e5d3b509e3600283464ea","src/combine.rs":"7147fc4002190d36d253ea5e194e0419035b087304bcb17887efe09a8a198815","src/lib.rs":"25c55822d7fd53ff1ff0769bcffbdbcade00d45ac042a541b7189c2e94b91ee7","src/specialized/aarch64.rs":"cc8097e68f1269cee32aa856b4f7e4ba7b7472df6c2f4cecd600d292a838fe83","src/specialized/mod.rs":"bc92450e8522e9df202b346b3a209153cbb0d6587804cbfd2b947fda0f190ed6","src/specialized/pclmulqdq.rs":"6ace803b42ff70a571fd8b5f3f7c2d5a836873ce28759381c2882319b8edba70","src/table.rs":"3201c520d97c5e2cf80b8a03d72fa2e3f1270bbdf93c2fbf85498a8ea39bc64b"},"package":"ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"} \ No newline at end of file +{"files":{"Cargo.toml":"15f76c4d8eb864eb816742390eb9941fd1186d67ec306252a0b78410448715d0","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"61d383b05b87d78f94d2937e2580cce47226d17823c0430fbcad09596537efcf","README.md":"6891e252b3c141f66e37ed5ed5aae15418968050a769824f2656115bd0b95137","benches/bench.rs":"b7e23cad4523e77c5c8f8e242d242cd4cd2ed855ecb9c5c42bf91116c5dc732d","build.rs":"4ccc50c3da67eb27f0b622440d2b7aee2f73fa9c71884571f3c041122231d105","src/baseline.rs":"bbe8fe49ceccbf9749052fa9c2756cf95f0fc79a063e5d3b509e3600283464ea","src/combine.rs":"7147fc4002190d36d253ea5e194e0419035b087304bcb17887efe09a8a198815","src/lib.rs":"25c55822d7fd53ff1ff0769bcffbdbcade00d45ac042a541b7189c2e94b91ee7","src/specialized/aarch64.rs":"cc8097e68f1269cee32aa856b4f7e4ba7b7472df6c2f4cecd600d292a838fe83","src/specialized/mod.rs":"bc92450e8522e9df202b346b3a209153cbb0d6587804cbfd2b947fda0f190ed6","src/specialized/pclmulqdq.rs":"6ace803b42ff70a571fd8b5f3f7c2d5a836873ce28759381c2882319b8edba70","src/table.rs":"3201c520d97c5e2cf80b8a03d72fa2e3f1270bbdf93c2fbf85498a8ea39bc64b"},"package":"81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"} \ No newline at end of file diff --git a/vendor/crc32fast/Cargo.toml b/vendor/crc32fast/Cargo.toml index ca8bbcc1e7..d211f29a7f 100644 --- a/vendor/crc32fast/Cargo.toml +++ b/vendor/crc32fast/Cargo.toml @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -12,7 +12,7 @@ [package] name = "crc32fast" -version = "1.2.0" +version = "1.2.1" authors = ["Sam Rijs ", "Alex Crichton "] description = "Fast, SIMD-accelerated CRC32 (IEEE) checksum computation" readme = "README.md" @@ -24,16 +24,16 @@ repository = "https://github.com/srijs/rust-crc32fast" name = "bench" harness = false [dependencies.cfg-if] -version = "0.1" +version = "1.0" [dev-dependencies.bencher] version = "0.1" [dev-dependencies.quickcheck] -version = "0.6" +version = "0.9" default-features = false [dev-dependencies.rand] -version = "0.4" +version = "0.7" [features] default = ["std"] diff --git a/vendor/crc32fast/README.md b/vendor/crc32fast/README.md index 4267dfaf2d..0f1f78b885 100644 --- a/vendor/crc32fast/README.md +++ b/vendor/crc32fast/README.md @@ -46,7 +46,7 @@ In order to ensure memory safety, the relevant code has been fuzz tested using [ On top of that, every commit is tested using an address sanitizer in CI to catch any out of bounds memory accesses. -Even though neither fuzzing not sanitization has revealed any safety bugs yet, please don't hesitate to file an issue if you run into any crashes or other unexpected behaviour. +Even though neither fuzzing nor sanitization has revealed any safety bugs yet, please don't hesitate to file an issue if you run into any crashes or other unexpected behaviour. ## Available feature flags diff --git a/vendor/crc32fast/benches/bench.rs b/vendor/crc32fast/benches/bench.rs index 91fbbb6de8..d702df0e11 100644 --- a/vendor/crc32fast/benches/bench.rs +++ b/vendor/crc32fast/benches/bench.rs @@ -9,7 +9,7 @@ use rand::Rng; fn bench(b: &mut Bencher, size: usize, hasher_init: Hasher) { let mut bytes = vec![0u8; size]; - rand::thread_rng().fill_bytes(&mut bytes); + rand::thread_rng().fill(&mut bytes[..]); b.iter(|| { let mut hasher = hasher_init.clone(); diff --git a/vendor/dlmalloc/.cargo-checksum.json b/vendor/dlmalloc/.cargo-checksum.json index ac5edb0d26..9f2a10f2b0 100644 --- a/vendor/dlmalloc/.cargo-checksum.json +++ b/vendor/dlmalloc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"31456b4e41100d025b80296675c7dec42dec38851f2725aef4a28d891f8223f0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e26786bd9af68f3065532fa85b68b8de12e0f6f455240d9a903ae947986aaa5f","build.rs":"1423186016b6fecf4dc2c3a7d506face8f644ec9c3dda035fe485d25a7e6a02d","src/dlmalloc.c":"103602c3fcbe200d5e257cdd7353d84bcc033d887bea3b245321319bf5401f47","src/dlmalloc.rs":"f731b5da9bb659b5562e273e36c06e43820a303b18abbcccc74c163aa90d68d4","src/global.rs":"a3f646a2a0814258376a24a2117d8651ae9621f7021d077120adfd475a789139","src/lib.rs":"e344757b515834c1c959f26f8622ac30253cc7b9e3e803d74caf2255006a25bb","src/linux.rs":"b7d9bfa6e22a3629485e287f235f711955a3029d69b4701741ab02152be78a84","src/macos.rs":"a4e8b02740e6de126269cfc86538f8c94ba9032283529fd171ca784a09269f9f","src/sgx.rs":"b7462ec8b0a111bf9de2ae595f34ce0b62853d1431fe548722b4c3dce3b491db","src/wasm.rs":"6cf4f3aea228c3c58dc1fa8dcbb38ca7046ab3704ad6600bed5798b310ca58b1","tests/global.rs":"6856894eb79abb643e3fb6cac9b71470c2f827be1dd363539053c3dcb84fd6de","tests/smoke.rs":"e22bbf7c4d0e297428c5c58d117957e61c21f494d129e6e93f9490360631bc36"},"package":"35055b1021724f4eb5262eb49130eebff23fc59fc5a14160e05faad8eeb36673"} \ No newline at end of file +{"files":{"Cargo.toml":"444e27e88cbc42aad5a61d471747cf51c779c8ca33ba40237f52c4ef06d0f874","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e26786bd9af68f3065532fa85b68b8de12e0f6f455240d9a903ae947986aaa5f","build.rs":"1423186016b6fecf4dc2c3a7d506face8f644ec9c3dda035fe485d25a7e6a02d","src/dlmalloc.c":"103602c3fcbe200d5e257cdd7353d84bcc033d887bea3b245321319bf5401f47","src/dlmalloc.rs":"d8120a4e3069107d2782e4df7e8d062486ed2d9534237aa270d78e4cdacd1f34","src/dummy.rs":"00dc39321426add094ab8efba58fb5f886726c06f032b8cb184b3d5fc71ad8ff","src/global.rs":"51b9cd2c1ed33bad34a2d4565113338eedc9154690fe06b6b67182b994ec5ac0","src/lib.rs":"86824bdfb667e88a9ef9b4baa535cd045229ca2b8b881640683f47bff904e767","src/linux.rs":"52e13e1e0c83e53a1b6da6b928c6d410cef1627008f021c12d45271aac007e6c","src/macos.rs":"63887811f49e96953aaa8472211bda54c052e21e232113adb09e73a96bd3a8f0","src/wasm.rs":"e7e47ad1e3851d5453ebfdb3fdf82825a537c27737e048bf33377fbab522ad97","tests/global.rs":"6f3ca05b44fb60fd7967d2ca1d11338e177b0266d75454410b82ea704c246892","tests/smoke.rs":"e22bbf7c4d0e297428c5c58d117957e61c21f494d129e6e93f9490360631bc36"},"package":"332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254"} \ No newline at end of file diff --git a/vendor/dlmalloc/Cargo.toml b/vendor/dlmalloc/Cargo.toml index c3796a7b4e..85efa71a10 100644 --- a/vendor/dlmalloc/Cargo.toml +++ b/vendor/dlmalloc/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "dlmalloc" -version = "0.1.4" +version = "0.2.1" authors = ["Alex Crichton "] description = "A Rust port of the dlmalloc allocator\n" homepage = "https://github.com/alexcrichton/dlmalloc-rs" @@ -39,7 +39,6 @@ package = "rustc-std-workspace-core" version = "0.3" [features] -allocator-api = [] debug = [] global = [] rustc-dep-of-std = ["core", "compiler_builtins/rustc-dep-of-std"] diff --git a/vendor/dlmalloc/src/dlmalloc.rs b/vendor/dlmalloc/src/dlmalloc.rs index 06e3e899a9..d16f523269 100644 --- a/vendor/dlmalloc/src/dlmalloc.rs +++ b/vendor/dlmalloc/src/dlmalloc.rs @@ -7,9 +7,9 @@ use core::cmp; use core::mem; use core::ptr; -use sys; +use Allocator; -pub struct Dlmalloc { +pub struct Dlmalloc { smallmap: u32, treemap: u32, smallbins: [*mut Chunk; (NSMALLBINS + 1) * 2], @@ -24,31 +24,9 @@ pub struct Dlmalloc { trim_check: usize, least_addr: *mut u8, release_checks: usize, + system_allocator: A, } - -unsafe impl Send for Dlmalloc {} - -pub const DLMALLOC_INIT: Dlmalloc = Dlmalloc { - smallmap: 0, - treemap: 0, - smallbins: [0 as *mut _; (NSMALLBINS + 1) * 2], - treebins: [0 as *mut _; NTREEBINS], - dvsize: 0, - topsize: 0, - dv: 0 as *mut _, - top: 0 as *mut _, - footprint: 0, - max_footprint: 0, - seg: Segment { - base: 0 as *mut _, - size: 0, - next: 0 as *mut _, - flags: 0, - }, - trim_check: 0, - least_addr: 0 as *mut _, - release_checks: 0, -}; +unsafe impl Send for Dlmalloc {} // TODO: document this const NSMALLBINS: usize = 32; @@ -108,7 +86,34 @@ fn leftshift_for_tree_index(x: u32) -> u32 { } } -impl Dlmalloc { +impl Dlmalloc { + pub const fn new(system_allocator: A) -> Dlmalloc { + Dlmalloc { + smallmap: 0, + treemap: 0, + smallbins: [0 as *mut _; (NSMALLBINS + 1) * 2], + treebins: [0 as *mut _; NTREEBINS], + dvsize: 0, + topsize: 0, + dv: 0 as *mut _, + top: 0 as *mut _, + footprint: 0, + max_footprint: 0, + seg: Segment { + base: 0 as *mut _, + size: 0, + next: 0 as *mut _, + flags: 0, + }, + trim_check: 0, + least_addr: 0 as *mut _, + release_checks: 0, + system_allocator, + } + } +} + +impl Dlmalloc { // TODO: can we get rid of this? pub fn malloc_alignment(&self) -> usize { mem::size_of::() * 2 @@ -225,7 +230,7 @@ impl Dlmalloc { } pub unsafe fn calloc_must_clear(&self, ptr: *mut u8) -> bool { - !sys::allocates_zeros() || !Chunk::mmapped(Chunk::from_mem(ptr)) + !self.system_allocator.allocates_zeros() || !Chunk::mmapped(Chunk::from_mem(ptr)) } pub unsafe fn malloc(&mut self, size: usize) -> *mut u8 { @@ -344,6 +349,7 @@ impl Dlmalloc { self.sys_alloc(nb) } + /// allocates system resources unsafe fn sys_alloc(&mut self, size: usize) -> *mut u8 { self.check_malloc_state(); // keep in sync with max_request @@ -352,7 +358,7 @@ impl Dlmalloc { DEFAULT_GRANULARITY, ); - let (tbase, tsize, flags) = sys::alloc(asize); + let (tbase, tsize, flags) = self.system_allocator.alloc(asize); if tbase.is_null() { return tbase; } @@ -533,7 +539,7 @@ impl Dlmalloc { let oldmmsize = oldsize + offset + self.mmap_foot_pad(); let newmmsize = self.mmap_align(nb + 6 * mem::size_of::() + self.malloc_alignment() - 1); - let ptr = sys::remap( + let ptr = self.system_allocator.remap( (oldp as *mut u8).offset(-(offset as isize)), oldmmsize, newmmsize, @@ -555,7 +561,7 @@ impl Dlmalloc { } fn mmap_align(&self, a: usize) -> usize { - align_up(a, sys::page_size()) + align_up(a, self.system_allocator.page_size()) } // Only call this with power-of-two alignment and alignment > @@ -631,7 +637,10 @@ impl Dlmalloc { let prevsize = (*p).prev_foot; if Chunk::mmapped(p) { psize += prevsize + self.mmap_foot_pad(); - if sys::free((p as *mut u8).offset(-(prevsize as isize)), psize) { + if self + .system_allocator + .free((p as *mut u8).offset(-(prevsize as isize)), psize) + { self.footprint -= psize; } return; @@ -1161,7 +1170,10 @@ impl Dlmalloc { if Chunk::mmapped(p) { psize += prevsize + self.mmap_foot_pad(); - if sys::free((p as *mut u8).offset(-(prevsize as isize)), psize) { + if self + .system_allocator + .free((p as *mut u8).offset(-(prevsize as isize)), psize) + { self.footprint -= psize; } return; @@ -1242,10 +1254,13 @@ impl Dlmalloc { debug_assert!(!sp.is_null()); if !Segment::is_extern(sp) { - if Segment::can_release_part(sp) { + if Segment::can_release_part(&self.system_allocator, sp) { if (*sp).size >= extra && !self.has_segment_link(sp) { let newsize = (*sp).size - extra; - if sys::free_part((*sp).base, (*sp).size, newsize) { + if self + .system_allocator + .free_part((*sp).base, (*sp).size, newsize) + { released = extra; } } @@ -1295,7 +1310,7 @@ impl Dlmalloc { let next = (*sp).next; nsegs += 1; - if Segment::can_release_part(sp) && !Segment::is_extern(sp) { + if Segment::can_release_part(&self.system_allocator, sp) && !Segment::is_extern(sp) { let p = self.align_as_chunk(base); let psize = Chunk::size(p); // We can unmap if the first chunk holds the entire segment and @@ -1311,7 +1326,7 @@ impl Dlmalloc { } else { self.unlink_large_chunk(tp); } - if sys::free(base, size) { + if self.system_allocator.free(base, size) { released += size; self.footprint -= size; // unlink our obsolete record @@ -1405,7 +1420,7 @@ impl Dlmalloc { ); debug_assert!(p as *mut u8 >= self.least_addr); debug_assert!(!self.is_small(sz)); - debug_assert_eq!(align_up(len, sys::page_size()), len); + debug_assert_eq!(align_up(len, self.system_allocator.page_size()), len); debug_assert_eq!((*Chunk::plus_offset(p, sz)).head, Chunk::fencepost_head()); debug_assert_eq!( (*Chunk::plus_offset(p, sz + mem::size_of::())).head, @@ -1746,8 +1761,8 @@ impl Segment { (*seg).flags & EXTERN != 0 } - unsafe fn can_release_part(seg: *mut Segment) -> bool { - sys::can_release_part((*seg).flags >> 1) + unsafe fn can_release_part(system_allocator: &A, seg: *mut Segment) -> bool { + system_allocator.can_release_part((*seg).flags >> 1) } unsafe fn sys_flags(seg: *mut Segment) -> u32 { @@ -1766,10 +1781,11 @@ impl Segment { #[cfg(test)] mod tests { use super::*; + use System; // Prime the allocator with some allocations such that there will be free // chunks in the treemap - unsafe fn setup_treemap(a: &mut Dlmalloc) { + unsafe fn setup_treemap(a: &mut Dlmalloc) { let large_request_size = NSMALLBINS * (1 << SMALLBIN_SHIFT); assert!(!a.is_small(large_request_size)); let large_request1 = a.malloc(large_request_size); @@ -1784,7 +1800,7 @@ mod tests { // Test allocating, with a non-empty treemap, a specific size that used to // trigger an integer overflow bug fn treemap_alloc_overflow_minimal() { - let mut a = DLMALLOC_INIT; + let mut a = Dlmalloc::new(System::new()); unsafe { setup_treemap(&mut a); let min_idx31_size = (0xc000 << TREEBIN_SHIFT) - a.chunk_overhead() + 1; @@ -1795,7 +1811,7 @@ mod tests { #[test] // Test allocating the maximum request size with a non-empty treemap fn treemap_alloc_max() { - let mut a = DLMALLOC_INIT; + let mut a = Dlmalloc::new(System::new()); unsafe { setup_treemap(&mut a); let max_request_size = a.max_request() - 1; diff --git a/vendor/dlmalloc/src/dummy.rs b/vendor/dlmalloc/src/dummy.rs new file mode 100644 index 0000000000..bd8d5b6e2a --- /dev/null +++ b/vendor/dlmalloc/src/dummy.rs @@ -0,0 +1,42 @@ +use core::ptr; +use Allocator; + +pub struct System { + _priv: (), +} + +impl System { + pub const fn new() -> System { + System { _priv: () } + } +} + +unsafe impl Allocator for System { + fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) { + (ptr::null_mut(), 0, 0) + } + + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + ptr::null_mut() + } + + fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { + false + } + + fn free(&self, _ptr: *mut u8, _size: usize) -> bool { + false + } + + fn can_release_part(&self, _flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + false + } + + fn page_size(&self) -> usize { + 1 + } +} diff --git a/vendor/dlmalloc/src/global.rs b/vendor/dlmalloc/src/global.rs index bb9ce0446d..fbac31539c 100644 --- a/vendor/dlmalloc/src/global.rs +++ b/vendor/dlmalloc/src/global.rs @@ -1,9 +1,5 @@ -#[cfg(feature = "allocator-api")] -use core::alloc::{Alloc, AllocErr}; use core::alloc::{GlobalAlloc, Layout}; use core::ops::{Deref, DerefMut}; -#[cfg(feature = "allocator-api")] -use core::ptr::NonNull; use Dlmalloc; @@ -35,35 +31,7 @@ unsafe impl GlobalAlloc for GlobalDlmalloc { } } -#[cfg(feature = "allocator-api")] -unsafe impl Alloc for GlobalDlmalloc { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - get().alloc(layout) - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - get().dealloc(ptr, layout) - } - - #[inline] - unsafe fn realloc( - &mut self, - ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - Alloc::realloc(&mut *get(), ptr, layout, new_size) - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - get().alloc_zeroed(layout) - } -} - -static mut DLMALLOC: Dlmalloc = Dlmalloc(::dlmalloc::DLMALLOC_INIT); +static mut DLMALLOC: Dlmalloc = Dlmalloc::new(); struct Instance; diff --git a/vendor/dlmalloc/src/lib.rs b/vendor/dlmalloc/src/lib.rs index 38826effc5..22a43c65e8 100644 --- a/vendor/dlmalloc/src/lib.rs +++ b/vendor/dlmalloc/src/lib.rs @@ -11,33 +11,66 @@ //! Support for other platforms is largely untested and unused, but is used when //! testing this crate. -#![cfg_attr(feature = "allocator-api", feature(allocator_api))] -#![cfg_attr(target_env = "sgx", feature(llvm_asm))] -#![cfg_attr(not(feature = "allocator-api"), allow(dead_code))] +#![allow(dead_code)] #![no_std] #![deny(missing_docs)] -#[cfg(feature = "allocator-api")] -use core::alloc::{Alloc, AllocErr, Layout}; use core::cmp; use core::ptr; +use sys::System; -#[cfg(all(feature = "global", not(test)))] +#[cfg(feature = "global")] pub use self::global::GlobalDlmalloc; mod dlmalloc; -#[cfg(all(feature = "global", not(test)))] +#[cfg(feature = "global")] mod global; +/// In order for this crate to efficiently manage memory, it needs a way to communicate with the +/// underlying platform. This `Allocator` trait provides an interface for this communication. +pub unsafe trait Allocator: Send { + /// Allocates system memory region of at least `size` bytes + /// Returns a triple of `(base, size, flags)` where `base` is a pointer to the beginning of the + /// allocated memory region. `size` is the actual size of the region while `flags` specifies + /// properties of the allocated region. If `EXTERN_BIT` (bit 0) set in flags, then we did not + /// allocate this segment and so should not try to deallocate or merge with others. + /// This function can return a `std::ptr::null_mut()` when allocation fails (other values of + /// the triple will be ignored). + fn alloc(&self, size: usize) -> (*mut u8, usize, u32); + + /// Remaps system memory region at `ptr` with size `oldsize` to a potential new location with + /// size `newsize`. `can_move` indicates if the location is allowed to move to a completely new + /// location, or that it is only allowed to change in size. Returns a pointer to the new + /// location in memory. + /// This function can return a `std::ptr::null_mut()` to signal an error. + fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8; + + /// Frees a part of a memory chunk. The original memory chunk starts at `ptr` with size `oldsize` + /// and is turned into a memory region starting at the same address but with `newsize` bytes. + /// Returns `true` iff the access memory region could be freed. + fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool; + + /// Frees an entire memory region. Returns `true` iff the operation succeeded. When `false` is + /// returned, the `dlmalloc` may re-use the location on future allocation requests + fn free(&self, ptr: *mut u8, size: usize) -> bool; + + /// Indicates if the system can release a part of memory. For the `flags` argument, see + /// `Allocator::alloc` + fn can_release_part(&self, flags: u32) -> bool; + + /// Indicates whether newly allocated regions contain zeros. + fn allocates_zeros(&self) -> bool; + + /// Returns the page size. Must be a power of two + fn page_size(&self) -> usize; +} + /// An allocator instance /// /// Instances of this type are used to allocate blocks of memory. For best /// results only use one of these. Currently doesn't implement `Drop` to release /// lingering memory back to the OS. That may happen eventually though! -pub struct Dlmalloc(dlmalloc::Dlmalloc); - -/// Constant initializer for `Dlmalloc` structure. -pub const DLMALLOC_INIT: Dlmalloc = Dlmalloc(dlmalloc::DLMALLOC_INIT); +pub struct Dlmalloc(dlmalloc::Dlmalloc); #[cfg(target_arch = "wasm32")] #[path = "wasm.rs"] @@ -51,16 +84,25 @@ mod sys; #[path = "linux.rs"] mod sys; -#[cfg(target_env = "sgx")] -#[path = "sgx.rs"] +#[cfg(not(any(target_os = "linux", target_os = "macos", target_arch = "wasm32")))] +#[path = "dummy.rs"] mod sys; -impl Dlmalloc { - /// Creates a new instance of an allocator, same as `DLMALLOC_INIT`. - pub fn new() -> Dlmalloc { - DLMALLOC_INIT +impl Dlmalloc { + /// Creates a new instance of an allocator + pub const fn new() -> Dlmalloc { + Dlmalloc(dlmalloc::Dlmalloc::new(System::new())) } +} +impl Dlmalloc { + /// Creates a new instance of an allocator + pub const fn new_with_allocator(sys_allocator: A) -> Dlmalloc { + Dlmalloc(dlmalloc::Dlmalloc::new(sys_allocator)) + } +} + +impl Dlmalloc { /// Allocates `size` bytes with `align` align. /// /// Returns a null pointer if allocation fails. Returns a valid pointer @@ -129,34 +171,3 @@ impl Dlmalloc { } } } - -#[cfg(feature = "allocator-api")] -unsafe impl Alloc for Dlmalloc { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - let ptr = ::malloc(self, layout.size(), layout.align()); - ptr::NonNull::new(ptr).ok_or(AllocErr) - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: ptr::NonNull, layout: Layout) { - ::free(self, ptr.as_ptr(), layout.size(), layout.align()) - } - - #[inline] - unsafe fn realloc( - &mut self, - ptr: ptr::NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let ptr = ::realloc(self, ptr.as_ptr(), layout.size(), layout.align(), new_size); - ptr::NonNull::new(ptr).ok_or(AllocErr) - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - let ptr = ::calloc(self, layout.size(), layout.align()); - ptr::NonNull::new(ptr).ok_or(AllocErr) - } -} diff --git a/vendor/dlmalloc/src/linux.rs b/vendor/dlmalloc/src/linux.rs index cbc4ef1ff9..42e6549ec9 100644 --- a/vendor/dlmalloc/src/linux.rs +++ b/vendor/dlmalloc/src/linux.rs @@ -1,51 +1,77 @@ extern crate libc; use core::ptr; +use Allocator; -pub unsafe fn alloc(size: usize) -> (*mut u8, usize, u32) { - let addr = libc::mmap( - 0 as *mut _, - size, - libc::PROT_WRITE | libc::PROT_READ, - libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, - -1, - 0, - ); - if addr == libc::MAP_FAILED { - (ptr::null_mut(), 0, 0) - } else { - (addr as *mut u8, size, 0) - } +/// System setting for Linux +pub struct System { + _priv: (), } -pub unsafe fn remap(ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 { - let flags = if can_move { libc::MREMAP_MAYMOVE } else { 0 }; - let ptr = libc::mremap(ptr as *mut _, oldsize, newsize, flags); - if ptr == libc::MAP_FAILED { - ptr::null_mut() - } else { - ptr as *mut u8 +impl System { + pub const fn new() -> System { + System { _priv: () } } } -pub unsafe fn free_part(ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { - let rc = libc::mremap(ptr as *mut _, oldsize, newsize, 0); - if rc != libc::MAP_FAILED { - return true; +#[cfg(feature = "global")] +static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + +unsafe impl Allocator for System { + fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { + let addr = unsafe { + libc::mmap( + 0 as *mut _, + size, + libc::PROT_WRITE | libc::PROT_READ, + libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, + -1, + 0, + ) + }; + if addr == libc::MAP_FAILED { + (ptr::null_mut(), 0, 0) + } else { + (addr as *mut u8, size, 0) + } } - libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 -} -pub unsafe fn free(ptr: *mut u8, size: usize) -> bool { - libc::munmap(ptr as *mut _, size) == 0 -} + fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 { + let flags = if can_move { libc::MREMAP_MAYMOVE } else { 0 }; + let ptr = unsafe { libc::mremap(ptr as *mut _, oldsize, newsize, flags) }; + if ptr == libc::MAP_FAILED { + ptr::null_mut() + } else { + ptr as *mut u8 + } + } -pub fn can_release_part(_flags: u32) -> bool { - true -} + fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { + unsafe { + let rc = libc::mremap(ptr as *mut _, oldsize, newsize, 0); + if rc != libc::MAP_FAILED { + return true; + } + libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 + } + } -#[cfg(feature = "global")] -static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + fn free(&self, ptr: *mut u8, size: usize) -> bool { + unsafe { libc::munmap(ptr as *mut _, size) == 0 } + } + + fn can_release_part(&self, _flags: u32) -> bool { + true + } + + fn allocates_zeros(&self) -> bool { + true + } + + fn page_size(&self) -> usize { + 4096 + } +} #[cfg(feature = "global")] pub fn acquire_global_lock() { @@ -56,11 +82,3 @@ pub fn acquire_global_lock() { pub fn release_global_lock() { unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) } } - -pub fn allocates_zeros() -> bool { - true -} - -pub fn page_size() -> usize { - 4096 -} diff --git a/vendor/dlmalloc/src/macos.rs b/vendor/dlmalloc/src/macos.rs index 5a94813404..d131271899 100644 --- a/vendor/dlmalloc/src/macos.rs +++ b/vendor/dlmalloc/src/macos.rs @@ -1,41 +1,65 @@ extern crate libc; use core::ptr; +use Allocator; -pub unsafe fn alloc(size: usize) -> (*mut u8, usize, u32) { - let addr = libc::mmap( - 0 as *mut _, - size, - libc::PROT_WRITE | libc::PROT_READ, - libc::MAP_ANON | libc::MAP_PRIVATE, - -1, - 0, - ); - if addr == libc::MAP_FAILED { - (ptr::null_mut(), 0, 0) - } else { - (addr as *mut u8, size, 0) - } +/// System setting for MacOS +pub struct System { + _priv: (), } -pub unsafe fn remap(_ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { - ptr::null_mut() +impl System { + pub const fn new() -> System { + System { _priv: () } + } } -pub unsafe fn free_part(ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { - libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 -} +#[cfg(feature = "global")] +static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; -pub unsafe fn free(ptr: *mut u8, size: usize) -> bool { - libc::munmap(ptr as *mut _, size) == 0 -} +unsafe impl Allocator for System { + fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { + let addr = unsafe { + libc::mmap( + 0 as *mut _, + size, + libc::PROT_WRITE | libc::PROT_READ, + libc::MAP_ANON | libc::MAP_PRIVATE, + -1, + 0, + ) + }; + if addr == libc::MAP_FAILED { + (ptr::null_mut(), 0, 0) + } else { + (addr as *mut u8, size, 0) + } + } -pub fn can_release_part(_flags: u32) -> bool { - true -} + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + ptr::null_mut() + } -#[cfg(feature = "global")] -static mut LOCK: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool { + unsafe { libc::munmap(ptr.offset(newsize as isize) as *mut _, oldsize - newsize) == 0 } + } + + fn free(&self, ptr: *mut u8, size: usize) -> bool { + unsafe { libc::munmap(ptr as *mut _, size) == 0 } + } + + fn can_release_part(&self, _flags: u32) -> bool { + true + } + + fn allocates_zeros(&self) -> bool { + true + } + + fn page_size(&self) -> usize { + 4096 + } +} #[cfg(feature = "global")] pub fn acquire_global_lock() { @@ -46,11 +70,3 @@ pub fn acquire_global_lock() { pub fn release_global_lock() { unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) } } - -pub fn allocates_zeros() -> bool { - true -} - -pub fn page_size() -> usize { - 4096 -} diff --git a/vendor/dlmalloc/src/sgx.rs b/vendor/dlmalloc/src/sgx.rs deleted file mode 100644 index 722bf03eb0..0000000000 --- a/vendor/dlmalloc/src/sgx.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::ptr; -use core::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT}; - -// Do not remove inline: will result in relocation failure -#[inline(always)] -unsafe fn rel_ptr_mut(offset: u64) -> *mut T { - (image_base() + offset) as *mut T -} - -// Do not remove inline: will result in relocation failure -// For the same reason we use inline ASM here instead of an extern static to -// locate the base -#[inline(always)] -fn image_base() -> u64 { - let base; - unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) }; - base -} - -pub unsafe fn alloc(_size: usize) -> (*mut u8, usize, u32) { - extern "C" { - static HEAP_BASE: u64; - static HEAP_SIZE: usize; - } - static INIT: AtomicBool = ATOMIC_BOOL_INIT; - // No ordering requirement since this function is protected by the global lock. - if !INIT.swap(true, Ordering::Relaxed) { - (rel_ptr_mut(HEAP_BASE), HEAP_SIZE, 0) - } else { - (ptr::null_mut(), 0, 0) - } -} - -pub unsafe fn remap(_ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { - ptr::null_mut() -} - -pub unsafe fn free_part(_ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { - false -} - -pub unsafe fn free(_ptr: *mut u8, _size: usize) -> bool { - false -} - -pub fn can_release_part(_flags: u32) -> bool { - false -} - -#[cfg(feature = "global")] -pub fn acquire_global_lock() { - compile_error!("The `global` feature is not implemented for the SGX platform") -} - -#[cfg(feature = "global")] -pub fn release_global_lock() { - compile_error!("The `global` feature is not implemented for the SGX platform") -} - -pub fn allocates_zeros() -> bool { - false -} - -pub fn page_size() -> usize { - 0x1000 -} diff --git a/vendor/dlmalloc/src/wasm.rs b/vendor/dlmalloc/src/wasm.rs index f63e8fa560..381fb025fe 100644 --- a/vendor/dlmalloc/src/wasm.rs +++ b/vendor/dlmalloc/src/wasm.rs @@ -1,30 +1,56 @@ use core::arch::wasm32; use core::ptr; +use Allocator; -pub unsafe fn alloc(size: usize) -> (*mut u8, usize, u32) { - let pages = size / page_size(); - let prev = wasm32::memory_grow(0, pages); - if prev == usize::max_value() { - return (ptr::null_mut(), 0, 0); - } - ((prev * page_size()) as *mut u8, pages * page_size(), 0) +/// System setting for Wasm +pub struct System { + _priv: (), } -pub unsafe fn remap(_ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { - // TODO: I think this can be implemented near the end? - ptr::null_mut() +impl System { + pub const fn new() -> System { + System { _priv: () } + } } -pub unsafe fn free_part(_ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { - false -} +unsafe impl Allocator for System { + fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { + let pages = size / self.page_size(); + let prev = wasm32::memory_grow(0, pages); + if prev == usize::max_value() { + return (ptr::null_mut(), 0, 0); + } + ( + (prev * self.page_size()) as *mut u8, + pages * self.page_size(), + 0, + ) + } -pub unsafe fn free(_ptr: *mut u8, _size: usize) -> bool { - false -} + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + // TODO: I think this can be implemented near the end? + ptr::null_mut() + } + + fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { + false + } + + fn free(&self, _ptr: *mut u8, _size: usize) -> bool { + false + } -pub fn can_release_part(_flags: u32) -> bool { - false + fn can_release_part(&self, _flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + true + } + + fn page_size(&self) -> usize { + 64 * 1024 + } } #[cfg(feature = "global")] @@ -36,11 +62,3 @@ pub fn acquire_global_lock() { pub fn release_global_lock() { // single threaded, no need! } - -pub fn allocates_zeros() -> bool { - true -} - -pub fn page_size() -> usize { - 64 * 1024 -} diff --git a/vendor/dlmalloc/tests/global.rs b/vendor/dlmalloc/tests/global.rs index c803ccc935..1e9bc66eca 100644 --- a/vendor/dlmalloc/tests/global.rs +++ b/vendor/dlmalloc/tests/global.rs @@ -1,12 +1,10 @@ -#![cfg(all(feature = "allocator-api", feature = "global"))] -#![feature(global_allocator)] - extern crate dlmalloc; use std::collections::HashMap; use std::thread; #[global_allocator] +#[cfg(feature = "global")] static A: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc; #[test] diff --git a/vendor/gimli/.cargo-checksum.json b/vendor/gimli/.cargo-checksum.json index 3cb2f4ed49..db1c199d39 100644 --- a/vendor/gimli/.cargo-checksum.json +++ b/vendor/gimli/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"48fe3a7c4c49387dae6e711be8f852eb22622882c9bd1cd923eb29c0a17c6446","CONTRIBUTING.md":"5f513ec06013e4f6f097e9c9492da5a47b9f25c94c6ecadfb655a77405fe912c","Cargo.lock":"fb84201d5d47fddf0c336c92e7ae372eee9c840c8a7f919ba5d53b1b3bae312c","Cargo.toml":"684c1f26fed0991eaa0e3864a046ae047e72e043d63accd345db7f3934157e7e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"f54273cb3a56511f07491c9813a39891fb613e6f775838fbcdce942dbdeedd8f","benches/bench.rs":"83438649d0ce7971a5d8dfba46e1cef059eee6ac6e8c01aff76eef2487d4e50d","examples/dwarf-validate.rs":"9e330340bd0869ba8f4188de5c109dff99dc7d3ed951777ab495f69af58c4b62","examples/dwarfdump.rs":"a499c8fb6463c34ec6a3232a1a50d7ff76e27da71002adc4ea4e3a09843cd79c","examples/simple.rs":"e87e041cdf56ae185b52dc4fa810b65bbc675ec8af0121f472b1fc351c58d321","examples/simple_line.rs":"e10200e3443342933d6df5c6ed3d3f7ac2c630e5d5f3e61d3d84b72df82b374d","fixtures/self/README.md":"557cd710240a14fdaa5842b216de57f2ed481151b640af09d6877984b3b2389f","fixtures/self/debug_abbrev":"7c0faa940d9c68d196d03ad55a20e5c746040fa428ff323277fa381deff82bba","fixtures/self/debug_aranges":"8c2aeb2335f61d04ecb7b747070d24f83a6517cbee79dc5c96d97fb6c53d6b6d","fixtures/self/debug_info":"42028a5983006e0703f9ca9515cd27d891ae4af70279fae5011d547f581e2661","fixtures/self/debug_inlined":"89d9516f06ff835621936037f5884fc56712bf304c1dcde52251ddd510fe8710","fixtures/self/debug_line":"b29aebcca3b38bb2bb8aa708cbe74a0dce5a3b0c18916b63d6d17282c017bec7","fixtures/self/debug_loc":"8906ccb9c204f233eb74c1d069dee97a19d18c2051f9147795d7b5364a9266aa","fixtures/self/debug_pubnames":"cf58e237f89c68afba724597fa7e260448636b45f2e69dc6f1bfe34006e27c48","fixtures/self/debug_pubtypes":"d43c1bed71c9d14d1683294cdc1833f069cf131d6e95ee808547919b4f352d81","fixtures/self/debug_ranges":"6d765ac18d33accd89186d077eeb505cbdf97d990c9201d63d9463cd7787ce7a","fixtures/self/debug_str":"9ed904b68eee77b8558b80b3b7ca03e8527f6c64483e9d6d845f40270eb21183","fixtures/self/eh_frame":"6dc3d84351cac42cf73d03452fbb532470dd94d08715154c48417e3f62095f17","fixtures/self/eh_frame_hdr":"afba7a0aa233c9a8c81c986495bd2505164844adb93272d6bc0c9e592e684716","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/arch.rs":"ea968df96573f7e1d5b9f8e496f665645f8a82ee5607495ecdd1aa44ec7bebc6","src/common.rs":"222e76ada0015e126d79e56a4e470ac5e3b2ae740a2b984746b95721d3445eba","src/constants.rs":"c61fac31b48cf19173a80447b0ce30f9ad07c308dd2f42402733e47db5feeffa","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"9d9e288ff591cf7863b8a595896faeaad8457068781c3091ac6c5dc2f41da692","src/lib.rs":"3b15540871587557d957ce5073d19f3866d37a874fe504779ac8592c888b95c4","src/read/abbrev.rs":"798fb791c130bed5b00a6160a5975feee0f66df627448ea7c822a40f137f7a9f","src/read/addr.rs":"f63f289edf889e87107bb2090fb1c50b48af7015f31b7c39c3d6ea09630a38e9","src/read/aranges.rs":"0ba7d541a3ca3d38d00a2c440b9b4bbfc26bfeeca6599deda13f0478583dc404","src/read/cfi.rs":"bb1497d41a1f17e8369cedc4093aa6351c280fbbae7fc1d8baba6dd9f8d51fa9","src/read/dwarf.rs":"1cbbb42c78e8ef3ce752bafbf7e30ef301f9d2ffc89c52a9170d97a0b2bef2c5","src/read/endian_reader.rs":"3a7fe3b3ae078678a6b13b4b24c3e6b3998cfff135039f1a8219b1003b946841","src/read/endian_slice.rs":"d07d4850d4199ba3a60eba1366dc26565bda804532270f3f5d1e5c2374ce42c5","src/read/line.rs":"848d5db6a8baec6fa227e9c00b1779cd96e9371cb4b3e5e8d935ab05a9eed0b6","src/read/loclists.rs":"39485c3a595afdd093c32a8a05b359a0ccb70e30fc3893e2f75c6b0ef6c4d92b","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"729f0dfed465e467fdf8982a018e725ac734986f130a6a7c03dabe18ce835dc2","src/read/op.rs":"270865aace2324a365dab68c78a624ae46118cac56b1ce009d77c9f7aa8373df","src/read/pubnames.rs":"701c1279aef596ed8eff13f19a5803f9e1070afa20c9bafbf29659d4c294edd4","src/read/pubtypes.rs":"6250112d63120ed283698cb42189b127f624fb453abb1222dfa75fe103ad077e","src/read/reader.rs":"ce3861c10bbd36bb0a38110dccc9e4a9248e3e9c48b27eea3e0e000e85d25770","src/read/rnglists.rs":"9b62814c18ee63dc163860f2a3f121f259cca61f62697885b607be59e0d2e065","src/read/str.rs":"dcdf5cd9260f0c9cf32aff5a03185f510f513661855d49980276ee0d6876802e","src/read/unit.rs":"a2cfc11658117edb92a39fb2aca82a084c35ffac61c946b30e87560797da5f99","src/read/value.rs":"380b1125f10880fe337a92d26016e0790705d7980e52c790ad1695cb7e92090d","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"5d36c6978d2bda09921f5b71b764a75a58e819551471fb44db23ce5db7c4a8e3","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"821fa9ac0c3afb27609034156f576301217b5c661c3e03eee09734b50ffc66a0","src/write/loc.rs":"d1c8a9068816e09c8a8e0673e4906806e88706f5712892c5990b5c10c09ed84e","src/write/mod.rs":"91aeddaae6557ffc4676d123b22c466832e939f8dd0aefb038b0193417d8c0af","src/write/op.rs":"14ec8145ec6fb0131504af53caeb1b6d2d929edd6baa4718ee7b8dd211533291","src/write/range.rs":"7e4174a8cbf9b3ac2724b0b07ad5e010838b98a848d5f839f4bc8e207c773c4a","src/write/section.rs":"3ce781d5e82ba365ff54fdd36e0ef58c58a2215b09a8861eb0b038efac82b77f","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"db2177fa1f771d797b1beb9e0a076076b81acaed91b523825f91b357aa4384ea","src/write/writer.rs":"aa6ebe7f2e695c5345558c73e71e3532ab0b3244fc18684bcd18de44e9ee3570","tests/convert_self.rs":"8fba3599ac892a704cbcd5aed53eaef51b040043da04f85f002c597ee7549046","tests/parse_self.rs":"a7d5b09c0cfb4891de96bc7db38aec14275b4d9b29c9df85b05d267b8d7030d4"},"package":"aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"} \ No newline at end of file +{"files":{"CHANGELOG.md":"a54c50975663c6252b7c125eda19235152070a37f998326f4b271a04f5d3e0f0","CONTRIBUTING.md":"5f513ec06013e4f6f097e9c9492da5a47b9f25c94c6ecadfb655a77405fe912c","Cargo.lock":"cd30e6fca722fc373af7141632e46c3b08ee6d7ab71fab90f762a922de34325f","Cargo.toml":"0a6d80adea2979e14326fd8aab0f36c06857e7d9449bda3f930e9432ddbcda65","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"a01f5693cdea3efedda9972688f5d1ed60e69f64d89a330d88a2aabb7556734f","benches/bench.rs":"83438649d0ce7971a5d8dfba46e1cef059eee6ac6e8c01aff76eef2487d4e50d","examples/dwarf-validate.rs":"8a322dc48a04bff33a759030f399ca9972ddb103e63851cbb9b8c9672095f645","examples/dwarfdump.rs":"3eb6de0979d427ae2cebad38bead8ba27b1dcc178f14f7373347c694bc6bf07c","examples/simple.rs":"cdf882d94aa561887308900ae305f4373bbd5222d846cd55ae96bcda9c139ecc","examples/simple_line.rs":"3bd3c16ed39b8156516d0660761e98b38b0a5d8295246a997aa47e278cf2bf6b","fixtures/self/README.md":"557cd710240a14fdaa5842b216de57f2ed481151b640af09d6877984b3b2389f","fixtures/self/debug_abbrev":"7c0faa940d9c68d196d03ad55a20e5c746040fa428ff323277fa381deff82bba","fixtures/self/debug_aranges":"8c2aeb2335f61d04ecb7b747070d24f83a6517cbee79dc5c96d97fb6c53d6b6d","fixtures/self/debug_info":"42028a5983006e0703f9ca9515cd27d891ae4af70279fae5011d547f581e2661","fixtures/self/debug_inlined":"89d9516f06ff835621936037f5884fc56712bf304c1dcde52251ddd510fe8710","fixtures/self/debug_line":"b29aebcca3b38bb2bb8aa708cbe74a0dce5a3b0c18916b63d6d17282c017bec7","fixtures/self/debug_loc":"8906ccb9c204f233eb74c1d069dee97a19d18c2051f9147795d7b5364a9266aa","fixtures/self/debug_pubnames":"cf58e237f89c68afba724597fa7e260448636b45f2e69dc6f1bfe34006e27c48","fixtures/self/debug_pubtypes":"d43c1bed71c9d14d1683294cdc1833f069cf131d6e95ee808547919b4f352d81","fixtures/self/debug_ranges":"6d765ac18d33accd89186d077eeb505cbdf97d990c9201d63d9463cd7787ce7a","fixtures/self/debug_str":"9ed904b68eee77b8558b80b3b7ca03e8527f6c64483e9d6d845f40270eb21183","fixtures/self/eh_frame":"6dc3d84351cac42cf73d03452fbb532470dd94d08715154c48417e3f62095f17","fixtures/self/eh_frame_hdr":"afba7a0aa233c9a8c81c986495bd2505164844adb93272d6bc0c9e592e684716","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/arch.rs":"8dc707e84d049fea7e0f9689a7346bf5e687536ba1171206411dbabdfb1bdd3a","src/common.rs":"c51b746a4a511726fd98bf30a9383dc42e9810942edd3b725355301897b4c3f0","src/constants.rs":"c61fac31b48cf19173a80447b0ce30f9ad07c308dd2f42402733e47db5feeffa","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"9d9e288ff591cf7863b8a595896faeaad8457068781c3091ac6c5dc2f41da692","src/lib.rs":"3b15540871587557d957ce5073d19f3866d37a874fe504779ac8592c888b95c4","src/read/abbrev.rs":"798fb791c130bed5b00a6160a5975feee0f66df627448ea7c822a40f137f7a9f","src/read/addr.rs":"f63f289edf889e87107bb2090fb1c50b48af7015f31b7c39c3d6ea09630a38e9","src/read/aranges.rs":"0ba7d541a3ca3d38d00a2c440b9b4bbfc26bfeeca6599deda13f0478583dc404","src/read/cfi.rs":"bb1497d41a1f17e8369cedc4093aa6351c280fbbae7fc1d8baba6dd9f8d51fa9","src/read/dwarf.rs":"e052498cfa0f4aff7a5dafda0e8d91350980b49e345e5c2bbd1567f8f1b39690","src/read/endian_reader.rs":"3a7fe3b3ae078678a6b13b4b24c3e6b3998cfff135039f1a8219b1003b946841","src/read/endian_slice.rs":"d07d4850d4199ba3a60eba1366dc26565bda804532270f3f5d1e5c2374ce42c5","src/read/line.rs":"848d5db6a8baec6fa227e9c00b1779cd96e9371cb4b3e5e8d935ab05a9eed0b6","src/read/lists.rs":"e473ff419feed9756289e245b7879bd89e7f19098a53162fe6773fac496ae5bc","src/read/loclists.rs":"2a5655c53fb2bf5cfe2df373210217edaa06e4d3addf27df0f724100cbfbe43b","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"49138ebd9a01121e13e341b8b18f255b7b7106a3cf4d3ee46aa58452f1004163","src/read/op.rs":"270865aace2324a365dab68c78a624ae46118cac56b1ce009d77c9f7aa8373df","src/read/pubnames.rs":"701c1279aef596ed8eff13f19a5803f9e1070afa20c9bafbf29659d4c294edd4","src/read/pubtypes.rs":"6250112d63120ed283698cb42189b127f624fb453abb1222dfa75fe103ad077e","src/read/reader.rs":"ce3861c10bbd36bb0a38110dccc9e4a9248e3e9c48b27eea3e0e000e85d25770","src/read/rnglists.rs":"054ca7bc75752955a4edc2b5e27781af94ce7791ac273d10a349ca980502f5ba","src/read/str.rs":"7857d4a5fe71ced4984c8e9a0f6e64c21c23e9836703b1b52d5cc674a83b3dfb","src/read/unit.rs":"6477343ec5278df2c7a5dac2da47a5574387bc16d34db02e3ab294d559446175","src/read/value.rs":"2c48e827d5c128d8824b64acea2e50eae5a1176760b9a6144e3fb0373b575505","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"5d36c6978d2bda09921f5b71b764a75a58e819551471fb44db23ce5db7c4a8e3","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"821fa9ac0c3afb27609034156f576301217b5c661c3e03eee09734b50ffc66a0","src/write/loc.rs":"fbe8eb33af5a3ef2d5681b561fe0f93fd5a2385c9ced9746c52a0693bffcd44b","src/write/mod.rs":"d8aa1da854cdee629d470d00d87e00dc6998e4bec1ca951f8d2f277730ab9d69","src/write/op.rs":"4229e471f223bbd705fe047498002f853495bb64cedc4c651a0542062433f635","src/write/range.rs":"9852cd73a05be409b69b9e5e2fcd0f64e585da5feeb2a6bd91a76d6b82a8ad18","src/write/section.rs":"3ce781d5e82ba365ff54fdd36e0ef58c58a2215b09a8861eb0b038efac82b77f","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"fecc7165b64d60856e289dce118d580eb2c2b61b13199083b811b462dcd01d03","src/write/writer.rs":"aa6ebe7f2e695c5345558c73e71e3532ab0b3244fc18684bcd18de44e9ee3570","tests/convert_self.rs":"8fba3599ac892a704cbcd5aed53eaef51b040043da04f85f002c597ee7549046","tests/parse_self.rs":"a7d5b09c0cfb4891de96bc7db38aec14275b4d9b29c9df85b05d267b8d7030d4"},"package":"f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"} \ No newline at end of file diff --git a/vendor/gimli/CHANGELOG.md b/vendor/gimli/CHANGELOG.md index 5bba42f3af..e9609c4763 100644 --- a/vendor/gimli/CHANGELOG.md +++ b/vendor/gimli/CHANGELOG.md @@ -2,6 +2,42 @@ -------------------------------------------------------------------------------- +## 0.23.0 + +Released 2020/10/27. + +### Breaking changes + +* Added more variants to `read::UnitType`. + Added `read::AttributeValue::DwoId` + [#521](https://github.com/gimli-rs/gimli/pull/521) + +* Replaced `CompilationUnitHeader` and `TypeUnitHeader` with `UnitHeader`. + Replaced `CompilationUnitHeadersIter` with `DebugInfoUnitHeadersIter`. + Replaced `TypeUnitHeadersIter` with `DebugTypesUnitHeadersIter`. + [#523](https://github.com/gimli-rs/gimli/pull/523) + + +### Added + +* Added read support for split DWARF. + [#527](https://github.com/gimli-rs/gimli/pull/527) + [#529](https://github.com/gimli-rs/gimli/pull/529) + +* Added `read::Dwarf::attr_address`. + [#524](https://github.com/gimli-rs/gimli/pull/524) + +* Added read support for `DW_AT_GNU_addr_base` and `DW_AT_GNU_ranges_base`. + [#525](https://github.com/gimli-rs/gimli/pull/525) + +* dwarfdump: Display index values for attributes. + [#526](https://github.com/gimli-rs/gimli/pull/526) + +* Added `name_to_register`. + [#532](https://github.com/gimli-rs/gimli/pull/532) + +-------------------------------------------------------------------------------- + ## 0.22.0 Released 2020/07/03. diff --git a/vendor/gimli/Cargo.lock b/vendor/gimli/Cargo.lock index 15d890f852..465a2439d6 100644 --- a/vendor/gimli/Cargo.lock +++ b/vendor/gimli/Cargo.lock @@ -1,405 +1,403 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "adler32" -version = "1.0.4" +name = "adler" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" [[package]] name = "aho-corasick" -version = "0.7.6" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b476ce7103678b0c6d3d395dbbae31d48ff910bd28be979ba5d48c6351131d0d" dependencies = [ - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "autocfg" -version = "0.1.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "byteorder" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd0782e0a7da7598164153173e5a5d4d9b1da094473c98dce0ff91406112369" + +[[package]] +name = "const_fn" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2" [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "crossbeam" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd01a6eb3daaafa260f6fc94c3a6c36390abc2080e38e3e34ced87393fb77d80" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", ] [[package]] name = "crossbeam-channel" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ - "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "const_fn", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2a58563f049aa3bae172bc4120f093b5901161c629f280a1f40ba55317d774" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "cfg-if 1.0.0", + "const_fn", + "lazy_static", ] [[package]] name = "either" -version = "1.5.3" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "fallible-iterator" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "flate2" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da80be589a72651dcda34d8b35bcdc9b7254ad06325611074d9cc0fbb19f60ee" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "crc32fast", + "libc", + "miniz_oxide", ] [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "gimli" -version = "0.22.0" +version = "0.23.0" dependencies = [ - "compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "object 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-alloc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "test-assembler 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "typed-arena 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins", + "crossbeam", + "fallible-iterator", + "getopts", + "indexmap", + "memmap", + "num_cpus", + "object", + "rayon", + "regex", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "stable_deref_trait", + "test-assembler", + "typed-arena", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + [[package]] name = "hermit-abi" -version = "0.1.6" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "indexmap" -version = "1.3.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "hashbrown", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.66" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "memchr" -version = "2.3.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi", ] [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "miniz_oxide" -version = "0.3.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ - "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "adler", + "autocfg", ] [[package]] name = "num_cpus" -version = "1.11.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] name = "object" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ - "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.57.0 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2", + "wasmparser", ] [[package]] name = "rayon" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" dependencies = [ - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", ] [[package]] name = "rayon-core" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", ] [[package]] name = "regex" -version = "1.3.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b" dependencies = [ - "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.13" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c" [[package]] name = "rustc-std-workspace-alloc" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" [[package]] name = "rustc-std-workspace-core" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" [[package]] name = "scopeguard" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "stable_deref_trait" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "test-assembler" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ccc488d8ed3a4a31f68372ba429642245ddbdf6642054334b7fcc06264cbde9" dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "thread_local" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] name = "typed-arena" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "wasmparser" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" -"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" -"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" -"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" -"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" -"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" -"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" -"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -"checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" -"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" -"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" -"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" -"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" -"checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" -"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" -"checksum object 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" -"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" -"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" -"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" -"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" -"checksum rustc-std-workspace-alloc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" -"checksum rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum test-assembler 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5ccc488d8ed3a4a31f68372ba429642245ddbdf6642054334b7fcc06264cbde9" -"checksum thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88ddf1ad580c7e3d1efff877d972bcc93f995556b9087a5a259630985c88ceab" -"checksum typed-arena 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum wasmparser 0.57.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/gimli/Cargo.toml b/vendor/gimli/Cargo.toml index 1f08916f56..5d82cf6695 100644 --- a/vendor/gimli/Cargo.toml +++ b/vendor/gimli/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "gimli" -version = "0.22.0" +version = "0.23.0" authors = ["Nick Fitzgerald ", "Philip Craig "] exclude = ["/ci/*", "/releases/*", "/.travis.yml"] description = "A library for reading and writing the DWARF debugging format." @@ -70,7 +70,7 @@ version = "1.1.0" optional = true default-features = false [dev-dependencies.crossbeam] -version = "0.7.1" +version = "0.8" [dev-dependencies.getopts] version = "0.2" @@ -82,7 +82,7 @@ version = "0.7" version = "1" [dev-dependencies.object] -version = "0.20" +version = "0.22" [dev-dependencies.rayon] version = "1.0" diff --git a/vendor/gimli/README.md b/vendor/gimli/README.md index 9e7edb4f49..b4595f9463 100644 --- a/vendor/gimli/README.md +++ b/vendor/gimli/README.md @@ -30,7 +30,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -gimli = "0.22.0" +gimli = "0.23.0" ``` The minimum supported Rust version is 1.38.0. diff --git a/vendor/gimli/examples/dwarf-validate.rs b/vendor/gimli/examples/dwarf-validate.rs index 3770521984..1eabccc118 100644 --- a/vendor/gimli/examples/dwarf-validate.rs +++ b/vendor/gimli/examples/dwarf-validate.rs @@ -1,7 +1,7 @@ // Allow clippy lints when building without clippy. #![allow(unknown_lints)] -use gimli::{AttributeValue, CompilationUnitHeader}; +use gimli::{AttributeValue, UnitHeader}; use object::{Object, ObjectSection}; use rayon::prelude::*; use std::borrow::{Borrow, Cow}; @@ -155,13 +155,14 @@ fn validate_info( Ok(None) => break, Ok(Some(u)) => u, }; - last_offset = u.offset().0 + u.length_including_self(); + last_offset = u.offset().as_debug_info_offset().unwrap().0 + u.length_including_self(); units.push(u); } - let process_unit = |unit: CompilationUnitHeader| -> UnitSummary { + let process_unit = |unit: UnitHeader| -> UnitSummary { + let unit_offset = unit.offset().as_debug_info_offset().unwrap(); let mut ret = UnitSummary { internally_valid: false, - offset: unit.offset(), + offset: unit_offset, die_offsets: Vec::new(), global_die_references: Vec::new(), }; @@ -170,8 +171,7 @@ fn validate_info( Err(err) => { w.error(format!( "Invalid abbrevs for unit {:#x}: {}", - unit.offset().0, - &err + unit_offset.0, &err )); return ret; } @@ -183,8 +183,7 @@ fn validate_info( Err(err) => { w.error(format!( "Invalid DIE for unit {:#x}: {}", - unit.offset().0, - &err + unit_offset.0, &err )); return ret; } @@ -199,7 +198,7 @@ fn validate_info( Err(err) => { w.error(format!( "Invalid attribute for unit {:#x} at DIE {:#x}: {}", - unit.offset().0, + unit_offset.0, entry.offset().0, &err )); @@ -228,9 +227,7 @@ fn validate_info( if ret.die_offsets.binary_search(&to).is_err() { w.error(format!( "Invalid intra-unit reference in unit {:#x} from DIE {:#x} to {:#x}", - unit.offset().0, - from.0, - to.0 + unit_offset.0, from.0, to.0 )); } } diff --git a/vendor/gimli/examples/dwarfdump.rs b/vendor/gimli/examples/dwarfdump.rs index 8f1ff72c1f..0875c0cb50 100644 --- a/vendor/gimli/examples/dwarfdump.rs +++ b/vendor/gimli/examples/dwarfdump.rs @@ -2,8 +2,8 @@ #![allow(unknown_lints)] use fallible_iterator::FallibleIterator; -use gimli::{CompilationUnitHeader, Section, UnitOffset, UnitSectionOffset, UnwindSection}; -use object::{Object, ObjectSection}; +use gimli::{Section, UnitHeader, UnitOffset, UnitSectionOffset, UnitType, UnwindSection}; +use object::{Object, ObjectSection, ObjectSymbol}; use regex::bytes::Regex; use std::borrow::{Borrow, Cow}; use std::cmp::min; @@ -550,7 +550,10 @@ where reader: Default::default(), }; - let dwarf = gimli::Dwarf::load(&mut load_section, |_| Ok(no_reader.clone())).unwrap(); + let mut dwarf = gimli::Dwarf::load(&mut load_section, |_| Ok(no_reader.clone())).unwrap(); + if flags.dwo { + dwarf.file_type = gimli::DwarfFileType::Dwo; + } let out = io::stdout(); if flags.eh_frame { @@ -920,13 +923,34 @@ where return Ok(()); } }; - let process_unit = |header: CompilationUnitHeader, buf: &mut Vec| -> Result<()> { + let process_unit = |header: UnitHeader, buf: &mut Vec| -> Result<()> { writeln!( buf, "\nUNIT
:", - header.offset().0, + header.offset().as_debug_info_offset().unwrap().0, )?; + match header.type_() { + UnitType::Compilation | UnitType::Partial => (), + UnitType::Type { + type_signature, + type_offset, + } + | UnitType::SplitType { + type_signature, + type_offset, + } => { + write!(buf, " signature = ")?; + dump_type_signature(buf, type_signature)?; + writeln!(buf)?; + writeln!(buf, " typeoffset = 0x{:08x}", type_offset.0,)?; + } + UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => { + write!(buf, " dwo_id = ")?; + writeln!(buf, "0x{:016x}", dwo_id.0)?; + } + } + let unit = match dwarf.unit(header) { Ok(unit) => unit, Err(err) => { @@ -966,14 +990,21 @@ fn dump_types( writeln!( w, "\nUNIT
:", - header.offset().0, + header.offset().as_debug_types_offset().unwrap().0, )?; write!(w, " signature = ")?; - dump_type_signature(w, header.type_signature())?; + let (type_signature, type_offset) = match header.type_() { + UnitType::Type { + type_signature, + type_offset, + } => (type_signature, type_offset), + _ => unreachable!(), // No other units allowed in .debug_types. + }; + dump_type_signature(w, type_signature)?; writeln!(w)?; - writeln!(w, " typeoffset = 0x{:08x}", header.type_offset().0,)?; + writeln!(w, " typeoffset = 0x{:08x}", type_offset.0,)?; - let unit = match dwarf.type_unit(header) { + let unit = match dwarf.unit(header) { Ok(unit) => unit, Err(err) => { writeln_error(w, dwarf, err.into(), "Failed to parse type unit root entry")?; @@ -1156,6 +1187,7 @@ fn dump_attr_value( writeln!(w, "<.debug_addr+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugAddrIndex(index) => { + write!(w, "(indirect address, index {:#x}): ", index.0)?; let address = dwarf.address(unit, index)?; writeln!(w, "0x{:08x}", address)?; } @@ -1187,6 +1219,7 @@ fn dump_attr_value( writeln!(w, "<.debug_loclists+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugLocListsIndex(index) => { + write!(w, "(indirect location list, index {:#x}): ", index.0)?; let offset = dwarf.locations_offset(unit, index)?; dump_loc_list(w, offset, unit, dwarf)?; } @@ -1203,6 +1236,7 @@ fn dump_attr_value( writeln!(w, "<.debug_rnglists+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugRngListsIndex(index) => { + write!(w, "(indirect range list, index {:#x}): ", index.0)?; let offset = dwarf.ranges_offset(unit, index)?; dump_range_list(w, offset, unit, dwarf)?; } @@ -1224,6 +1258,7 @@ fn dump_attr_value( writeln!(w, "<.debug_str_offsets+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugStrOffsetsIndex(index) => { + write!(w, "(indirect string, index {:#x}): ", index.0)?; let offset = dwarf.debug_str_offsets.get_str_offset( unit.encoding().format, unit.str_offsets_base, @@ -1286,6 +1321,9 @@ fn dump_attr_value( dump_file_index(w, value, unit, dwarf)?; writeln!(w)?; } + gimli::AttributeValue::DwoId(value) => { + writeln!(w, "0x{:016x}", value.0)?; + } } Ok(()) @@ -1790,7 +1828,7 @@ fn dump_line(w: &mut W, dwarf: &gimli::Dwarf) -> Result< writeln!( w, "\n.debug_line: line number info for unit at .debug_info offset 0x{:08x}", - header.offset().0 + header.offset().as_debug_info_offset().unwrap().0 )?; let unit = match dwarf.unit(header) { Ok(unit) => unit, diff --git a/vendor/gimli/examples/simple.rs b/vendor/gimli/examples/simple.rs index 9f5a68adf4..a45a4b9205 100644 --- a/vendor/gimli/examples/simple.rs +++ b/vendor/gimli/examples/simple.rs @@ -46,7 +46,10 @@ fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), // Iterate over the compilation units. let mut iter = dwarf.units(); while let Some(header) = iter.next()? { - println!("Unit at <.debug_info+0x{:x}>", header.offset().0); + println!( + "Unit at <.debug_info+0x{:x}>", + header.offset().as_debug_info_offset().unwrap().0 + ); let unit = dwarf.unit(header)?; // Iterate over the Debugging Information Entries (DIEs) in the unit. diff --git a/vendor/gimli/examples/simple_line.rs b/vendor/gimli/examples/simple_line.rs index efb7b92368..cecdf30b24 100644 --- a/vendor/gimli/examples/simple_line.rs +++ b/vendor/gimli/examples/simple_line.rs @@ -48,7 +48,7 @@ fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), while let Some(header) = iter.next()? { println!( "Line number info for unit at <.debug_info+0x{:x}>", - header.offset().0 + header.offset().as_debug_info_offset().unwrap().0 ); let unit = dwarf.unit(header)?; diff --git a/vendor/gimli/src/arch.rs b/vendor/gimli/src/arch.rs index 6256a60679..d30c3fc480 100644 --- a/vendor/gimli/src/arch.rs +++ b/vendor/gimli/src/arch.rs @@ -19,6 +19,16 @@ macro_rules! registers { _ => return None, } } + + /// Converts a register name into a register number. + pub fn name_to_register(value: &str) -> Option { + match value { + $( + $disp => Some(Self::$name), + )+ + _ => return None, + } + } } }; } diff --git a/vendor/gimli/src/common.rs b/vendor/gimli/src/common.rs index e612869aa7..7cd4b5e3f1 100644 --- a/vendor/gimli/src/common.rs +++ b/vendor/gimli/src/common.rs @@ -196,6 +196,38 @@ pub enum UnitSectionOffset { DebugTypesOffset(DebugTypesOffset), } +impl From> for UnitSectionOffset { + fn from(offset: DebugInfoOffset) -> Self { + UnitSectionOffset::DebugInfoOffset(offset) + } +} + +impl From> for UnitSectionOffset { + fn from(offset: DebugTypesOffset) -> Self { + UnitSectionOffset::DebugTypesOffset(offset) + } +} + +impl UnitSectionOffset +where + T: Clone, +{ + /// Returns the `DebugInfoOffset` inside, or `None` otherwise. + pub fn as_debug_info_offset(&self) -> Option> { + match self { + UnitSectionOffset::DebugInfoOffset(offset) => Some(offset.clone()), + UnitSectionOffset::DebugTypesOffset(_) => None, + } + } + /// Returns the `DebugTypesOffset` inside, or `None` otherwise. + pub fn as_debug_types_offset(&self) -> Option> { + match self { + UnitSectionOffset::DebugInfoOffset(_) => None, + UnitSectionOffset::DebugTypesOffset(offset) => Some(offset.clone()), + } + } +} + /// An identifier for a DWARF section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum SectionId { @@ -274,11 +306,37 @@ impl SectionId { SectionId::DebugAbbrev => ".debug_abbrev.dwo", SectionId::DebugInfo => ".debug_info.dwo", SectionId::DebugLine => ".debug_line.dwo", + // The debug_loc section can be present in the dwo when using the + // GNU split-dwarf extension to DWARF4. + SectionId::DebugLoc => ".debug_loc.dwo", SectionId::DebugLocLists => ".debug_loclists.dwo", SectionId::DebugMacro => ".debug_macro.dwo", + SectionId::DebugRngLists => ".debug_rnglists.dwo", SectionId::DebugStr => ".debug_str.dwo", SectionId::DebugStrOffsets => ".debug_str_offsets.dwo", _ => return None, }) } } + +/// An optionally-provided implementation-defined compilation unit ID to enable +/// split DWARF and linking a split compilation unit back together. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DwoId(pub u64); + +/// The "type" of file with DWARF debugging information. This determines, among other things, +/// which files DWARF sections should be loaded from. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DwarfFileType { + /// A normal executable or object file. + Main, + /// A .dwo split DWARF file. + Dwo, + // TODO: Supplementary files, .dwps? +} + +impl Default for DwarfFileType { + fn default() -> Self { + DwarfFileType::Main + } +} diff --git a/vendor/gimli/src/read/dwarf.rs b/vendor/gimli/src/read/dwarf.rs index eeb1a747c8..10636c2315 100644 --- a/vendor/gimli/src/read/dwarf.rs +++ b/vendor/gimli/src/read/dwarf.rs @@ -3,17 +3,16 @@ use alloc::string::String; use crate::common::{ DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, - DebugStrOffsetsIndex, DebugTypesOffset, Encoding, LocationListsOffset, RangeListsOffset, - SectionId, UnitSectionOffset, + DebugStrOffsetsIndex, DebugTypesOffset, DwarfFileType, Encoding, LocationListsOffset, + RangeListsOffset, SectionId, UnitSectionOffset, }; use crate::constants; use crate::read::{ - Abbreviations, AttributeValue, CompilationUnitHeader, CompilationUnitHeadersIter, DebugAbbrev, - DebugAddr, DebugInfo, DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, + Abbreviations, AttributeValue, DebugAbbrev, DebugAddr, DebugInfo, DebugInfoUnitHeadersIter, + DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, Error, IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, Reader, ReaderOffset, - ReaderOffsetId, Result, RngListIter, Section, TypeUnitHeader, TypeUnitHeadersIter, UnitHeader, - UnitOffset, + ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitOffset, }; /// All of the commonly used DWARF sections, and other common information. @@ -51,6 +50,9 @@ pub struct Dwarf { /// The range lists in the `.debug_ranges` and `.debug_rnglists` sections. pub ranges: RangeLists, + + /// The type of this file. + pub file_type: DwarfFileType, } impl Dwarf { @@ -85,6 +87,7 @@ impl Dwarf { debug_types: Section::load(&mut section)?, locations: LocationLists::new(debug_loc, debug_loclists), ranges: RangeLists::new(debug_ranges, debug_rnglists), + file_type: DwarfFileType::Main, }) } @@ -130,24 +133,24 @@ impl Dwarf { debug_types: self.debug_types.borrow(&mut borrow), locations: self.locations.borrow(&mut borrow), ranges: self.ranges.borrow(&mut borrow), + file_type: self.file_type, } } } impl Dwarf { - /// Iterate the compilation- and partial-unit headers in the - /// `.debug_info` section. + /// Iterate the unit headers in the `.debug_info` section. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[inline] - pub fn units(&self) -> CompilationUnitHeadersIter { + pub fn units(&self) -> DebugInfoUnitHeadersIter { self.debug_info.units() } - /// Construct a new `Unit` from the given compilation unit header. + /// Construct a new `Unit` from the given unit header. #[inline] - pub fn unit(&self, header: CompilationUnitHeader) -> Result> { + pub fn unit(&self, header: UnitHeader) -> Result> { Unit::new(self, header) } @@ -156,27 +159,14 @@ impl Dwarf { /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[inline] - pub fn type_units(&self) -> TypeUnitHeadersIter { + pub fn type_units(&self) -> DebugTypesUnitHeadersIter { self.debug_types.units() } - /// Construct a new `Unit` from the given type unit header. - #[inline] - pub fn type_unit(&self, header: TypeUnitHeader) -> Result> { - Unit::new_type_unit(self, header) - } - /// Parse the abbreviations for a compilation unit. // TODO: provide caching of abbreviations #[inline] - pub fn abbreviations(&self, unit: &CompilationUnitHeader) -> Result { - unit.abbreviations(&self.debug_abbrev) - } - - /// Parse the abbreviations for a type unit. - // TODO: provide caching of abbreviations - #[inline] - pub fn type_abbreviations(&self, unit: &TypeUnitHeader) -> Result { + pub fn abbreviations(&self, unit: &UnitHeader) -> Result { unit.abbreviations(&self.debug_abbrev) } @@ -241,6 +231,23 @@ impl Dwarf { .get_address(unit.encoding().address_size, unit.addr_base, index) } + /// Try to return an attribute value as an address. + /// + /// If the attribute value is one of: + /// + /// - a `DW_FORM_addr` + /// - a `DW_FORM_addrx` index into the `.debug_addr` entries for the unit + /// + /// then return the address. + /// Returns `None` for other forms. + pub fn attr_address(&self, unit: &Unit, attr: AttributeValue) -> Result> { + match attr { + AttributeValue::Addr(addr) => Ok(Some(addr)), + AttributeValue::DebugAddrIndex(index) => self.address(unit, index).map(Some), + _ => Ok(None), + } + } + /// Return the range list offset at the given index. pub fn ranges_offset( &self, @@ -374,13 +381,22 @@ impl Dwarf { unit: &Unit, offset: LocationListsOffset, ) -> Result> { - self.locations.locations( - offset, - unit.encoding(), - unit.low_pc, - &self.debug_addr, - unit.addr_base, - ) + match self.file_type { + DwarfFileType::Main => self.locations.locations( + offset, + unit.encoding(), + unit.low_pc, + &self.debug_addr, + unit.addr_base, + ), + DwarfFileType::Dwo => self.locations.locations_dwo( + offset, + unit.encoding(), + unit.low_pc, + &self.debug_addr, + unit.addr_base, + ), + } } /// Try to return an attribute value as a location list offset. @@ -480,9 +496,6 @@ where R: Reader, Offset: ReaderOffset, { - /// The section offset of the unit. - pub offset: UnitSectionOffset, - /// The header of the unit. pub header: UnitHeader, @@ -515,45 +528,31 @@ where } impl Unit { - /// Construct a new `Unit` from the given compilation unit header. + /// Construct a new `Unit` from the given unit header. #[inline] - pub fn new(dwarf: &Dwarf, header: CompilationUnitHeader) -> Result { - Self::new_internal( - dwarf, - UnitSectionOffset::DebugInfoOffset(header.offset()), - header.header(), - ) - } - - /// Construct a new `Unit` from the given type unit header. - #[inline] - pub fn new_type_unit(dwarf: &Dwarf, header: TypeUnitHeader) -> Result { - Self::new_internal( - dwarf, - UnitSectionOffset::DebugTypesOffset(header.offset()), - header.header(), - ) - } - - fn new_internal( - dwarf: &Dwarf, - offset: UnitSectionOffset, - header: UnitHeader, - ) -> Result { + pub fn new(dwarf: &Dwarf, header: UnitHeader) -> Result { let abbreviations = header.abbreviations(&dwarf.debug_abbrev)?; let mut unit = Unit { - offset, - header, abbreviations, name: None, comp_dir: None, low_pc: 0, - // Defaults to 0 for GNU extensions. - str_offsets_base: DebugStrOffsetsBase(R::Offset::from_u8(0)), + str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file( + header.encoding(), + dwarf.file_type, + ), + // NB: Because the .debug_addr section never lives in a .dwo, we can assume its base is always 0 or provided. addr_base: DebugAddrBase(R::Offset::from_u8(0)), - loclists_base: DebugLocListsBase(R::Offset::from_u8(0)), - rnglists_base: DebugRngListsBase(R::Offset::from_u8(0)), + loclists_base: DebugLocListsBase::default_for_encoding_and_file( + header.encoding(), + dwarf.file_type, + ), + rnglists_base: DebugRngListsBase::default_for_encoding_and_file( + header.encoding(), + dwarf.file_type, + ), line_program: None, + header, }; let mut name = None; let mut comp_dir = None; @@ -587,7 +586,7 @@ impl Unit { unit.str_offsets_base = base; } } - constants::DW_AT_addr_base => { + constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => { if let AttributeValue::DebugAddrBase(base) = attr.value() { unit.addr_base = base; } @@ -597,7 +596,7 @@ impl Unit { unit.loclists_base = base; } } - constants::DW_AT_rnglists_base => { + constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => { if let AttributeValue::DebugRngListsBase(base) = attr.value() { unit.rnglists_base = base; } @@ -663,6 +662,17 @@ impl Unit { pub fn entries_raw(&self, offset: Option>) -> Result> { self.header.entries_raw(&self.abbreviations, offset) } + + /// Copy attributes that are subject to relocation from another unit. This is intended + /// to be used to copy attributes from a skeleton compilation unit to the corresponding + /// split compilation unit. + pub fn copy_relocated_attributes(&mut self, other: &Unit) { + self.low_pc = other.low_pc; + self.addr_base = other.addr_base; + if self.header.version() < 5 { + self.rnglists_base = other.rnglists_base; + } + } } impl UnitSectionOffset { @@ -673,7 +683,7 @@ impl UnitSectionOffset { where R: Reader, { - let (offset, unit_offset) = match (self, unit.offset) { + let (offset, unit_offset) = match (self, unit.header.offset()) { ( UnitSectionOffset::DebugInfoOffset(offset), UnitSectionOffset::DebugInfoOffset(unit_offset), @@ -704,12 +714,12 @@ impl UnitOffset { where R: Reader, { - match unit.offset { + match unit.header.offset() { UnitSectionOffset::DebugInfoOffset(unit_offset) => { - UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(unit_offset.0 + self.0)) + DebugInfoOffset(unit_offset.0 + self.0).into() } UnitSectionOffset::DebugTypesOffset(unit_offset) => { - UnitSectionOffset::DebugTypesOffset(DebugTypesOffset(unit_offset.0 + self.0)) + DebugTypesOffset(unit_offset.0 + self.0).into() } } } diff --git a/vendor/gimli/src/read/lists.rs b/vendor/gimli/src/read/lists.rs new file mode 100644 index 0000000000..b63c5c126a --- /dev/null +++ b/vendor/gimli/src/read/lists.rs @@ -0,0 +1,67 @@ +use crate::common::{Encoding, Format}; +use crate::read::{Error, Reader, Result}; + +#[derive(Debug, Clone, Copy)] +pub(crate) struct ListsHeader { + encoding: Encoding, + offset_entry_count: u32, +} + +impl Default for ListsHeader { + fn default() -> Self { + ListsHeader { + encoding: Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 0, + }, + offset_entry_count: 0, + } + } +} + +impl ListsHeader { + /// Return the serialized size of the table header. + #[allow(dead_code)] + #[inline] + fn size(self) -> u8 { + // initial_length + version + address_size + segment_selector_size + offset_entry_count + ListsHeader::size_for_encoding(self.encoding) + } + + /// Return the serialized size of the table header. + #[inline] + pub(crate) fn size_for_encoding(encoding: Encoding) -> u8 { + // initial_length + version + address_size + segment_selector_size + offset_entry_count + encoding.format.initial_length_size() + 2 + 1 + 1 + 4 + } +} + +// TODO: add an iterator over headers in the appropriate sections section +#[allow(dead_code)] +fn parse_header(input: &mut R) -> Result { + let (length, format) = input.read_initial_length()?; + input.truncate(length)?; + + let version = input.read_u16()?; + if version != 5 { + return Err(Error::UnknownVersion(u64::from(version))); + } + + let address_size = input.read_u8()?; + let segment_selector_size = input.read_u8()?; + if segment_selector_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } + let offset_entry_count = input.read_u32()?; + + let encoding = Encoding { + format, + version, + address_size, + }; + Ok(ListsHeader { + encoding, + offset_entry_count, + }) +} diff --git a/vendor/gimli/src/read/loclists.rs b/vendor/gimli/src/read/loclists.rs index 7dc30567a4..3c4da127d1 100644 --- a/vendor/gimli/src/read/loclists.rs +++ b/vendor/gimli/src/read/loclists.rs @@ -1,12 +1,12 @@ use crate::common::{ - DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, Encoding, Format, + DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, DwarfFileType, Encoding, LocationListsOffset, SectionId, }; use crate::constants; use crate::endianity::Endianity; use crate::read::{ - DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader, ReaderOffset, - ReaderOffsetId, Result, Section, + lists::ListsHeader, DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader, + ReaderOffset, ReaderOffsetId, Result, Section, }; /// The raw contents of the `.debug_loc` section. @@ -100,64 +100,29 @@ impl From for DebugLocLists { } } -#[derive(Debug, Clone, Copy)] -struct LocListsHeader { - encoding: Encoding, - offset_entry_count: u32, -} +pub(crate) type LocListsHeader = ListsHeader; -impl Default for LocListsHeader { - fn default() -> Self { - LocListsHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 0, - }, - offset_entry_count: 0, +impl DebugLocListsBase +where + Offset: ReaderOffset, +{ + /// Returns a `DebugLocListsBase` with the default value of DW_AT_loclists_base + /// for the given `Encoding` and `DwarfFileType`. + pub fn default_for_encoding_and_file( + encoding: Encoding, + file_type: DwarfFileType, + ) -> DebugLocListsBase { + if encoding.version >= 5 && file_type == DwarfFileType::Dwo { + // In .dwo files, the compiler omits the DW_AT_loclists_base attribute (because there is + // only a single unit in the file) but we must skip past the header, which the attribute + // would normally do for us. + DebugLocListsBase(Offset::from_u8(LocListsHeader::size_for_encoding(encoding))) + } else { + DebugLocListsBase(Offset::from_u8(0)) } } } -impl LocListsHeader { - /// Return the serialized size of the table header. - #[allow(dead_code)] - #[inline] - fn size(self) -> u8 { - // initial_length + version + address_size + segment_selector_size + offset_entry_count - self.encoding.format.initial_length_size() + 2 + 1 + 1 + 4 - } -} - -// TODO: add an iterator over headers in the .debug_loclists section -#[allow(dead_code)] -fn parse_header(input: &mut R) -> Result { - let (length, format) = input.read_initial_length()?; - input.truncate(length)?; - - let version = input.read_u16()?; - if version != 5 { - return Err(Error::UnknownVersion(u64::from(version))); - } - - let address_size = input.read_u8()?; - let segment_selector_size = input.read_u8()?; - if segment_selector_size != 0 { - return Err(Error::UnsupportedSegmentSize); - } - let offset_entry_count = input.read_u32()?; - - let encoding = Encoding { - format, - version, - address_size, - }; - Ok(LocListsHeader { - encoding, - offset_entry_count, - }) -} - /// The DWARF data found in `.debug_loc` and `.debug_loclists` sections. #[derive(Debug, Default, Clone, Copy)] pub struct LocationLists { @@ -231,6 +196,25 @@ impl LocationLists { )) } + /// Similar to `locations`, but with special handling for .dwo files. + /// This should only been used when this `LocationLists` was loaded from a + /// .dwo file. + pub fn locations_dwo( + &self, + offset: LocationListsOffset, + unit_encoding: Encoding, + base_address: u64, + debug_addr: &DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> Result> { + Ok(LocListIter::new( + self.raw_locations_dwo(offset, unit_encoding)?, + base_address, + debug_addr.clone(), + debug_addr_base, + )) + } + /// Iterate over the raw `LocationListEntry`s starting at the given offset. /// /// The `unit_encoding` must match the compilation unit that the @@ -245,14 +229,38 @@ impl LocationLists { &self, offset: LocationListsOffset, unit_encoding: Encoding, + ) -> Result> { + let (mut input, format) = if unit_encoding.version <= 4 { + (self.debug_loc.section.clone(), LocListsFormat::Bare) + } else { + (self.debug_loclists.section.clone(), LocListsFormat::LLE) + }; + input.skip(offset.0)?; + Ok(RawLocListIter::new(input, unit_encoding, format)) + } + + /// Similar to `raw_locations`, but with special handling for .dwo files. + /// This should only been used when this `LocationLists` was loaded from a + /// .dwo file. + pub fn raw_locations_dwo( + &self, + offset: LocationListsOffset, + unit_encoding: Encoding, ) -> Result> { let mut input = if unit_encoding.version <= 4 { + // In the GNU split dwarf extension the locations are present in the + // .debug_loc section but are encoded with the DW_LLE values used + // for the DWARF 5 .debug_loclists section. self.debug_loc.section.clone() } else { self.debug_loclists.section.clone() }; input.skip(offset.0)?; - Ok(RawLocListIter::new(input, unit_encoding)) + Ok(RawLocListIter::new( + input, + unit_encoding, + LocListsFormat::LLE, + )) } /// Returns the `.debug_loclists` offset at the given `base` and `index`. @@ -286,6 +294,15 @@ impl LocationLists { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum LocListsFormat { + /// The bare location list format used before DWARF 5. + Bare, + /// The DW_LLE encoded range list format used in DWARF 5 and the non-standard GNU + /// split dwarf extension. + LLE, +} + /// A raw iterator over a location list. /// /// This iterator does not perform any processing of the location entries, @@ -294,6 +311,7 @@ impl LocationLists { pub struct RawLocListIter { input: R, encoding: Encoding, + format: LocListsFormat, } /// A raw entry in .debug_loclists. @@ -370,77 +388,94 @@ pub enum RawLocListEntry { }, } -fn parse_data(input: &mut R) -> Result> { - let len = R::Offset::from_u64(input.read_uleb128()?)?; - Ok(Expression(input.split(len)?)) +fn parse_data(input: &mut R, encoding: Encoding) -> Result> { + if encoding.version >= 5 { + let len = R::Offset::from_u64(input.read_uleb128()?)?; + Ok(Expression(input.split(len)?)) + } else { + // In the GNU split-dwarf extension this is a fixed 2 byte value. + let len = R::Offset::from_u16(input.read_u16()?); + Ok(Expression(input.split(len)?)) + } } impl RawLocListEntry { /// Parse a location list entry from `.debug_loclists` - fn parse(input: &mut R, encoding: Encoding) -> Result> { - if encoding.version < 5 { - let range = RawRange::parse(input, encoding.address_size)?; - return Ok(if range.is_end() { - None - } else if range.is_base_address(encoding.address_size) { - Some(RawLocListEntry::BaseAddress { addr: range.end }) - } else { - let len = R::Offset::from_u16(input.read_u16()?); - let data = Expression(input.split(len)?); - Some(RawLocListEntry::AddressOrOffsetPair { - begin: range.begin, - end: range.end, - data, - }) - }); - } - Ok(match constants::DwLle(input.read_u8()?) { - constants::DW_LLE_end_of_list => None, - constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx { - addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - }), - constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - data: parse_data(input)?, - }), - constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - length: input.read_uleb128()?, - data: parse_data(input)?, - }), - constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair { - begin: input.read_uleb128()?, - end: input.read_uleb128()?, - data: parse_data(input)?, - }), - constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation { - data: parse_data(input)?, - }), - constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress { - addr: input.read_address(encoding.address_size)?, - }), - constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd { - begin: input.read_address(encoding.address_size)?, - end: input.read_address(encoding.address_size)?, - data: parse_data(input)?, - }), - constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength { - begin: input.read_address(encoding.address_size)?, - length: input.read_uleb128()?, - data: parse_data(input)?, - }), - _ => { - return Err(Error::InvalidAddressRange); + fn parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result> { + match format { + LocListsFormat::Bare => { + let range = RawRange::parse(input, encoding.address_size)?; + return Ok(if range.is_end() { + None + } else if range.is_base_address(encoding.address_size) { + Some(RawLocListEntry::BaseAddress { addr: range.end }) + } else { + let len = R::Offset::from_u16(input.read_u16()?); + let data = Expression(input.split(len)?); + Some(RawLocListEntry::AddressOrOffsetPair { + begin: range.begin, + end: range.end, + data, + }) + }); } - }) + LocListsFormat::LLE => Ok(match constants::DwLle(input.read_u8()?) { + constants::DW_LLE_end_of_list => None, + constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx { + addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + }), + constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + length: if encoding.version >= 5 { + input.read_uleb128()? + } else { + // In the GNU split-dwarf extension this is a fixed 4 byte value. + input.read_u32()? as u64 + }, + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair { + begin: input.read_uleb128()?, + end: input.read_uleb128()?, + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation { + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress { + addr: input.read_address(encoding.address_size)?, + }), + constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd { + begin: input.read_address(encoding.address_size)?, + end: input.read_address(encoding.address_size)?, + data: parse_data(input, encoding)?, + }), + constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength { + begin: input.read_address(encoding.address_size)?, + length: input.read_uleb128()?, + data: parse_data(input, encoding)?, + }), + _ => { + return Err(Error::InvalidAddressRange); + } + }), + } } } impl RawLocListIter { /// Construct a `RawLocListIter`. - pub fn new(input: R, encoding: Encoding) -> RawLocListIter { - RawLocListIter { input, encoding } + fn new(input: R, encoding: Encoding, format: LocListsFormat) -> RawLocListIter { + RawLocListIter { + input, + encoding, + format, + } } /// Advance the iterator to the next location. @@ -449,7 +484,7 @@ impl RawLocListIter { return Ok(None); } - match RawLocListEntry::parse(&mut self.input, self.encoding) { + match RawLocListEntry::parse(&mut self.input, self.encoding, self.format) { Ok(entry) => { if entry.is_none() { self.input.empty(); @@ -600,6 +635,7 @@ pub struct LocationListEntry { #[cfg(test)] mod tests { use super::*; + use crate::common::Format; use crate::endianity::LittleEndian; use crate::read::{EndianSlice, Range}; use crate::test_util::GimliSectionMethods; @@ -1426,4 +1462,53 @@ mod tests { ); } } + + #[test] + fn test_loclists_gnu_v4_split_dwarf() { + #[rustfmt::skip] + let buf = [ + 0x03, // DW_LLE_startx_length + 0x00, // ULEB encoded b7 + 0x08, 0x00, 0x00, 0x00, // Fixed 4 byte length of 8 + 0x03, 0x00, // Fixed two byte length of the location + 0x11, 0x00, // DW_OP_constu 0 + 0x9f, // DW_OP_stack_value + // Padding data + //0x99, 0x99, 0x99, 0x99 + ]; + let data_buf = [0x11, 0x00, 0x9f]; + let expected_data = EndianSlice::new(&data_buf, LittleEndian); + let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + let loclists = LocationLists::new(debug_loc, debug_loclists); + let debug_addr = + &DebugAddr::from(EndianSlice::new(&[0x01, 0x02, 0x03, 0x04], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + + // An invalid location range. + let mut locations = loclists + .locations_dwo( + LocationListsOffset(0x0), + encoding, + 0, + debug_addr, + debug_addr_base, + ) + .unwrap(); + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0403_0201, + end: 0x0403_0209 + }, + data: Expression(expected_data), + })) + ); + } } diff --git a/vendor/gimli/src/read/mod.rs b/vendor/gimli/src/read/mod.rs index 3d36090c70..c5da32552d 100644 --- a/vendor/gimli/src/read/mod.rs +++ b/vendor/gimli/src/read/mod.rs @@ -199,6 +199,8 @@ pub use self::aranges::*; mod line; pub use self::line::*; +mod lists; + mod loclists; pub use self::loclists::*; diff --git a/vendor/gimli/src/read/rnglists.rs b/vendor/gimli/src/read/rnglists.rs index 9d4b7f4cab..7f9b1961d9 100644 --- a/vendor/gimli/src/read/rnglists.rs +++ b/vendor/gimli/src/read/rnglists.rs @@ -1,11 +1,12 @@ use crate::common::{ - DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, Encoding, Format, + DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, DwarfFileType, Encoding, RangeListsOffset, SectionId, }; use crate::constants; use crate::endianity::Endianity; use crate::read::{ - DebugAddr, EndianSlice, Error, Reader, ReaderOffset, ReaderOffsetId, Result, Section, + lists::ListsHeader, DebugAddr, EndianSlice, Error, Reader, ReaderOffset, ReaderOffsetId, + Result, Section, }; /// The raw contents of the `.debug_ranges` section. @@ -100,64 +101,30 @@ impl From for DebugRngLists { } } -#[derive(Debug, Clone, Copy)] -struct RngListsHeader { - encoding: Encoding, - offset_entry_count: u32, -} +#[allow(unused)] +pub(crate) type RngListsHeader = ListsHeader; -impl Default for RngListsHeader { - fn default() -> Self { - RngListsHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 0, - }, - offset_entry_count: 0, +impl DebugRngListsBase +where + Offset: ReaderOffset, +{ + /// Returns a `DebugRngListsBase` with the default value of DW_AT_rnglists_base + /// for the given `Encoding` and `DwarfFileType`. + pub fn default_for_encoding_and_file( + encoding: Encoding, + file_type: DwarfFileType, + ) -> DebugRngListsBase { + if encoding.version >= 5 && file_type == DwarfFileType::Dwo { + // In .dwo files, the compiler omits the DW_AT_rnglists_base attribute (because there is + // only a single unit in the file) but we must skip past the header, which the attribute + // would normally do for us. + DebugRngListsBase(Offset::from_u8(RngListsHeader::size_for_encoding(encoding))) + } else { + DebugRngListsBase(Offset::from_u8(0)) } } } -impl RngListsHeader { - /// Return the serialized size of the table header. - #[allow(dead_code)] - #[inline] - fn size(self) -> u8 { - // initial_length + version + address_size + segment_selector_size + offset_entry_count - self.encoding.format.initial_length_size() + 2 + 1 + 1 + 4 - } -} - -// TODO: add an iterator over headers in the .debug_rnglists section -#[allow(dead_code)] -fn parse_header(input: &mut R) -> Result { - let (length, format) = input.read_initial_length()?; - input.truncate(length)?; - - let version = input.read_u16()?; - if version != 5 { - return Err(Error::UnknownVersion(u64::from(version))); - } - - let address_size = input.read_u8()?; - let segment_selector_size = input.read_u8()?; - if segment_selector_size != 0 { - return Err(Error::UnsupportedSegmentSize); - } - let offset_entry_count = input.read_u32()?; - - let encoding = Encoding { - format, - version, - address_size, - }; - Ok(RngListsHeader { - encoding, - offset_entry_count, - }) -} - /// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections. #[derive(Debug, Default, Clone, Copy)] pub struct RangeLists { @@ -245,13 +212,13 @@ impl RangeLists { offset: RangeListsOffset, unit_encoding: Encoding, ) -> Result> { - let mut input = if unit_encoding.version <= 4 { - self.debug_ranges.section.clone() + let (mut input, format) = if unit_encoding.version <= 4 { + (self.debug_ranges.section.clone(), RangeListsFormat::Bare) } else { - self.debug_rnglists.section.clone() + (self.debug_rnglists.section.clone(), RangeListsFormat::RLE) }; input.skip(offset.0)?; - Ok(RawRngListIter::new(input, unit_encoding)) + Ok(RawRngListIter::new(input, unit_encoding, format)) } /// Returns the `.debug_rnglists` offset at the given `base` and `index`. @@ -288,6 +255,14 @@ impl RangeLists { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum RangeListsFormat { + /// The bare range list format used before DWARF 5. + Bare, + /// The DW_RLE encoded range list format used in DWARF 5. + RLE, +} + /// A raw iterator over an address range list. /// /// This iterator does not perform any processing of the range entries, @@ -296,6 +271,7 @@ impl RangeLists { pub struct RawRngListIter { input: R, encoding: Encoding, + format: RangeListsFormat, } /// A raw entry in .debug_rnglists @@ -357,59 +333,69 @@ pub enum RawRngListEntry { impl RawRngListEntry { /// Parse a range entry from `.debug_rnglists` - fn parse>(input: &mut R, encoding: Encoding) -> Result> { - if encoding.version < 5 { - let range = RawRange::parse(input, encoding.address_size)?; - return Ok(if range.is_end() { - None - } else if range.is_base_address(encoding.address_size) { - Some(RawRngListEntry::BaseAddress { addr: range.end }) - } else { - Some(RawRngListEntry::AddressOrOffsetPair { - begin: range.begin, - end: range.end, - }) - }); - } - Ok(match constants::DwRle(input.read_u8()?) { - constants::DW_RLE_end_of_list => None, - constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx { - addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - }), - constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - }), - constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - length: input.read_uleb128()?, - }), - constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair { - begin: input.read_uleb128()?, - end: input.read_uleb128()?, - }), - constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress { - addr: input.read_address(encoding.address_size)?, - }), - constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd { - begin: input.read_address(encoding.address_size)?, - end: input.read_address(encoding.address_size)?, - }), - constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength { - begin: input.read_address(encoding.address_size)?, - length: input.read_uleb128()?, - }), - _ => { - return Err(Error::InvalidAddressRange); + fn parse>( + input: &mut R, + encoding: Encoding, + format: RangeListsFormat, + ) -> Result> { + match format { + RangeListsFormat::Bare => { + let range = RawRange::parse(input, encoding.address_size)?; + return Ok(if range.is_end() { + None + } else if range.is_base_address(encoding.address_size) { + Some(RawRngListEntry::BaseAddress { addr: range.end }) + } else { + Some(RawRngListEntry::AddressOrOffsetPair { + begin: range.begin, + end: range.end, + }) + }); } - }) + RangeListsFormat::RLE => Ok(match constants::DwRle(input.read_u8()?) { + constants::DW_RLE_end_of_list => None, + constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx { + addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + }), + constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + }), + constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength { + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + length: input.read_uleb128()?, + }), + constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair { + begin: input.read_uleb128()?, + end: input.read_uleb128()?, + }), + constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress { + addr: input.read_address(encoding.address_size)?, + }), + constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd { + begin: input.read_address(encoding.address_size)?, + end: input.read_address(encoding.address_size)?, + }), + constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength { + begin: input.read_address(encoding.address_size)?, + length: input.read_uleb128()?, + }), + _ => { + return Err(Error::InvalidAddressRange); + } + }), + } } } impl RawRngListIter { /// Construct a `RawRngListIter`. - fn new(input: R, encoding: Encoding) -> RawRngListIter { - RawRngListIter { input, encoding } + fn new(input: R, encoding: Encoding, format: RangeListsFormat) -> RawRngListIter { + RawRngListIter { + input, + encoding, + format, + } } /// Advance the iterator to the next range. @@ -418,7 +404,7 @@ impl RawRngListIter { return Ok(None); } - match RawRngListEntry::parse(&mut self.input, self.encoding) { + match RawRngListEntry::parse(&mut self.input, self.encoding, self.format) { Ok(range) => { if range.is_none() { self.input.empty(); @@ -600,6 +586,7 @@ impl Range { #[cfg(test)] mod tests { use super::*; + use crate::common::Format; use crate::endianity::LittleEndian; use crate::test_util::GimliSectionMethods; use test_assembler::{Endian, Label, LabelMaker, Section}; diff --git a/vendor/gimli/src/read/str.rs b/vendor/gimli/src/read/str.rs index d55ff1f288..a107df8265 100644 --- a/vendor/gimli/src/read/str.rs +++ b/vendor/gimli/src/read/str.rs @@ -1,5 +1,6 @@ use crate::common::{ - DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, SectionId, + DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType, + Encoding, SectionId, }; use crate::endianity::Endianity; use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section}; @@ -173,6 +174,30 @@ impl From for DebugStrOffsets { } } +impl DebugStrOffsetsBase +where + Offset: ReaderOffset, +{ + /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base + /// for the given `Encoding` and `DwarfFileType`. + pub fn default_for_encoding_and_file( + encoding: Encoding, + file_type: DwarfFileType, + ) -> DebugStrOffsetsBase { + if encoding.version >= 5 && file_type == DwarfFileType::Dwo { + // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is + // only a single unit in the file) but we must skip past the header, which the attribute + // would normally do for us. + // initial_length_size + version + 2 bytes of padding. + DebugStrOffsetsBase(Offset::from_u8( + encoding.format.initial_length_size() + 2 + 2, + )) + } else { + DebugStrOffsetsBase(Offset::from_u8(0)) + } + } +} + /// The `DebugLineStr` struct represents the DWARF strings /// found in the `.debug_line_str` section. #[derive(Debug, Default, Clone, Copy)] diff --git a/vendor/gimli/src/read/unit.rs b/vendor/gimli/src/read/unit.rs index 4a51f46ce7..ef8d5be45a 100644 --- a/vendor/gimli/src/read/unit.rs +++ b/vendor/gimli/src/read/unit.rs @@ -8,8 +8,8 @@ use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset, DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset, DebugMacroOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, - DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, Encoding, Format, - LocationListsOffset, RangeListsOffset, SectionId, + DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwoId, Encoding, Format, + LocationListsOffset, RangeListsOffset, SectionId, UnitSectionOffset, }; use crate::constants; use crate::endianity::Endianity; @@ -22,15 +22,13 @@ impl DebugTypesOffset { /// Convert an offset to be relative to the start of the given unit, /// instead of relative to the start of the .debug_types section. /// Returns `None` if the offset is not within the unit entries. - pub fn to_unit_offset(&self, unit: &TypeUnitHeader) -> Option> + pub fn to_unit_offset(&self, unit: &UnitHeader) -> Option> where R: Reader, { - let offset = match self.0.checked_sub(unit.offset.0) { - Some(offset) => UnitOffset(offset), - None => return None, - }; - if !unit.header.is_valid_offset(offset) { + let unit_offset = unit.offset().as_debug_types_offset()?; + let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?); + if !unit.is_valid_offset(offset) { return None; } Some(offset) @@ -41,15 +39,13 @@ impl DebugInfoOffset { /// Convert an offset to be relative to the start of the given unit, /// instead of relative to the start of the .debug_info section. /// Returns `None` if the offset is not within this unit entries. - pub fn to_unit_offset(&self, unit: &CompilationUnitHeader) -> Option> + pub fn to_unit_offset(&self, unit: &UnitHeader) -> Option> where R: Reader, { - let offset = match self.0.checked_sub(unit.offset.0) { - Some(offset) => UnitOffset(offset), - None => return None, - }; - if !unit.header.is_valid_offset(offset) { + let unit_offset = unit.offset().as_debug_info_offset()?; + let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?); + if !unit.is_valid_offset(offset) { return None; } Some(offset) @@ -62,21 +58,25 @@ pub struct UnitOffset(pub T); impl UnitOffset { /// Convert an offset to be relative to the start of the .debug_info section, - /// instead of relative to the start of the given compilation unit. - pub fn to_debug_info_offset(&self, unit: &CompilationUnitHeader) -> DebugInfoOffset + /// instead of relative to the start of the given unit. Returns None if the + /// provided unit lives in the .debug_types section. + pub fn to_debug_info_offset(&self, unit: &UnitHeader) -> Option> where R: Reader, { - DebugInfoOffset(unit.offset.0 + self.0) + let unit_offset = unit.offset().as_debug_info_offset()?; + Some(DebugInfoOffset(unit_offset.0 + self.0)) } /// Convert an offset to be relative to the start of the .debug_types section, - /// instead of relative to the start of the given type unit. - pub fn to_debug_types_offset(&self, unit: &TypeUnitHeader) -> DebugTypesOffset + /// instead of relative to the start of the given unit. Returns None if the + /// provided unit lives in the .debug_info section. + pub fn to_debug_types_offset(&self, unit: &UnitHeader) -> Option> where R: Reader, { - DebugTypesOffset(unit.offset.0 + self.0) + let unit_offset = unit.offset().as_debug_types_offset()?; + Some(DebugTypesOffset(unit_offset.0 + self.0)) } } @@ -111,8 +111,7 @@ where } impl DebugInfo { - /// Iterate the compilation- and partial-units in this - /// `.debug_info` section. + /// Iterate the units in this `.debug_info` section. /// /// ``` /// use gimli::{DebugInfo, LittleEndian}; @@ -129,23 +128,20 @@ impl DebugInfo { /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn units(&self) -> CompilationUnitHeadersIter { - CompilationUnitHeadersIter { + pub fn units(&self) -> DebugInfoUnitHeadersIter { + DebugInfoUnitHeadersIter { input: self.debug_info_section.clone(), offset: DebugInfoOffset(R::Offset::from_u8(0)), } } - /// Get the CompilationUnitHeader located at offset from this .debug_info section. + /// Get the UnitHeader located at offset from this .debug_info section. /// /// - pub fn header_from_offset( - &self, - offset: DebugInfoOffset, - ) -> Result> { + pub fn header_from_offset(&self, offset: DebugInfoOffset) -> Result> { let input = &mut self.debug_info_section.clone(); input.skip(offset.0)?; - CompilationUnitHeader::parse(input, offset) + parse_unit_header(input, offset.into()) } } @@ -189,24 +185,24 @@ impl From for DebugInfo { } } -/// An iterator over the compilation- and partial-units of a section. +/// An iterator over the units of a .debug_info section. /// /// See the [documentation on /// `DebugInfo::units`](./struct.DebugInfo.html#method.units) for more detail. #[derive(Clone, Debug)] -pub struct CompilationUnitHeadersIter { +pub struct DebugInfoUnitHeadersIter { input: R, offset: DebugInfoOffset, } -impl CompilationUnitHeadersIter { +impl DebugInfoUnitHeadersIter { /// Advance the iterator to the next unit header. - pub fn next(&mut self) -> Result>> { + pub fn next(&mut self) -> Result>> { if self.input.is_empty() { Ok(None) } else { let len = self.input.len(); - match CompilationUnitHeader::parse(&mut self.input, self.offset) { + match parse_unit_header(&mut self.input, self.offset.into()) { Ok(header) => { self.offset.0 += len - self.input.len(); Ok(Some(header)) @@ -221,235 +217,17 @@ impl CompilationUnitHeadersIter { } #[cfg(feature = "fallible-iterator")] -impl fallible_iterator::FallibleIterator for CompilationUnitHeadersIter { - type Item = CompilationUnitHeader; +impl fallible_iterator::FallibleIterator for DebugInfoUnitHeadersIter { + type Item = UnitHeader; type Error = Error; fn next(&mut self) -> ::core::result::Result, Self::Error> { - CompilationUnitHeadersIter::next(self) - } -} - -/// The header of a compilation unit's debugging information. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct CompilationUnitHeader::Offset> -where - R: Reader, - Offset: ReaderOffset, -{ - header: UnitHeader, - offset: DebugInfoOffset, -} - -impl CompilationUnitHeader -where - R: Reader, - Offset: ReaderOffset, -{ - /// Construct a new `CompilationUnitHeader`. - pub fn new(header: UnitHeader, offset: DebugInfoOffset) -> Self { - CompilationUnitHeader { header, offset } - } - - /// Return the `UnitHeader` containing common unit header fields. - pub fn header(self) -> UnitHeader { - self.header - } - - /// Return the serialized size of the compilation unit header for the given - /// DWARF encoding. - pub fn size_of_header(encoding: Encoding) -> usize { - UnitHeader::::size_of_header(encoding) - } - - /// Get the offset of this compilation unit within the .debug_info section. - pub fn offset(&self) -> DebugInfoOffset { - self.offset - } - - /// Get the length of the debugging info for this compilation unit, not - /// including the byte length of the encoded length itself. - pub fn unit_length(&self) -> R::Offset { - self.header.unit_length - } - - /// Get the length of the debugging info for this compilation unit, - /// including the byte length of the encoded length itself. - pub fn length_including_self(&self) -> R::Offset { - self.header.length_including_self() - } - - /// Return the encoding parameters for this unit. - pub fn encoding(&self) -> Encoding { - self.header.encoding - } - - /// Get the DWARF version of the debugging info for this compilation unit. - pub fn version(&self) -> u16 { - self.header.version() - } - - /// The offset into the `.debug_abbrev` section for this compilation unit's - /// debugging information entries' abbreviations. - pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { - self.header.debug_abbrev_offset - } - - /// The size of addresses (in bytes) in this type-unit. - pub fn address_size(&self) -> u8 { - self.header.address_size() - } - - /// Whether this type unit is encoded in 64- or 32-bit DWARF. - pub fn format(&self) -> Format { - self.header.format() - } - - /// The serialized size of the header for this compilation unit. - pub fn header_size(&self) -> R::Offset { - self.header.header_size() - } - - /// Read the `DebuggingInformationEntry` at the given offset. - pub fn entry<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: UnitOffset, - ) -> Result> { - self.header.entry(abbreviations, offset) - } - - /// Navigate this compilation unit's `DebuggingInformationEntry`s. - pub fn entries<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - ) -> EntriesCursor<'abbrev, 'me, R> { - self.header.entries(abbreviations) - } - - /// Navigate this compilation unit's `DebuggingInformationEntry`s - /// starting at the given offset. - pub fn entries_at_offset<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: UnitOffset, - ) -> Result> { - self.header.entries_at_offset(abbreviations, offset) - } - - /// Navigate this compilation unit's `DebuggingInformationEntry`s as a tree - /// starting at the given offset. - pub fn entries_tree<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: Option>, - ) -> Result> { - self.header.entries_tree(abbreviations, offset) - } - - /// Read the raw data that defines the Debugging Information Entries. - pub fn entries_raw<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: Option>, - ) -> Result> { - self.header.entries_raw(abbreviations, offset) - } - - /// Parse this compilation unit's abbreviations. - /// - /// ``` - /// use gimli::DebugAbbrev; - /// # use gimli::{DebugInfo, LittleEndian}; - /// # let info_buf = [ - /// # // Comilation unit header - /// # - /// # // 32-bit unit length = 25 - /// # 0x19, 0x00, 0x00, 0x00, - /// # // Version 4 - /// # 0x04, 0x00, - /// # // debug_abbrev_offset - /// # 0x00, 0x00, 0x00, 0x00, - /// # // Address size - /// # 0x04, - /// # - /// # // DIEs - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # ]; - /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); - /// # - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_yes - /// # 0x01, - /// # // Begin attributes - /// # // Attribute name = DW_AT_name - /// # 0x03, - /// # // Attribute form = DW_FORM_string - /// # 0x08, - /// # // End attributes - /// # 0x00, - /// # 0x00, - /// # // Null terminator - /// # 0x00 - /// # ]; - /// # - /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); - /// - /// let unit = get_some_unit(); - /// - /// # let read_debug_abbrev_section_somehow = || &abbrev_buf; - /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); - /// let abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); - /// ``` - pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev) -> Result { - self.header.abbreviations(debug_abbrev) - } - - /// Parse a compilation unit header. - fn parse( - input: &mut R, - offset: DebugInfoOffset, - ) -> Result> { - let header = parse_unit_header(input)?; - Ok(CompilationUnitHeader { header, offset }) + DebugInfoUnitHeadersIter::next(self) } } -/// Parse the unit type from the compilation unit header. -fn parse_compilation_unit_type(input: &mut R) -> Result { +/// Parse the unit type from the unit header. +fn parse_unit_type(input: &mut R) -> Result { let val = input.read_u8()?; Ok(constants::DwUt(val)) } @@ -470,6 +248,69 @@ pub(crate) fn parse_debug_info_offset( input.read_offset(format).map(DebugInfoOffset) } +/// This enum specifies the type of the unit and any type +/// specific data carried in the header (e.g. the type +/// signature/type offset of a type unit). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UnitType +where + Offset: ReaderOffset, +{ + /// In DWARF5, a unit with type `DW_UT_compile`. In previous DWARF versions, + /// any unit appearing in the .debug_info section. + Compilation, + /// In DWARF5, a unit with type `DW_UT_type`. In DWARF4, any unit appearing + /// in the .debug_types section. + Type { + /// The unique type signature for this type unit. + type_signature: DebugTypeSignature, + /// The offset within this type unit where the type is defined. + type_offset: UnitOffset, + }, + /// A unit with type `DW_UT_partial`. The root DIE of this unit should be a + /// `DW_TAG_partial_unit`. + Partial, + /// A unit with type `DW_UT_skeleton`. The enclosed dwo_id can be used to + /// link this with the corresponding `SplitCompilation` unit in a dwo file. + /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead + /// be a `Compilation` unit with the dwo_id present as an attribute on the + /// root DIE. + Skeleton(DwoId), + /// A unit with type `DW_UT_split_compile`. The enclosed dwo_id can be used to + /// link this with the corresponding `Skeleton` unit in the original binary. + /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead + /// be a `Compilation` unit with the dwo_id present as an attribute on the + /// root DIE. + SplitCompilation(DwoId), + /// A unit with type `DW_UT_split_type`. A split type unit is identical to a + /// conventional type unit except for the section in which it appears. + SplitType { + /// The unique type signature for this type unit. + type_signature: DebugTypeSignature, + /// The offset within this type unit where the type is defined. + type_offset: UnitOffset, + }, +} + +impl UnitType +where + Offset: ReaderOffset, +{ + // TODO: This will be used by the DWARF writing code once it + // supports unit types other than simple compilation units. + #[allow(unused)] + pub(crate) fn dw_ut(&self) -> constants::DwUt { + match self { + UnitType::Compilation => constants::DW_UT_compile, + UnitType::Type { .. } => constants::DW_UT_type, + UnitType::Partial => constants::DW_UT_partial, + UnitType::Skeleton(_) => constants::DW_UT_skeleton, + UnitType::SplitCompilation(_) => constants::DW_UT_split_compile, + UnitType::SplitType { .. } => constants::DW_UT_split_type, + } + } +} + /// The common fields for the headers of compilation units and /// type units. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -480,7 +321,9 @@ where { encoding: Encoding, unit_length: Offset, + unit_type: UnitType, debug_abbrev_offset: DebugAbbrevOffset, + unit_offset: UnitSectionOffset, entries_buf: R, } @@ -493,51 +336,70 @@ where /// Construct a new `UnitHeader`. pub fn new( encoding: Encoding, - unit_length: R::Offset, - debug_abbrev_offset: DebugAbbrevOffset, + unit_length: Offset, + unit_type: UnitType, + debug_abbrev_offset: DebugAbbrevOffset, + unit_offset: UnitSectionOffset, entries_buf: R, ) -> Self { UnitHeader { encoding, unit_length, + unit_type, debug_abbrev_offset, + unit_offset, entries_buf, } } +} + +/// Instance methods. +impl UnitHeader +where + R: Reader, + Offset: ReaderOffset, +{ + /// Get the offset of this unit within its section. + pub fn offset(&self) -> UnitSectionOffset { + self.unit_offset + } /// Return the serialized size of the common unit header for the given /// DWARF format. - pub fn size_of_header(encoding: Encoding) -> usize { - let unit_length_size = encoding.format.initial_length_size() as usize; + pub fn size_of_header(&self) -> usize { + let unit_length_size = self.encoding.format.initial_length_size() as usize; let version_size = 2; - let debug_abbrev_offset_size = encoding.format.word_size() as usize; + let debug_abbrev_offset_size = self.encoding.format.word_size() as usize; let address_size_size = 1; - let unit_type_size = if encoding.version == 5 { 1 } else { 0 }; + let unit_type_size = if self.encoding.version == 5 { 1 } else { 0 }; + let type_specific_size = match self.unit_type { + UnitType::Compilation | UnitType::Partial => 0, + UnitType::Type { .. } | UnitType::SplitType { .. } => { + let type_signature_size = 8; + let type_offset_size = self.encoding.format.word_size() as usize; + type_signature_size + type_offset_size + } + UnitType::Skeleton(_) | UnitType::SplitCompilation(_) => 8, + }; unit_length_size + version_size + debug_abbrev_offset_size + address_size_size + unit_type_size + + type_specific_size } -} -/// Instance methods. -impl UnitHeader -where - R: Reader, - Offset: ReaderOffset, -{ /// Get the length of the debugging info for this compilation unit, not /// including the byte length of the encoded length itself. - pub fn unit_length(&self) -> R::Offset { + pub fn unit_length(&self) -> Offset { self.unit_length } /// Get the length of the debugging info for this compilation unit, /// including the byte length of the encoded length itself. - pub fn length_including_self(&self) -> R::Offset { - R::Offset::from_u8(self.format().initial_length_size()) + self.unit_length + pub fn length_including_self(&self) -> Offset { + Offset::from_u8(self.format().initial_length_size()) + self.unit_length } /// Return the encoding parameters for this unit. @@ -550,9 +412,14 @@ where self.encoding.version } + /// Get the UnitType of this unit. + pub fn type_(&self) -> UnitType { + self.unit_type + } + /// The offset into the `.debug_abbrev` section for this compilation unit's /// debugging information entries' abbreviations. - pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { + pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { self.debug_abbrev_offset } @@ -567,11 +434,11 @@ where } /// The serialized size of the header for this compilation unit. - pub fn header_size(&self) -> R::Offset { + pub fn header_size(&self) -> Offset { self.length_including_self() - self.entries_buf.len() } - pub(crate) fn is_valid_offset(&self, offset: UnitOffset) -> bool { + pub(crate) fn is_valid_offset(&self, offset: UnitOffset) -> bool { let size_of_header = self.header_size(); if offset.0 < size_of_header { return false; @@ -582,7 +449,7 @@ where } /// Get the underlying bytes for the supplied range. - pub fn range(&self, idx: Range>) -> Result { + pub fn range(&self, idx: Range>) -> Result { if !self.is_valid_offset(idx.start) { return Err(Error::OffsetOutOfBounds); } @@ -600,7 +467,7 @@ where } /// Get the underlying bytes for the supplied range. - pub fn range_from(&self, idx: RangeFrom>) -> Result { + pub fn range_from(&self, idx: RangeFrom>) -> Result { if !self.is_valid_offset(idx.start) { return Err(Error::OffsetOutOfBounds); } @@ -611,7 +478,7 @@ where } /// Get the underlying bytes for the supplied range. - pub fn range_to(&self, idx: RangeTo>) -> Result { + pub fn range_to(&self, idx: RangeTo>) -> Result { if !self.is_valid_offset(idx.end) { return Err(Error::OffsetOutOfBounds); } @@ -625,7 +492,7 @@ where pub fn entry<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, - offset: UnitOffset, + offset: UnitOffset, ) -> Result> { let mut input = self.range_from(offset..)?; let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?; @@ -651,7 +518,7 @@ where pub fn entries_at_offset<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, - offset: UnitOffset, + offset: UnitOffset, ) -> Result> { let input = self.range_from(offset..)?; Ok(EntriesCursor { @@ -668,7 +535,7 @@ where pub fn entries_tree<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, - offset: Option>, + offset: Option>, ) -> Result> { let input = match offset { Some(offset) => self.range_from(offset..)?, @@ -681,7 +548,7 @@ where pub fn entries_raw<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, - offset: Option>, + offset: Option>, ) -> Result> { let input = match offset { Some(offset) => self.range_from(offset..)?, @@ -701,26 +568,37 @@ where } } -/// Parse a compilation unit header. -fn parse_unit_header(input: &mut R) -> Result> { +/// Parse a unit header. +fn parse_unit_header( + input: &mut R, + unit_offset: UnitSectionOffset, +) -> Result> +where + R: Reader, + Offset: ReaderOffset, +{ let (unit_length, format) = input.read_initial_length()?; let mut rest = input.split(unit_length)?; let version = rest.read_u16()?; - let offset; + let abbrev_offset; let address_size; + let unit_type; // DWARF 1 was very different, and is obsolete, so isn't supported by this // reader. if 2 <= version && version <= 4 { - offset = parse_debug_abbrev_offset(&mut rest, format)?; + abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; address_size = rest.read_u8()?; + // Before DWARF5, all units in the .debug_info section are compilation + // units, and all units in the .debug_types section are type units. + unit_type = match unit_offset { + UnitSectionOffset::DebugInfoOffset(_) => constants::DW_UT_compile, + UnitSectionOffset::DebugTypesOffset(_) => constants::DW_UT_type, + }; } else if version == 5 { - let unit_type = parse_compilation_unit_type(&mut rest)?; - if unit_type != constants::DW_UT_compile { - return Err(Error::UnsupportedUnitType); - } + unit_type = parse_unit_type(&mut rest)?; address_size = rest.read_u8()?; - offset = parse_debug_abbrev_offset(&mut rest, format)?; + abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; } else { return Err(Error::UnknownVersion(u64::from(version))); } @@ -730,7 +608,50 @@ fn parse_unit_header(input: &mut R) -> Result> { address_size, }; - Ok(UnitHeader::new(encoding, unit_length, offset, rest)) + // Parse any data specific to this type of unit. + let unit_type = match unit_type { + constants::DW_UT_compile => UnitType::Compilation, + constants::DW_UT_type => { + let type_signature = parse_type_signature(&mut rest)?; + let type_offset = parse_type_offset(&mut rest, format)?; + UnitType::Type { + type_signature, + type_offset, + } + } + constants::DW_UT_partial => UnitType::Partial, + constants::DW_UT_skeleton => { + let dwo_id = parse_dwo_id(&mut rest)?; + UnitType::Skeleton(dwo_id) + } + constants::DW_UT_split_compile => { + let dwo_id = parse_dwo_id(&mut rest)?; + UnitType::SplitCompilation(dwo_id) + } + constants::DW_UT_split_type => { + let type_signature = parse_type_signature(&mut rest)?; + let type_offset = parse_type_offset(&mut rest, format)?; + UnitType::SplitType { + type_signature, + type_offset, + } + } + _ => return Err(Error::UnsupportedUnitType), + }; + + Ok(UnitHeader::new( + encoding, + unit_length, + unit_type, + abbrev_offset, + unit_offset, + rest, + )) +} + +/// Parse a dwo_id from a header +fn parse_dwo_id(input: &mut R) -> Result { + Ok(DwoId(input.read_u64()?)) } /// A Debugging Information Entry (DIE). @@ -776,7 +697,7 @@ where } /// Get this entry's offset. - pub fn offset(&self) -> UnitOffset { + pub fn offset(&self) -> UnitOffset { self.offset } @@ -1192,6 +1113,10 @@ where /// An index into the filename entries from the line number information /// table for the compilation unit containing this value. FileIndex(u64), + + /// An implementation-defined identifier uniquely identifying a compilation + /// unit. + DwoId(DwoId), } /// An attribute in a `DebuggingInformationEntry`, consisting of a name and @@ -1393,6 +1318,14 @@ impl Attribute { } }; } + // This isn't a separate form but it's useful to distinguish it from a generic udata. + macro_rules! dwoid { + () => { + if let Some(value) = self.udata_value() { + return AttributeValue::DwoId(DwoId(value)); + } + }; + } // Perform the allowed class conversions for each attribute name. match self.name { @@ -1721,10 +1654,10 @@ impl Attribute { constants::DW_AT_str_offsets_base => { stroffsetsptr!(); } - constants::DW_AT_addr_base => { + constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => { addrptr!(); } - constants::DW_AT_rnglists_base => { + constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => { rnglistsptr!(); } constants::DW_AT_dwo_name => { @@ -1796,6 +1729,9 @@ impl Attribute { constants::DW_AT_loclists_base => { loclistsptr!(); } + constants::DW_AT_GNU_dwo_id => { + dwoid!(); + } _ => {} } self.value.clone() @@ -3155,8 +3091,8 @@ impl DebugTypes { /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn units(&self) -> TypeUnitHeadersIter { - TypeUnitHeadersIter { + pub fn units(&self) -> DebugTypesUnitHeadersIter { + DebugTypesUnitHeadersIter { input: self.debug_types_section.clone(), offset: DebugTypesOffset(R::Offset::from_u8(0)), } @@ -3169,19 +3105,19 @@ impl DebugTypes { /// `DebugTypes::units`](./struct.DebugTypes.html#method.units) for /// more detail. #[derive(Clone, Debug)] -pub struct TypeUnitHeadersIter { +pub struct DebugTypesUnitHeadersIter { input: R, offset: DebugTypesOffset, } -impl TypeUnitHeadersIter { +impl DebugTypesUnitHeadersIter { /// Advance the iterator to the next type unit header. - pub fn next(&mut self) -> Result>> { + pub fn next(&mut self) -> Result>> { if self.input.is_empty() { Ok(None) } else { let len = self.input.len(); - match parse_type_unit_header(&mut self.input, self.offset) { + match parse_unit_header(&mut self.input, self.offset.into()) { Ok(header) => { self.offset.0 += len - self.input.len(); Ok(Some(header)) @@ -3196,290 +3132,37 @@ impl TypeUnitHeadersIter { } #[cfg(feature = "fallible-iterator")] -impl fallible_iterator::FallibleIterator for TypeUnitHeadersIter { - type Item = TypeUnitHeader; +impl fallible_iterator::FallibleIterator for DebugTypesUnitHeadersIter { + type Item = UnitHeader; type Error = Error; fn next(&mut self) -> ::core::result::Result, Self::Error> { - TypeUnitHeadersIter::next(self) + DebugTypesUnitHeadersIter::next(self) } } -/// The header of a type unit's debugging information. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct TypeUnitHeader::Offset> -where - R: Reader, - Offset: ReaderOffset, -{ - header: UnitHeader, - offset: DebugTypesOffset, - type_signature: DebugTypeSignature, - type_offset: UnitOffset, -} - -impl TypeUnitHeader -where - R: Reader, - Offset: ReaderOffset, -{ - /// Construct a new `TypeUnitHeader`. - fn new( - header: UnitHeader, - offset: DebugTypesOffset, - type_signature: DebugTypeSignature, - type_offset: UnitOffset, - ) -> Self { - TypeUnitHeader { - header, - offset, - type_signature, - type_offset, - } - } - - /// Return the `UnitHeader` containing common unit fields. - pub fn header(self) -> UnitHeader { - self.header - } - - /// Return the serialized size of the type-unit header for the given - /// DWARF format. - pub fn size_of_header(encoding: Encoding) -> usize { - let unit_header_size = UnitHeader::::size_of_header(encoding); - let type_signature_size = 8; - let type_offset_size = encoding.format.word_size() as usize; - unit_header_size + type_signature_size + type_offset_size - } - - /// Get the offset of this compilation unit within the .debug_info section. - pub fn offset(&self) -> DebugTypesOffset { - self.offset - } - - /// Get the length of the debugging info for this type-unit. - pub fn unit_length(&self) -> R::Offset { - self.header.unit_length - } - - /// Get the length of the debugging info for this type-unit, - /// including the byte length of the encoded length itself. - pub fn length_including_self(&self) -> R::Offset { - self.header.length_including_self() - } - - /// Return the encoding parameters for this unit. - pub fn encoding(&self) -> Encoding { - self.header.encoding - } - - /// Get the DWARF version of the debugging info for this type-unit. - pub fn version(&self) -> u16 { - self.header.version() - } - - /// The offset into the `.debug_abbrev` section for this type-unit's - /// debugging information entries. - pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { - self.header.debug_abbrev_offset - } - - /// The size of addresses (in bytes) in this type-unit. - pub fn address_size(&self) -> u8 { - self.header.address_size() - } - - /// Whether this type unit is encoded in 64- or 32-bit DWARF. - pub fn format(&self) -> Format { - self.header.format() - } - - /// The serialized size of the header for this type-unit. - pub fn header_size(&self) -> R::Offset { - self.header.header_size() - } - - /// Get the unique type signature for this type unit. - pub fn type_signature(&self) -> DebugTypeSignature { - self.type_signature - } - - /// Get the offset within this type unit where the type is defined. - pub fn type_offset(&self) -> UnitOffset { - self.type_offset - } - - /// Navigate this type unit's `DebuggingInformationEntry`s. - pub fn entries<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - ) -> EntriesCursor<'abbrev, 'me, R> { - self.header.entries(abbreviations) - } - - /// Navigate this type unit's `DebuggingInformationEntry`s - /// starting at the given offset. - pub fn entries_at_offset<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: UnitOffset, - ) -> Result> { - self.header.entries_at_offset(abbreviations, offset) - } - - /// Navigate this type unit's `DebuggingInformationEntry`s as a tree - /// starting at the given offset. - pub fn entries_tree<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: Option>, - ) -> Result> { - self.header.entries_tree(abbreviations, offset) - } - - /// Read the raw data that defines the Debugging Information Entries. - pub fn entries_raw<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: Option>, - ) -> Result> { - self.header.entries_raw(abbreviations, offset) - } - - /// Parse this type unit's abbreviations. - /// - /// ``` - /// use gimli::DebugAbbrev; - /// # use gimli::{DebugTypes, LittleEndian}; - /// # let types_buf = [ - /// # // Type unit header - /// # - /// # // 32-bit unit length = 37 - /// # 0x25, 0x00, 0x00, 0x00, - /// # // Version 4 - /// # 0x04, 0x00, - /// # // debug_abbrev_offset - /// # 0x00, 0x00, 0x00, 0x00, - /// # // Address size - /// # 0x04, - /// # // Type signature - /// # 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - /// # // Type offset - /// # 0x01, 0x02, 0x03, 0x04, - /// # - /// # // DIEs - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # ]; - /// # let debug_types = DebugTypes::new(&types_buf, LittleEndian); - /// # - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_yes - /// # 0x01, - /// # // Begin attributes - /// # // Attribute name = DW_AT_name - /// # 0x03, - /// # // Attribute form = DW_FORM_string - /// # 0x08, - /// # // End attributes - /// # 0x00, - /// # 0x00, - /// # // Null terminator - /// # 0x00 - /// # ]; - /// # - /// # let get_some_type_unit = || debug_types.units().next().unwrap().unwrap(); - /// - /// let unit = get_some_type_unit(); - /// - /// # let read_debug_abbrev_section_somehow = || &abbrev_buf; - /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); - /// let abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); - /// ``` - pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev) -> Result { - self.header.abbreviations(debug_abbrev) - } -} - -/// Parse a type unit header. -fn parse_type_unit_header( - input: &mut R, - offset: DebugTypesOffset, -) -> Result> { - let mut header = parse_unit_header(input)?; - let format = header.format(); - let signature = parse_type_signature(&mut header.entries_buf)?; - let type_offset = parse_type_offset(&mut header.entries_buf, format)?; - Ok(TypeUnitHeader::new(header, offset, signature, type_offset)) -} - -#[cfg(test)] -// Tests require leb128::write. -#[cfg(feature = "write")] -mod tests { - use super::*; - use crate::constants; - use crate::constants::*; - use crate::endianity::{Endianity, LittleEndian}; - use crate::leb128; - use crate::read::abbrev::tests::AbbrevSectionMethods; - use crate::read::{ - Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result, - }; - use crate::test_util::GimliSectionMethods; - use alloc::vec::Vec; - use core::cell::Cell; - use test_assembler::{Endian, Label, LabelMaker, Section}; +#[cfg(test)] +// Tests require leb128::write. +#[cfg(feature = "write")] +mod tests { + use super::*; + use crate::constants; + use crate::constants::*; + use crate::endianity::{Endianity, LittleEndian}; + use crate::leb128; + use crate::read::abbrev::tests::AbbrevSectionMethods; + use crate::read::{ + Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result, + }; + use crate::test_util::GimliSectionMethods; + use alloc::vec::Vec; + use core::cell::Cell; + use test_assembler::{Endian, Label, LabelMaker, Section}; // Mixin methods for `Section` to help define binary test data. trait UnitSectionMethods { - fn comp_unit<'input, E>( - self, - unit: &mut CompilationUnitHeader>, - ) -> Self - where - E: Endianity; - fn type_unit<'input, E>(self, unit: &mut TypeUnitHeader>) -> Self - where - E: Endianity; - fn unit<'input, E>( - self, - unit: &mut UnitHeader>, - extra_header: &[u8], - ) -> Self + fn unit<'input, E>(self, unit: &mut UnitHeader>) -> Self where E: Endianity; fn die(self, code: u64, attr: F) -> Self @@ -3492,37 +3175,11 @@ mod tests { } impl UnitSectionMethods for Section { - fn comp_unit<'input, E>( - self, - unit: &mut CompilationUnitHeader>, - ) -> Self - where - E: Endianity, - { - unit.offset = DebugInfoOffset(self.size() as usize); - self.unit(&mut unit.header, &[]) - } - - fn type_unit<'input, E>(self, unit: &mut TypeUnitHeader>) -> Self - where - E: Endianity, - { - unit.offset = DebugTypesOffset(self.size() as usize); - let section = Section::with_endian(Endian::Little) - .L64(unit.type_signature.0) - .offset(unit.type_offset.0, unit.header.format()); - let extra_header = section.get_contents().unwrap(); - self.unit(&mut unit.header, &extra_header) - } - - fn unit<'input, E>( - self, - unit: &mut UnitHeader>, - extra_header: &[u8], - ) -> Self + fn unit<'input, E>(self, unit: &mut UnitHeader>) -> Self where E: Endianity, { + let size = self.size(); let length = Label::new(); let start = Label::new(); let end = Label::new(); @@ -3537,22 +3194,46 @@ mod tests { .mark(&start) .L16(unit.version()) .offset(unit.debug_abbrev_offset.0, unit.format()) - .D8(unit.address_size()) - .append_bytes(extra_header) - .append_bytes(unit.entries_buf.into()) - .mark(&end), + .D8(unit.address_size()), 5 => section .mark(&start) .L16(unit.version()) - .D8(constants::DW_UT_compile.0) + .D8(unit.type_().dw_ut().0) .D8(unit.address_size()) - .offset(unit.debug_abbrev_offset.0, unit.format()) - .append_bytes(extra_header) - .append_bytes(unit.entries_buf.into()) - .mark(&end), + .offset(unit.debug_abbrev_offset.0, unit.format()), _ => unreachable!(), }; + let section = match unit.type_() { + UnitType::Compilation | UnitType::Partial => { + unit.unit_offset = DebugInfoOffset(size as usize).into(); + section + } + UnitType::Type { + type_signature, + type_offset, + } + | UnitType::SplitType { + type_signature, + type_offset, + } => { + if unit.version() == 5 { + unit.unit_offset = DebugInfoOffset(size as usize).into(); + } else { + unit.unit_offset = DebugTypesOffset(size as usize).into(); + } + section + .L64(type_signature.0) + .offset(type_offset.0, unit.format()) + } + UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => { + unit.unit_offset = DebugInfoOffset(size as usize).into(); + section.L64(dwo_id.0) + } + }; + + let section = section.append_bytes(unit.entries_buf.into()).mark(&end); + unit.unit_length = (&end - &start) as usize; length.set_const(unit.unit_length as u64); @@ -3587,6 +3268,17 @@ mod tests { } } + /// Ensure that `UnitHeader` is covariant wrt R. + #[test] + fn test_unit_header_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>( + x: UnitHeader>, + ) -> UnitHeader> { + x + } + } + #[test] fn test_parse_debug_abbrev_offset_32() { let section = Section::with_endian(Endian::Little).L32(0x0403_0201); @@ -3682,129 +3374,314 @@ mod tests { } #[test] - #[cfg(target_pointer_width = "64")] - fn test_units() { + #[cfg(target_pointer_width = "64")] + fn test_units() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let mut unit64 = UnitHeader { + encoding: Encoding { + format: Format::Dwarf64, + version: 4, + address_size: 8, + }, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let mut unit32 = UnitHeader { + encoding: Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut unit64) + .unit(&mut unit32); + let buf = section.get_contents().unwrap(); + + let debug_info = DebugInfo::new(&buf, LittleEndian); + let mut units = debug_info.units(); + + assert_eq!(units.next(), Ok(Some(unit64))); + assert_eq!(units.next(), Ok(Some(unit32))); + assert_eq!(units.next(), Ok(None)); + } + + #[test] + fn test_unit_version_unknown_version() { + let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_unit_header(rest, DebugInfoOffset(0).into()) { + Err(Error::UnknownVersion(0xcdab)) => assert!(true), + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + + let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_unit_header(rest, DebugInfoOffset(0).into()) { + Err(Error::UnknownVersion(1)) => assert!(true), + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_unit_version_incomplete() { + let buf = [0x01, 0x00, 0x00, 0x00, 0x04]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + match parse_unit_header(rest, DebugInfoOffset(0).into()) { + Err(Error::UnexpectedEof(_)) => assert!(true), + otherwise => panic!("Unexpected result: {:?}", otherwise), + }; + } + + #[test] + fn test_parse_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 4, + address_size: 4, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 4, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 4, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_partial_unit_header_32_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let mut unit64 = CompilationUnitHeader { - header: UnitHeader { - encoding: Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }, - offset: DebugInfoOffset(0), + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 4, }; - let mut unit32 = CompilationUnitHeader { - header: UnitHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }, - offset: DebugInfoOffset(0), + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Partial, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) - .comp_unit(&mut unit64) - .comp_unit(&mut unit32); + .unit(&mut expected_unit) + .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); - let debug_info = DebugInfo::new(&buf, LittleEndian); - let mut units = debug_info.units(); - - assert_eq!(units.next(), Ok(Some(unit64))); - assert_eq!(units.next(), Ok(Some(unit32))); - assert_eq!(units.next(), Ok(None)); + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] - fn test_unit_version_unknown_version() { - let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest) { - Err(Error::UnknownVersion(0xcdab)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_partial_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, }; - - let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest) { - Err(Error::UnknownVersion(1)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Partial, + debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; - } - - #[test] - fn test_unit_version_incomplete() { - let buf = [0x01, 0x00, 0x00, 0x00, 0x04]; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); - match parse_unit_header(rest) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] - fn test_parse_unit_header_32_ok() { + fn test_parse_v5_skeleton_unit_header_32_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf32, - version: 4, + version: 5, address_size: 4, }; let mut expected_unit = UnitHeader { encoding, unit_length: 0, + unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit, &[]) + .unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); - assert_eq!(parse_unit_header(rest), Ok(expected_unit)); + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] #[cfg(target_pointer_width = "64")] - fn test_parse_unit_header_64_ok() { + fn test_parse_v5_skeleton_unit_header_64_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf64, - version: 4, + version: 5, address_size: 8, }; let mut expected_unit = UnitHeader { encoding, unit_length: 0, + unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit, &[]) + .unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); - assert_eq!(parse_unit_header(rest), Ok(expected_unit)); + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] - fn test_parse_v5_unit_header_32_ok() { + fn test_parse_v5_split_compilation_unit_header_32_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf32, @@ -3814,22 +3691,27 @@ mod tests { let mut expected_unit = UnitHeader { encoding, unit_length: 0, + unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit, &[]) + .unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); - assert_eq!(parse_unit_header(rest), Ok(expected_unit)); + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] #[cfg(target_pointer_width = "64")] - fn test_parse_v5_unit_header_64_ok() { + fn test_parse_v5_split_compilation_unit_header_64_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf64, @@ -3839,16 +3721,21 @@ mod tests { let mut expected_unit = UnitHeader { encoding, unit_length: 0, + unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), + unit_offset: DebugInfoOffset(0).into(), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit, &[]) + .unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); - assert_eq!(parse_unit_header(rest), Ok(expected_unit)); + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } @@ -3901,25 +3788,25 @@ mod tests { version: 4, address_size: 8, }; - let mut expected_unit = TypeUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412), }, - offset: DebugTypesOffset(0), - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412), + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) - .type_unit(&mut expected_unit) + .unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!( - parse_type_unit_header(rest, DebugTypesOffset(0)), + parse_unit_header(rest, DebugTypesOffset(0).into()), Ok(expected_unit) ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); @@ -3934,25 +3821,155 @@ mod tests { version: 4, address_size: 8, }; - let mut expected_unit = TypeUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412_7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugTypesOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_type_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_type_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412_7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + fn test_parse_v5_split_type_unit_header_32_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf32, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::SplitType { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412), + }, + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), + }; + let section = Section::with_endian(Endian::Little) + .unit(&mut expected_unit) + .append_bytes(expected_rest); + let buf = section.get_contents().unwrap(); + let rest = &mut EndianSlice::new(&buf, LittleEndian); + + assert_eq!( + parse_unit_header(rest, DebugInfoOffset(0).into()), + Ok(expected_unit) + ); + assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_parse_v5_split_type_unit_header_64_ok() { + let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; + let encoding = Encoding { + format: Format::Dwarf64, + version: 5, + address_size: 8, + }; + let mut expected_unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::SplitType { + type_signature: DebugTypeSignature(0xdead_beef_dead_beef), + type_offset: UnitOffset(0x7856_3412_7856_3412), }, - offset: DebugTypesOffset(0), - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412_7856_3412), + debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) - .type_unit(&mut expected_unit) + .unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!( - parse_type_unit_header(rest, DebugTypesOffset(0)), + parse_unit_header(rest, DebugInfoOffset(0).into()), Ok(expected_unit) ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); @@ -4189,7 +4206,9 @@ mod tests { UnitHeader::new( encoding, 7, + UnitType::Compilation, DebugAbbrevOffset(0x0807_0605), + DebugInfoOffset(0).into(), EndianSlice::new(&[], endian), ) } @@ -4792,7 +4811,9 @@ mod tests { let unit = UnitHeader::new( encoding, 7, + UnitType::Compilation, DebugAbbrevOffset(0x0807_0605), + DebugInfoOffset(0).into(), EndianSlice::new(&[], LittleEndian), ); @@ -4901,7 +4922,9 @@ mod tests { let unit = UnitHeader::new( encoding, 7, + UnitType::Compilation, DebugAbbrevOffset(0x0807_0605), + DebugInfoOffset(0).into(), EndianSlice::new(&[], LittleEndian), ); @@ -5103,16 +5126,15 @@ mod tests { version: 4, address_size: 4, }; - let mut unit = CompilationUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }, - offset: DebugInfoOffset(0), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }; - let section = Section::with_endian(Endian::Little).comp_unit(&mut unit); + let section = Section::with_endian(Endian::Little).unit(&mut unit); section.get_contents().unwrap() } @@ -5130,16 +5152,15 @@ mod tests { version: 4, address_size: 4, }; - let mut unit = CompilationUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }, - offset: DebugInfoOffset(0), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }; - let section = Section::with_endian(Endian::Little).comp_unit(&mut unit); + let section = Section::with_endian(Endian::Little).unit(&mut unit); let info_buf = §ion.get_contents().unwrap(); let debug_info = DebugInfo::new(info_buf, LittleEndian); @@ -5456,20 +5477,19 @@ mod tests { version: 4, address_size: 4, }; - let header_size = - CompilationUnitHeader::, _>::size_of_header(encoding); - let entries_buf = entries_cursor_sibling_entries_buf(header_size); - let mut unit = CompilationUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }, - offset: DebugInfoOffset(0), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&[], LittleEndian), }; - let section = Section::with_endian(Endian::Little).comp_unit(&mut unit); + let header_size = unit.size_of_header(); + let entries_buf = entries_cursor_sibling_entries_buf(header_size); + unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); + let section = Section::with_endian(Endian::Little).unit(&mut unit); let info_buf = section.get_contents().unwrap(); let debug_info = DebugInfo::new(&info_buf, LittleEndian); @@ -5497,21 +5517,21 @@ mod tests { version: 4, address_size: 4, }; - let header_size = TypeUnitHeader::, _>::size_of_header(encoding); - let entries_buf = entries_cursor_sibling_entries_buf(header_size); - - let mut unit = TypeUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0), + type_offset: UnitOffset(0), }, - type_signature: DebugTypeSignature(0), - type_offset: UnitOffset(0), - offset: DebugTypesOffset(0), + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(&[], LittleEndian), }; - let section = Section::with_endian(Endian::Little).type_unit(&mut unit); + let header_size = unit.size_of_header(); + let entries_buf = entries_cursor_sibling_entries_buf(header_size); + unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); + let section = Section::with_endian(Endian::Little).unit(&mut unit); let info_buf = section.get_contents().unwrap(); let debug_types = DebugTypes::new(&info_buf, LittleEndian); @@ -5651,20 +5671,19 @@ mod tests { version: 4, address_size: 4, }; - let header_size = - CompilationUnitHeader::, _>::size_of_header(encoding); - let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size); - let mut unit = CompilationUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }, - offset: DebugInfoOffset(0), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&[], LittleEndian), }; + let header_size = unit.size_of_header(); + let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size); + unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); let info_buf = Section::with_endian(Endian::Little) - .comp_unit(&mut unit) + .unit(&mut unit) .get_contents() .unwrap(); let debug_info = DebugInfo::new(&info_buf, LittleEndian); @@ -5818,16 +5837,15 @@ mod tests { version: 4, address_size: 4, }; - let mut unit = CompilationUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }, - offset: DebugInfoOffset(0), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }; - let section = Section::with_endian(Endian::Little).comp_unit(&mut unit); + let section = Section::with_endian(Endian::Little).unit(&mut unit); let info_buf = section.get_contents().unwrap(); let debug_info = DebugInfo::new(&info_buf, LittleEndian); @@ -5890,21 +5908,19 @@ mod tests { version: 4, address_size: 4, }; - let mut unit = CompilationUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(entries, LittleEndian), - }, - offset: DebugInfoOffset(0), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Compilation, + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), + entries_buf: EndianSlice::new(entries, LittleEndian), }; Section::with_endian(Endian::Little) .append_bytes(padding) - .comp_unit(&mut unit); + .unit(&mut unit); let offset = padding.len(); - let header_length = - CompilationUnitHeader::, _>::size_of_header(encoding); + let header_length = unit.size_of_header(); let length = unit.length_including_self(); assert_eq!(DebugInfoOffset(0).to_unit_offset(&unit), None); assert_eq!(DebugInfoOffset(offset - 1).to_unit_offset(&unit), None); @@ -5924,11 +5940,11 @@ mod tests { assert_eq!(DebugInfoOffset(offset + length).to_unit_offset(&unit), None); assert_eq!( UnitOffset(header_length).to_debug_info_offset(&unit), - DebugInfoOffset(offset + header_length) + Some(DebugInfoOffset(offset + header_length)) ); assert_eq!( UnitOffset(length - 1).to_debug_info_offset(&unit), - DebugInfoOffset(offset + length - 1) + Some(DebugInfoOffset(offset + length - 1)) ); } @@ -5941,23 +5957,22 @@ mod tests { version: 4, address_size: 4, }; - let mut unit = TypeUnitHeader { - header: UnitHeader { - encoding, - unit_length: 0, - debug_abbrev_offset: DebugAbbrevOffset(0), - entries_buf: EndianSlice::new(entries, LittleEndian), + let mut unit = UnitHeader { + encoding, + unit_length: 0, + unit_type: UnitType::Type { + type_signature: DebugTypeSignature(0), + type_offset: UnitOffset(0), }, - type_signature: DebugTypeSignature(0), - type_offset: UnitOffset(0), - offset: DebugTypesOffset(0), + debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugTypesOffset(0).into(), + entries_buf: EndianSlice::new(entries, LittleEndian), }; Section::with_endian(Endian::Little) .append_bytes(padding) - .type_unit(&mut unit); + .unit(&mut unit); let offset = padding.len(); - let header_length = - TypeUnitHeader::, _>::size_of_header(encoding); + let header_length = unit.size_of_header(); let length = unit.length_including_self(); assert_eq!(DebugTypesOffset(0).to_unit_offset(&unit), None); assert_eq!(DebugTypesOffset(offset - 1).to_unit_offset(&unit), None); @@ -5980,11 +5995,11 @@ mod tests { ); assert_eq!( UnitOffset(header_length).to_debug_types_offset(&unit), - DebugTypesOffset(offset + header_length) + Some(DebugTypesOffset(offset + header_length)) ); assert_eq!( UnitOffset(length - 1).to_debug_types_offset(&unit), - DebugTypesOffset(offset + length - 1) + Some(DebugTypesOffset(offset + length - 1)) ); } @@ -5998,7 +6013,9 @@ mod tests { let mut unit = UnitHeader { encoding, unit_length: 0, + unit_type: UnitType::Compilation, debug_abbrev_offset: DebugAbbrevOffset(0), + unit_offset: DebugInfoOffset(0).into(), entries_buf: EndianSlice::new(&[], LittleEndian), }; unit.encoding.format = Format::Dwarf32; @@ -6008,4 +6025,50 @@ mod tests { unit.unit_length = 10; assert_eq!(unit.length_including_self(), 22); } + + #[test] + fn test_parse_type_unit_abbrevs() { + let types_buf = [ + // Type unit header + 0x25, 0x00, 0x00, 0x00, // 32-bit unit length = 37 + 0x04, 0x00, // Version 4 + 0x00, 0x00, 0x00, 0x00, // debug_abbrev_offset + 0x04, // Address size + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Type signature + 0x01, 0x02, 0x03, 0x04, // Type offset + // DIEs + // Abbreviation code + 0x01, // Attribute of form DW_FORM_string = "foo\0" + 0x66, 0x6f, 0x6f, 0x00, // Children + // Abbreviation code + 0x01, // Attribute of form DW_FORM_string = "foo\0" + 0x66, 0x6f, 0x6f, 0x00, // Children + // Abbreviation code + 0x01, // Attribute of form DW_FORM_string = "foo\0" + 0x66, 0x6f, 0x6f, 0x00, // Children + 0x00, // End of children + 0x00, // End of children + 0x00, // End of children + ]; + let debug_types = DebugTypes::new(&types_buf, LittleEndian); + + let abbrev_buf = [ + // Code + 0x01, // DW_TAG_subprogram + 0x2e, // DW_CHILDREN_yes + 0x01, // Begin attributes + 0x03, // Attribute name = DW_AT_name + 0x08, // Attribute form = DW_FORM_string + 0x00, 0x00, // End attributes + 0x00, // Null terminator + ]; + + let get_some_type_unit = || debug_types.units().next().unwrap().unwrap(); + + let unit = get_some_type_unit(); + + let read_debug_abbrev_section_somehow = || &abbrev_buf; + let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); + let _abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); + } } diff --git a/vendor/gimli/src/read/value.rs b/vendor/gimli/src/read/value.rs index 292320485e..b5d290781e 100644 --- a/vendor/gimli/src/read/value.rs +++ b/vendor/gimli/src/read/value.rs @@ -906,11 +906,11 @@ impl Value { #[cfg(test)] mod tests { use super::*; - use crate::common::{DebugAbbrevOffset, Encoding, Format}; + use crate::common::{DebugAbbrevOffset, DebugInfoOffset, Encoding, Format}; use crate::endianity::LittleEndian; use crate::read::{ Abbreviation, AttributeSpecification, DebuggingInformationEntry, EndianSlice, UnitHeader, - UnitOffset, + UnitOffset, UnitType, }; #[test] @@ -924,7 +924,9 @@ mod tests { let unit = UnitHeader::new( encoding, 7, + UnitType::Compilation, DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), EndianSlice::new(&[], LittleEndian), ); diff --git a/vendor/gimli/src/write/loc.rs b/vendor/gimli/src/write/loc.rs index 2e742f76b2..6c029c2aae 100644 --- a/vendor/gimli/src/write/loc.rs +++ b/vendor/gimli/src/write/loc.rs @@ -428,7 +428,7 @@ mod tests { use super::*; use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, UnitSectionOffset, + DebugStrOffsetsBase, Format, }; use crate::read; use crate::write::{ @@ -500,11 +500,12 @@ mod tests { ..Default::default() }; let unit = read::Unit { - offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: read::UnitHeader::new( encoding, 0, + read::UnitType::Compilation, DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), read::EndianSlice::default(), ), abbreviations: read::Abbreviations::default(), diff --git a/vendor/gimli/src/write/mod.rs b/vendor/gimli/src/write/mod.rs index bf36de48c3..47ba6319d3 100644 --- a/vendor/gimli/src/write/mod.rs +++ b/vendor/gimli/src/write/mod.rs @@ -356,6 +356,8 @@ mod convert { UnsupportedOperation, /// Operation branch target is invalid. InvalidBranchTarget, + /// Writing this unit type is not supported yet. + UnsupportedUnitType, } impl fmt::Display for ConvertError { @@ -403,6 +405,7 @@ mod convert { "Writing this expression operation is not implemented yet." ), InvalidBranchTarget => write!(f, "Operation branch target is invalid."), + UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."), } } } diff --git a/vendor/gimli/src/write/op.rs b/vendor/gimli/src/write/op.rs index 6bf6920a0a..f66d0b6d2b 100644 --- a/vendor/gimli/src/write/op.rs +++ b/vendor/gimli/src/write/op.rs @@ -1014,7 +1014,7 @@ mod tests { use super::*; use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, SectionId, UnitSectionOffset, + DebugStrOffsetsBase, Format, SectionId, }; use crate::read; use crate::write::{ @@ -1506,11 +1506,12 @@ mod tests { // Fake the unit. let unit = read::Unit { - offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: read::UnitHeader::new( encoding, 0, + read::UnitType::Compilation, DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), read::EndianSlice::new(&[], LittleEndian), ), abbreviations: read::Abbreviations::default(), @@ -1525,10 +1526,7 @@ mod tests { }; let mut entry_ids = HashMap::new(); - entry_ids.insert( - UnitSectionOffset::DebugInfoOffset(debug_info_offset), - (unit_id, entry_id), - ); + entry_ids.insert(debug_info_offset.into(), (unit_id, entry_id)); let convert_expression = Expression::from( read_expression, encoding, diff --git a/vendor/gimli/src/write/range.rs b/vendor/gimli/src/write/range.rs index 5ad60dce13..a9cc55b029 100644 --- a/vendor/gimli/src/write/range.rs +++ b/vendor/gimli/src/write/range.rs @@ -306,7 +306,7 @@ mod tests { use super::*; use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, UnitSectionOffset, + DebugStrOffsetsBase, Format, }; use crate::read; use crate::write::{ @@ -367,11 +367,12 @@ mod tests { ..Default::default() }; let unit = read::Unit { - offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: read::UnitHeader::new( encoding, 0, + read::UnitType::Compilation, DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), read::EndianSlice::default(), ), abbreviations: read::Abbreviations::default(), diff --git a/vendor/gimli/src/write/unit.rs b/vendor/gimli/src/write/unit.rs index 796bfbcec9..87dd28b3f4 100644 --- a/vendor/gimli/src/write/unit.rs +++ b/vendor/gimli/src/write/unit.rs @@ -4,7 +4,7 @@ use std::{slice, usize}; use crate::common::{ DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset, - DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId, + DebugStrOffset, DebugTypeSignature, DwoId, Encoding, Format, SectionId, }; use crate::constants; use crate::leb128::write::{sleb128_size, uleb128_size}; @@ -1555,11 +1555,15 @@ pub(crate) mod convert { /// Does not add entry attributes. #[allow(clippy::too_many_arguments)] pub(crate) fn convert_entries>( - from_header: read::CompilationUnitHeader, + from_header: read::UnitHeader, unit_id: UnitId, entry_ids: &mut HashMap, dwarf: &read::Dwarf, ) -> ConvertResult> { + match from_header.type_() { + read::UnitType::Compilation => (), + _ => return Err(ConvertError::UnsupportedUnitType), + } let base_id = BaseId::default(); let from_unit = dwarf.unit(from_header)?; @@ -1900,6 +1904,7 @@ pub(crate) mod convert { read::AttributeValue::SecOffset(_) => { return Err(ConvertError::InvalidAttributeValue); } + read::AttributeValue::DwoId(DwoId(val)) => AttributeValue::Udata(val), }; Ok(Some(to)) } @@ -1912,7 +1917,6 @@ mod tests { use super::*; use crate::common::{ DebugAddrBase, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, LineEncoding, - UnitSectionOffset, }; use crate::constants; use crate::read; @@ -2304,7 +2308,9 @@ mod tests { let from_unit = read::UnitHeader::new( encoding, 0, + read::UnitType::Compilation, DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), read::EndianSlice::new(&[], LittleEndian), ); @@ -2532,7 +2538,6 @@ mod tests { }; let unit = read::Unit { - offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: from_unit, abbreviations: read::Abbreviations::default(), name: None, @@ -2652,7 +2657,10 @@ mod tests { let mut read_units = dwarf.units(); { let read_unit1 = read_units.next().unwrap().unwrap(); - assert_eq!(read_unit1.offset(), debug_info_offsets.unit(unit_id1)); + assert_eq!( + read_unit1.offset(), + debug_info_offsets.unit(unit_id1).into() + ); let abbrevs = dwarf.abbreviations(&read_unit1).unwrap(); let mut read_entries = read_unit1.entries(&abbrevs); @@ -2681,7 +2689,10 @@ mod tests { } { let read_unit2 = read_units.next().unwrap().unwrap(); - assert_eq!(read_unit2.offset(), debug_info_offsets.unit(unit_id2)); + assert_eq!( + read_unit2.offset(), + debug_info_offsets.unit(unit_id2).into() + ); let abbrevs = dwarf.abbreviations(&read_unit2).unwrap(); let mut read_entries = read_unit2.entries(&abbrevs); @@ -2818,7 +2829,7 @@ mod tests { } fn check_sibling>( - unit: &read::CompilationUnitHeader, + unit: &read::UnitHeader, debug_abbrev: &read::DebugAbbrev, ) { let abbrevs = unit.abbreviations(debug_abbrev).unwrap(); @@ -2926,7 +2937,9 @@ mod tests { let from_unit = read::UnitHeader::new( encoding, 0, + read::UnitType::Compilation, DebugAbbrevOffset(0), + DebugInfoOffset(0).into(), read::EndianSlice::new(&[], LittleEndian), ); @@ -2997,7 +3010,6 @@ mod tests { assert_eq!(read_value, expect_value); let unit = read::Unit { - offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: from_unit, abbreviations: read::Abbreviations::default(), name: None, diff --git a/vendor/gsgdt/.cargo-checksum.json b/vendor/gsgdt/.cargo-checksum.json new file mode 100644 index 0000000000..8958e894b0 --- /dev/null +++ b/vendor/gsgdt/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"40dc18042039b34017b8bda7fc5691dd542fc46878de141645719af58c04662c","LICENSE":"8c5c5319720056c06aa9be4cbf4deeb07a929022862a457cf12d73c7072204d9","README.md":"d2b14f3be64777a3081dbee452eb719e1349c882418791ac4e21f24805ff914a","src/diff/diff.rs":"9a6d2aa5c770e8205b3d401c073dc790a4038ad23f2711b283d9c378f1748f52","src/diff/diff_graph.rs":"9f4d0ddd196e14f7001264d6f720e8b7d6abaa44b11c2477e05c6c2228982608","src/diff/match_graph.rs":"45de7188e76c79e55ffb31c372192969eb13f4a7f5d5b6f352ff3be5c3d02723","src/diff/mod.rs":"d94a9f63cff74c1b6268d074a7c9e13545b105f6707da34936c09fdcd3b5b5ff","src/graph.rs":"baaac14fc6648d6adc237a3dc8eb0bfd54b41ae278e7f091a097c8b4fa179da5","src/levenshtein.rs":"ceeef56f2a6740888d4d54cd1c004f7f6e754d22473478a202bbaa2625ec6050","src/lib.rs":"b97c5fe8d4c473d2596e940659b9a85f94cda173b7f52ccd39b03df683f22d37","src/multi_graph.rs":"971a90d5bf535ec0ce68dac94412c6a71119f3fff955c68379fda38b83e3beb2","src/node.rs":"5478d0a321c11481c2a34fa9ae0ed2dc536071c9cebafc4aab608989a8a7a335","src/util.rs":"c3d447897068b546665dd4bf205a96e858bf2d5455cfbc379982243955b6b9e5","tests/graph1.json":"06f57d4ac2780e463597130d5702567609b188a003321e2c1c669331c5af55fe","tests/graph2.json":"38e01443b996448f1b9b90eaaa1514fbf1f727ad81a94ad9f9455dff599556b2","tests/helpers.rs":"6e9b54931b341540c1fa6b4521525ec663938f62994e9dc8a6ffe488c7a3d0b5","tests/small_graph.json":"38479f33f59062c3629a6ecee491859c639d71310f4c98569eccb7bb818aa338","tests/test_diff.rs":"649cbfadaa4f43f714458ec7a11b2117aade8acfba32ba168b60fe79e93ae29e","tests/test_graph.rs":"76de7a06f06662d947fb37dbdb1c0165fd7c39249a18f660e862910d539dec1e","tests/test_multigraph.rs":"5435f8da3b669a908272ab245b2c4f724fa9add9bd73c63c455a37d359a0c280"},"package":"a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825"} \ No newline at end of file diff --git a/vendor/gsgdt/Cargo.toml b/vendor/gsgdt/Cargo.toml new file mode 100644 index 0000000000..2a25aa06ff --- /dev/null +++ b/vendor/gsgdt/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "gsgdt" +version = "0.1.2" +authors = ["Vishnunarayan K I "] +description = "Generic Stringly Typed Graph Datatype" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/vn-ki/gsgdt-rs" +[dependencies.serde] +version = "1.0" +features = ["derive"] +[dev-dependencies.serde_json] +version = "1.0" diff --git a/vendor/gsgdt/LICENSE b/vendor/gsgdt/LICENSE new file mode 100644 index 0000000000..ead4a7322d --- /dev/null +++ b/vendor/gsgdt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Vishnunarayan K I + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/gsgdt/README.md b/vendor/gsgdt/README.md new file mode 100644 index 0000000000..a7cb4c6b9c --- /dev/null +++ b/vendor/gsgdt/README.md @@ -0,0 +1,33 @@ +# gsgdt + +**G**eneric **S**tringly typed **G**raph **D**ata**T**ype + +```rust +fn main() { + let label1: String = "bb0__0_3".into(); + let label2: String = "bb0__1_3".into(); + let style: NodeStyle = Default::default(); + + let nodes = vec![ + Node::new( + vec!["_1 = const 1_i32".into(), "_2 = const 2_i32".into()], + label1.clone(), + "0".into(), + style.clone(), + ), + Node::new( + vec!["return".into()], + label2.clone(), + "1".into(), + style.clone(), + ), + ]; + + let g = Graph::new( + "Mir_0_3".into(), + GraphKind::Digraph, + nodes, + vec![Edge::new(label1, label2, "return".into())], + ); +} +``` diff --git a/vendor/gsgdt/src/diff/diff.rs b/vendor/gsgdt/src/diff/diff.rs new file mode 100644 index 0000000000..7a85a53c5b --- /dev/null +++ b/vendor/gsgdt/src/diff/diff.rs @@ -0,0 +1,106 @@ +use crate::diff::{match_graphs, DiffGraph, Match}; +use crate::{MultiGraph, Edge, Graph, NodeStyle}; +use std::collections::HashSet; + +/// Returns a MultiGraph containing the diff of the two graphs. +/// To be visualized with dot. +pub fn visualize_diff(d1: &DiffGraph, d2: &DiffGraph) -> MultiGraph { + let matches = match_graphs(d1, d2); + + let mut matched1 = HashSet::new(); + let mut matched2 = HashSet::new(); + let mut partial1 = HashSet::new(); + let mut partial2 = HashSet::new(); + + for mch in matches { + match mch { + Match::Full(m) => { + matched1.insert(m.from); + matched2.insert(m.to); + } + Match::Partial(m) => { + partial1.insert(m.from); + partial2.insert(m.to); + } + } + } + + let added_style = NodeStyle { + title_bg: Some("green".into()), + ..Default::default() + }; + let removed_style = NodeStyle { + title_bg: Some("red".into()), + ..Default::default() + }; + let changed_style = NodeStyle { + title_bg: Some("yellow".into()), + ..Default::default() + }; + let default_style = NodeStyle { + ..Default::default() + }; + + let edges1: Vec = d1 + .graph + .edges + .iter() + .map(|e| { + Edge::new( + format!("{}_diff1", e.from), + format!("{}_diff1", e.to), + e.label.clone(), + ) + }) + .collect(); + let edges2: Vec = d2 + .graph + .edges + .iter() + .map(|e| { + Edge::new( + format!("{}_diff2", e.from), + format!("{}_diff2", e.to), + e.label.clone(), + ) + }) + .collect(); + + let mut nodes1 = Vec::new(); + for node in &d1.graph.nodes { + let label = node.label.as_str(); + let mut node_cloned = node.clone(); + node_cloned.label = format!("{}_diff1", node.label); + if matched1.contains(label) { + node_cloned.style = default_style.clone(); + nodes1.push(node_cloned); + } else if partial1.contains(label) { + node_cloned.style = changed_style.clone(); + nodes1.push(node_cloned); + } else { + node_cloned.style = removed_style.clone(); + nodes1.push(node_cloned); + } + } + + let mut nodes2 = Vec::new(); + for node in &d2.graph.nodes { + let label = node.label.as_str(); + let mut node_cloned = node.clone(); + node_cloned.label = format!("{}_diff2", node.label); + if matched2.contains(label) { + node_cloned.style = default_style.clone(); + nodes2.push(node_cloned); + } else if partial2.contains(label) { + node_cloned.style = changed_style.clone(); + nodes2.push(node_cloned); + } else { + node_cloned.style = added_style.clone(); + nodes2.push(node_cloned); + } + } + let newg1 = Graph::new("diff1".to_owned(), nodes1, edges1); + let newg2 = Graph::new("diff2".to_owned(), nodes2, edges2); + + MultiGraph::new("diff".to_owned(), vec![newg1, newg2]) +} diff --git a/vendor/gsgdt/src/diff/diff_graph.rs b/vendor/gsgdt/src/diff/diff_graph.rs new file mode 100644 index 0000000000..8e1e2c8370 --- /dev/null +++ b/vendor/gsgdt/src/diff/diff_graph.rs @@ -0,0 +1,57 @@ +use crate::*; +use std::collections::{HashMap, HashSet, VecDeque}; + +/// A wrapper around [Graph](struct.Graph.html) to assist diffing. +pub struct DiffGraph<'a> { + pub(crate) graph: &'a Graph, + pub(crate) dist_start: HashMap<&'a str, usize>, + pub(crate) dist_end: HashMap<&'a str, usize>, +} + +impl<'a> DiffGraph<'a> { + pub fn new(graph: &'a Graph) -> Self { + let adj_list = graph.adj_list(); + let rev_adj_list = graph.rev_adj_list(); + let start_nodes = Self::get_source_labels(&adj_list); + let end_nodes = Self::get_source_labels(&rev_adj_list); + DiffGraph { + graph, + dist_start: Self::bfs_shortest_dist(rev_adj_list, start_nodes), + dist_end: Self::bfs_shortest_dist(adj_list, end_nodes), + } + } + + /// Calculate the shortest distance to the end from the given sources nodes using bfs. + fn bfs_shortest_dist(adj_list: AdjList<'a>, source: Vec<&'a str>) -> HashMap<&'a str, usize> { + let mut dist = HashMap::new(); + for k in source.iter() { + dist.insert(*k, 0); + } + let mut visited = HashSet::new(); + let mut queue: VecDeque<&str> = source.into(); + while let Some(node) = queue.pop_front() { + let neighbours = adj_list.get(node).unwrap(); + let curr_dist = *dist.get(&node).unwrap(); + + for neighbour in neighbours { + if !visited.contains(neighbour) { + dist.insert(neighbour, curr_dist + 1); + queue.push_back(neighbour); + visited.insert(neighbour); + } + } + } + + dist + } + + /// Get the source labels for a given adjacency list. The source labels will the + // TODO: This is sink labels, not source labels + fn get_source_labels(adj_list: &AdjList<'a>) -> Vec<&'a str> { + adj_list + .iter() + .filter(|(_, v)| v.is_empty()) + .map(|(k, _)| *k) + .collect() + } +} diff --git a/vendor/gsgdt/src/diff/match_graph.rs b/vendor/gsgdt/src/diff/match_graph.rs new file mode 100644 index 0000000000..a75545ef7c --- /dev/null +++ b/vendor/gsgdt/src/diff/match_graph.rs @@ -0,0 +1,184 @@ +use crate::diff::*; +use crate::levenshtein::distance; +use std::collections::{BTreeMap, HashSet}; + +pub type Mapping<'a> = BTreeMap<&'a str, &'a str>; + +// TODO: Is it better to return a list of matches or a hashmap +// It might be better to do former because we may need to distinguise +// b/w full and partial match +#[derive(Debug, PartialEq)] +pub struct Matching<'a> { + pub from: &'a str, + pub to: &'a str, +} + +impl<'a> Matching<'a> { + pub fn new(from: &'a str, to: &'a str) -> Matching<'a> { + Matching { from, to } + } +} + +#[derive(Debug, PartialEq)] +pub enum Match<'a> { + Full(Matching<'a>), + Partial(Matching<'a>), +} +// +// impl<'a> Match<'a> { +// fn is_full(&self) -> bool { +// match self { +// Match::Full(_) => true, +// _ => false +// } +// } +// } + +/// Matches both graphs and returns the mapping of nodes from g1 to g2 +pub fn match_graphs<'a>(d1: &'a DiffGraph<'_>, d2: &'a DiffGraph<'_>) -> Vec> { + let mut mapping: BTreeMap<&str, &str> = get_initial_mapping(d1, d2); + + // TODO: This mapping may have duplicate mappings, remove them + + let mut matches: Vec = mapping + .iter() + .map(|(from, to)| Match::Full(Matching { from, to })) + .collect(); + + // we use rev adjacency list because we are going to compare the parents + let rev_adj_list1 = d1.graph.rev_adj_list(); + let rev_adj_list2 = d2.graph.rev_adj_list(); + + let mut matched_labels_in_2: HashSet<&str> = mapping.iter().map(|(_, v)| *v).collect(); + + let mut prev_mapping = mapping.clone(); + loop { + let mut new_mapping: Mapping = BTreeMap::new(); + for (k, v) in prev_mapping.iter() { + let parents_in_1 = rev_adj_list1.get(k).unwrap(); + let parents_in_2 = rev_adj_list2.get(v).unwrap(); + + for n in parents_in_1.iter() { + // don't bother selecting if the node in 1 is already matched + // as we use a stricter selection for the initial matching + if mapping.contains_key(n) { + continue; + } + if let Some(lab) = select(d1, d2, n, &parents_in_2, false) { + // if the matched label is already matched to some node in 1, skip + if !matched_labels_in_2.contains(lab) { + matched_labels_in_2.insert(lab); + new_mapping.insert(n, lab); + } + } + } + } + // println!("{:?}", new_mapping); + // merge + let new_matches = get_new_matches(&mapping, &new_mapping); + if new_matches.len() == 0 { + break; + } + for mch in new_matches { + mapping.insert(mch.from, mch.to); + matches.push(Match::Partial(mch)); + } + prev_mapping = new_mapping; + } + + matches +} + +fn get_initial_mapping<'a>(d1: &'a DiffGraph<'_>, d2: &'a DiffGraph<'_>) -> Mapping<'a> { + let mut mapping: BTreeMap<&str, &str> = BTreeMap::new(); + let mut reverse_mapping: BTreeMap<&str, &str> = BTreeMap::new(); + let g2_labels: Vec<&str> = d2.graph.nodes.iter().map(|n| n.label.as_str()).collect(); + + // TODO: this can be functional + for node in d1.graph.nodes.iter() { + if let Some(matched_lab) = select(d1, d2, &node.label, &g2_labels, true) { + if let Some(lab_in_1) = reverse_mapping.get(matched_lab) { + // matched_lab was already matched + // select the one with the lowest cost + // this is done so that no duplicate matching will occur + let dist_already = dist_bw_nodes(d1, d2, lab_in_1, matched_lab); + let dist_new = dist_bw_nodes(d1, d2, &node.label, matched_lab); + if dist_new > dist_already { + continue; + } + mapping.remove(lab_in_1); + } + mapping.insert(&node.label, matched_lab); + reverse_mapping.insert(matched_lab, &node.label); + } + } + + mapping +} + +fn dist_bw_nodes(d1: &DiffGraph<'_>, d2: &DiffGraph<'_>, n1: &str, n2: &str) -> Option { + let node1 = d1.graph.get_node_by_label(n1).unwrap(); + let node2 = d2.graph.get_node_by_label(n2).unwrap(); + + let tup1 = ( + d1.dist_start[n1] as i64, + d1.dist_end[n1] as i64, + node1.stmts.len() as i64, + ); + let tup2 = ( + d2.dist_start[n2] as i64, + d2.dist_end[n2] as i64, + node2.stmts.len() as i64, + ); + + let s1 = node1.stmts.join(""); + let s2 = node2.stmts.join(""); + let dist = distance(&s1, &s2); + + Some( + ((tup1.0 - tup2.0).pow(2) + (tup1.1 - tup2.1).pow(2) + (tup1.2 - tup2.2).pow(2)) as usize + + dist, + ) +} + +/// Selects the most suitable match for n from L +fn select<'a>( + d1: &'a DiffGraph<'_>, + d2: &'a DiffGraph<'_>, + n: &'a str, + list_of_labs: &[&'a str], + use_text_dist_filter: bool, +) -> Option<&'a str> { + let node = d1.graph.get_node_by_label(n).unwrap(); + let node_stmt_len = node.stmts.len(); + let node_stmts = node.stmts.join(""); + list_of_labs + .iter() + .filter(|lab| { + let other_node = d2.graph.get_node_by_label(lab).unwrap(); + // filter out nodes that may differ by more than 2 lines + (other_node.stmts.len() as i64 - node.stmts.len() as i64).abs() <= 2 + }) + .filter(|lab| { + if !use_text_dist_filter { + return true; + } + let other_node_stmts = d2.graph.get_node_by_label(lab).unwrap().stmts.join(""); + // allow bigger basic blocks have more edits + // 2 here is arbitary + distance(&node_stmts, &other_node_stmts) < 2 * node_stmt_len + }) + .min_by_key(|x| dist_bw_nodes(d1, d2, n, x)) + .map(|x| *x) +} + +fn get_new_matches<'a>(mapping: &Mapping<'a>, new_mapping: &Mapping<'a>) -> Vec> { + let mut changed = Vec::new(); + for (k, v) in new_mapping.iter() { + if !mapping.contains_key(k) { + changed.push(Matching { from: k, to: v }) + } + } + + changed +} diff --git a/vendor/gsgdt/src/diff/mod.rs b/vendor/gsgdt/src/diff/mod.rs new file mode 100644 index 0000000000..5e3d95529d --- /dev/null +++ b/vendor/gsgdt/src/diff/mod.rs @@ -0,0 +1,7 @@ +mod diff_graph; +mod match_graph; +mod diff; + +pub use match_graph::*; +pub use diff_graph::*; +pub use diff::*; diff --git a/vendor/gsgdt/src/graph.rs b/vendor/gsgdt/src/graph.rs new file mode 100644 index 0000000000..17c8597740 --- /dev/null +++ b/vendor/gsgdt/src/graph.rs @@ -0,0 +1,273 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::io::{self, Write}; + +use crate::node::*; + +#[derive(Clone, Serialize, Deserialize)] +pub enum GraphKind { + Digraph, + Subgraph, +} + +pub type AdjList<'a> = HashMap<&'a str, Vec<&'a str>>; + +/// Graph represents a directed graph as a list of nodes and list of edges. +#[derive(Serialize, Deserialize)] +pub struct Graph { + /// Identifier for the graph + pub name: String, + + /// The Vector containing the Nodes + pub nodes: Vec, + + /// The Vector containing the Edges + pub edges: Vec, +} + +#[derive(Clone)] +pub struct GraphvizSettings { + /// The attributes of the graph in graphviz. + pub graph_attrs: Option, + + /// The attributes of the nodes in graphviz. + pub node_attrs: Option, + + /// The attributes of the edges in graphviz. + pub edge_attrs: Option, + + /// Label of the graph + pub graph_label: Option, +} + +impl Default for GraphvizSettings { + fn default() -> GraphvizSettings { + GraphvizSettings { + graph_attrs: None, + node_attrs: None, + edge_attrs: None, + graph_label: None, + } + } +} + +impl Graph { + pub fn new(name: String, nodes: Vec, edges: Vec) -> Graph { + Graph { name, nodes, edges } + } + + /// Returns the adjacency list representation of the graph. + /// Adjacency list can be used to easily find the childern of a given node. + /// If the a node does not have any childern, then the list correspoding to that node + /// will be empty. + pub fn adj_list(&self) -> AdjList<'_> { + let mut m: AdjList<'_> = HashMap::new(); + for node in &self.nodes { + m.insert(&node.label, Vec::new()); + } + for edge in &self.edges { + m.entry(&edge.from).or_insert_with(Vec::new).push(&edge.to); + } + m + } + + /// Returns the reverse adjacency list representation of the graph. + /// Reverse adjacency list represents the adjacency list of a directed graph where + /// the edges have been reversed. + /// Reverse adjacency list can be used to easily find the parents of a given node. + /// If the a node does not have any childern, then the list correspoding to that node + /// will be empty. + pub fn rev_adj_list(&self) -> AdjList<'_> { + let mut m: AdjList<'_> = HashMap::new(); + for node in &self.nodes { + m.insert(&node.label, Vec::new()); + } + for edge in &self.edges { + m.entry(&edge.to).or_insert_with(Vec::new).push(&edge.from); + } + m + } + + /// Returns the node with the given label, if found. + pub fn get_node_by_label(&self, label: &str) -> Option<&Node> { + self.nodes.iter().find(|node| node.label == *label) + } + + /// Returns the dot representation of the given graph. + /// This can rendered using the graphviz program. + pub fn to_dot( + &self, + w: &mut W, + settings: &GraphvizSettings, + as_subgraph: bool, + ) -> io::Result<()> { + if as_subgraph { + write!(w, "subgraph cluster_{}", self.name)?; + } else { + write!(w, "digraph {}", self.name)?; + } + + writeln!(w, " {{")?; + + if let Some(graph_attrs) = &settings.graph_attrs { + writeln!(w, r#" graph [{}];"#, graph_attrs)?; + } + if let Some(node_attrs) = &settings.node_attrs { + writeln!(w, r#" node [{}];"#, node_attrs)?; + } + if let Some(edge_attrs) = &settings.edge_attrs { + writeln!(w, r#" edge [{}];"#, edge_attrs)?; + } + if let Some(label) = &settings.graph_label { + writeln!(w, r#" label=<{}>;"#, label)?; + } + + for node in self.nodes.iter() { + write!(w, r#" {} [shape="none", label=<"#, node.label)?; + node.to_dot(w)?; + writeln!(w, ">];")?; + } + + for edge in self.edges.iter() { + edge.to_dot(w)?; + } + + writeln!(w, "}}") + } +} + +#[cfg(test)] +mod tests { + use crate::*; + fn get_test_graph() -> Graph { + let stmts: Vec = vec!["hi".into(), "hell".into()]; + let label1: String = "bb0__0_3".into(); + let style: NodeStyle = Default::default(); + let node1 = Node::new(stmts, label1.clone(), "0".into(), style.clone()); + + let stmts: Vec = vec!["_1 = const 1_i32".into(), "_2 = const 2_i32".into()]; + let label2: String = "bb0__1_3".into(); + let node2 = Node::new(stmts, label2.clone(), "1".into(), style.clone()); + + Graph::new( + "Mir_0_3".into(), + vec![node1, node2], + vec![Edge::new(label1, label2, "return".into())], + ) + } + + #[test] + fn test_adj_list() { + let g = get_test_graph(); + let adj_list = g.adj_list(); + let expected: AdjList = [("bb0__0_3", vec!["bb0__1_3"]), (&"bb0__1_3", vec![])] + .iter() + .cloned() + .collect(); + assert_eq!(adj_list, expected); + } + + #[test] + fn test_json_ser() { + let g = get_test_graph(); + let json = serde_json::to_string(&g).unwrap(); + let expected_json: String = "\ + {\ + \"name\":\"Mir_0_3\",\ + \"nodes\":[\ + {\ + \"stmts\":[\ + \"hi\",\ + \"hell\"\ + ],\ + \"label\":\"bb0__0_3\",\ + \"title\":\"0\",\ + \"style\":{\ + \"title_bg\":null,\ + \"last_stmt_sep\":false\ + }\ + },\ + {\ + \"stmts\":[\ + \"_1 = const 1_i32\",\ + \"_2 = const 2_i32\"\ + ],\ + \"label\":\"bb0__1_3\",\ + \"title\":\"1\",\ + \"style\":{\ + \"title_bg\":null,\ + \"last_stmt_sep\":false\ + }\ + }\ + ],\ + \"edges\":[\ + {\ + \"from\":\"bb0__0_3\",\ + \"to\":\"bb0__1_3\",\ + \"label\":\"return\"\ + }\ + ]\ + }" + .into(); + assert_eq!(json, expected_json) + } + + #[test] + fn test_json_deser() { + let expected = get_test_graph(); + let struct_json: String = "\ + {\ + \"name\":\"Mir_0_3\",\ + \"nodes\":[\ + {\ + \"stmts\":[\ + \"hi\",\ + \"hell\"\ + ],\ + \"label\":\"bb0__0_3\",\ + \"title\":\"0\",\ + \"style\":{\ + \"title_bg\":null,\ + \"last_stmt_sep\":false\ + }\ + },\ + {\ + \"stmts\":[\ + \"_1 = const 1_i32\",\ + \"_2 = const 2_i32\"\ + ],\ + \"label\":\"bb0__1_3\",\ + \"title\":\"1\",\ + \"style\":{\ + \"title_bg\":null,\ + \"last_stmt_sep\":false\ + }\ + }\ + ],\ + \"edges\":[\ + {\ + \"from\":\"bb0__0_3\",\ + \"to\":\"bb0__1_3\",\ + \"label\":\"return\"\ + }\ + ]\ + }" + .into(); + let got: Graph = serde_json::from_str(&struct_json).unwrap(); + + assert_eq!(expected.nodes.len(), got.nodes.len()); + assert_eq!(expected.edges.len(), got.edges.len()); + + for (n1, n2) in expected.nodes.iter().zip(got.nodes.iter()) { + assert_eq!(n1.stmts, n2.stmts); + assert_eq!(n1.label, n2.label); + assert_eq!(n1.title, n2.title); + } + + for (e1, e2) in expected.edges.iter().zip(got.edges.iter()) { + assert_eq!(e1.from, e2.from); + assert_eq!(e1.to, e2.to); + assert_eq!(e1.label, e2.label); + } + } +} diff --git a/vendor/gsgdt/src/levenshtein.rs b/vendor/gsgdt/src/levenshtein.rs new file mode 100644 index 0000000000..8acfefc83a --- /dev/null +++ b/vendor/gsgdt/src/levenshtein.rs @@ -0,0 +1,70 @@ +use std::cmp::min; + +/// Calculate the levenshtein distance between two strings. +pub(crate) fn distance(s1: &str, s2: &str) -> usize { + let v1: Vec = s1.chars().collect(); + let v2: Vec = s2.chars().collect(); + + let l_v1 = v1.len(); + let l_v2 = v2.len(); + + if l_v1 == 0 { + return l_v2; + } + if l_v2 == 0 { + return l_v1; + } + if l_v1 > l_v2 { + return distance(s2, s1); + } + + let mut col: Vec = (0..=l_v1).collect(); + + for i in 1..=l_v2 { + let mut last_diag = col[0]; + col[0] += 1; + for j in 1..=l_v1 { + let last_diag_temp = col[j]; + if v1[j-1] == v2[i-1] { + col[j] = last_diag; + } else { + col[j] = min(last_diag, min(col[j-1], col[j])) + 1; + } + last_diag = last_diag_temp; + } + } + + col[l_v1] +} + + +#[cfg(test)] +mod tests { + use crate::levenshtein::*; + #[test] + fn test1() { + assert_eq!(distance("kitten", "sitting"), 3); + } + + #[test] + fn test_diff_len() { + assert_eq!(distance("kit", "kitten"), 3); + } + + #[test] + fn test_equal() { + assert_eq!(distance("test", "test"), 0); + assert_eq!(distance("", ""), 0); + assert_eq!(distance("long string with space", "long string with space"), 0); + assert_eq!(distance("unicode 😀", "unicode 😀"), 0); + } + + #[test] + fn test_one_empty() { + assert_eq!(distance("test", ""), 4); + assert_eq!(distance("", "test"), 4); + assert_eq!(distance("", ""), 0); + assert_eq!(distance("long string", ""), 11); + assert_eq!(distance("😀", ""), 1); + } +} diff --git a/vendor/gsgdt/src/lib.rs b/vendor/gsgdt/src/lib.rs new file mode 100644 index 0000000000..a361e4979f --- /dev/null +++ b/vendor/gsgdt/src/lib.rs @@ -0,0 +1,12 @@ +#![allow(rustc::default_hash_types)] +mod diff; +mod graph; +mod multi_graph; +mod levenshtein; +mod node; +mod util; + +pub use diff::*; +pub use graph::*; +pub use multi_graph::*; +pub use node::*; diff --git a/vendor/gsgdt/src/multi_graph.rs b/vendor/gsgdt/src/multi_graph.rs new file mode 100644 index 0000000000..f0200a3185 --- /dev/null +++ b/vendor/gsgdt/src/multi_graph.rs @@ -0,0 +1,33 @@ +use crate::graph::*; +use std::io::{self, Write}; +use serde::{Deserialize, Serialize}; + +/// A collection of graphs. +#[derive(Deserialize, Serialize)] +pub struct MultiGraph { + name: String, + graphs: Vec, +} + +impl MultiGraph { + pub fn new(name: String, graphs: Vec) -> MultiGraph { + MultiGraph { name, graphs } + } + + pub fn to_dot(&self, w: &mut W, settings: &GraphvizSettings) -> io::Result<()> { + let subgraphs = self.graphs.len() > 1; + if subgraphs { + writeln!(w, "digraph {} {{", self.name)?; + } + + for graph in &self.graphs { + graph.to_dot(w, settings, subgraphs)?; + } + + if subgraphs { + writeln!(w, "}}")?; + } + + Ok(()) + } +} diff --git a/vendor/gsgdt/src/node.rs b/vendor/gsgdt/src/node.rs new file mode 100644 index 0000000000..c72925b7ab --- /dev/null +++ b/vendor/gsgdt/src/node.rs @@ -0,0 +1,118 @@ +use crate::util::escape_html; +use std::io::{self, Write}; +use serde::{Deserialize, Serialize}; + +/// NodeStyle defines some style of [Node](struct.Node.html) +#[derive(Clone, Serialize, Deserialize)] +pub struct NodeStyle { + /// Override the title color of the title + /// To color the title of the node differently in graphviz + pub title_bg: Option, + + /// Print a seperator b/w the rest of the statements and the last one + pub last_stmt_sep: bool, +} + +impl Default for NodeStyle { + fn default() -> NodeStyle { + NodeStyle { + title_bg: None, + last_stmt_sep: false, + } + } +} + +/// A graph node +#[derive(Clone, Serialize, Deserialize)] +pub struct Node { + /// A list of statements. + pub stmts: Vec, + + /// A unique identifier for the given node. + pub label: String, + + /// The title is printed on the top of BB, the index of the basic block + pub(crate) title: String, + + /// Can be used to override the default styles + pub(crate) style: NodeStyle, +} + +impl Node { + pub fn new(stmts: Vec, label: String, title: String, style: NodeStyle) -> Node { + Node { + stmts, + label, + title, + style, + } + } + + pub fn to_dot(&self, w: &mut W) -> io::Result<()> { + write!(w, r#""#)?; + + let bg_attr = match &self.style.title_bg { + Some(color) => format!(r#"bgcolor="{}""#, color), + None => "".into(), + }; + write!( + w, + r#""#, + attrs = r#"align="center""#, + // TODO: Not sure what this is for + colspan = 1, + blk = self.title, + bg_attr = bg_attr + )?; + + let stmts_len = self.stmts.len(); + if !self.stmts.is_empty() { + if self.stmts.len() > 1 { + write!(w, r#"")?; + } + + if !self.style.last_stmt_sep { + write!(w, r#"")?; + } + + write!(w, "
{blk}
"#)?; + for statement in &self.stmts[..stmts_len - 1] { + write!(w, "{}
", escape_html(statement))?; + } + write!(w, "
"#)?; + write!(w, "{}", escape_html(&self.stmts[stmts_len - 1]))?; + } else { + write!(w, r#"
"#)?; + write!(w, "{}", escape_html(&self.stmts[stmts_len - 1]))?; + } + write!(w, "
") + } +} + +/// A directed graph edge +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Edge { + /// The label of the source node of the edge. + pub from: String, + + /// The label of the target node of the edge. + pub to: String, + + /// The label (title) of the edge. This doesn't have to unique. + // TODO: Rename this to title? + pub label: String, +} + +impl Edge { + pub fn new(from: String, to: String, label: String) -> Edge { + Edge { from, to, label } + } + + pub fn to_dot(&self, w: &mut W) -> io::Result<()> { + writeln!( + w, + r#" {} -> {} [label="{}"];"#, + self.from, self.to, self.label + ) + } +} diff --git a/vendor/gsgdt/src/util.rs b/vendor/gsgdt/src/util.rs new file mode 100644 index 0000000000..f6fcf08f65 --- /dev/null +++ b/vendor/gsgdt/src/util.rs @@ -0,0 +1,6 @@ +pub fn escape_html(s: &str) -> String { + s.replace("&", "&") + .replace("\"", """) + .replace("<", "<") + .replace(">", ">") +} diff --git a/vendor/gsgdt/tests/graph1.json b/vendor/gsgdt/tests/graph1.json new file mode 100644 index 0000000000..f6381d78a5 --- /dev/null +++ b/vendor/gsgdt/tests/graph1.json @@ -0,0 +1,513 @@ +{ + "name": "Mir_0_3", + "kind": "Digraph", + "nodes": [ + { + "label": "bb0", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb0", + "stmts": [ + "StorageLive(_1)", + "_1 = Vec::::new()" + ] + }, + { + "label": "bb1", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb1", + "stmts": [ + "resume" + ] + }, + { + "label": "bb2", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb2", + "stmts": [ + "StorageLive(_2)", "StorageLive(_3)", "(_3.0: i32) = const 1_i32", "(_3.1: i32) = const 10_i32", + "_2 = as IntoIterator>::into_iter(move _3)" + ] + }, + { + "label": "bb3", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb3", + "stmts": [ + "StorageDead(_3)", "StorageLive(_4)", "_4 = move _2", + "goto" + ] + }, + { + "label": "bb4", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb4", + "stmts": [ + "drop(_1)" + ] + }, + { + "label": "bb5", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb5", + "stmts": [ + "StorageLive(_5)", "StorageLive(_6)", "StorageLive(_7)", "StorageLive(_8)", "_8 = &mut _4", "_7 = &mut (*_8)", + "_6 = as Iterator>::next(move _7)" + ] + }, + { + "label": "bb6", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb6", + "stmts": [ + "StorageDead(_7)", "_9 = discriminant(_6)", + "switchInt(move _9)" + ] + }, + { + "label": "bb7", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb7", + "stmts": [ + "StorageDead(_8)", "StorageDead(_6)", "StorageDead(_5)", "StorageDead(_4)", "StorageDead(_2)", "StorageLive(_21)", "StorageLive(_22)", "(_22.0: i32) = const 1_i32", "(_22.1: i32) = const 10_i32", + "_21 = as IntoIterator>::into_iter(move _22)" + ] + }, + { + "label": "bb8", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb8", + "stmts": [ + "unreachable" + ] + }, + { + "label": "bb9", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb9", + "stmts": [ + "StorageLive(_10)", "_10 = ((_6 as Some).0: i32)", "StorageLive(_11)", "_11 = _10", "_5 = move _11", "StorageDead(_11)", "StorageDead(_10)", "StorageDead(_8)", "StorageDead(_6)", "StorageLive(_12)", "_12 = _5", "StorageLive(_13)", "StorageLive(_14)", "_14 = _12", "_15 = const false", "_16 = Eq(_14, const i32::MIN)", "_17 = BitAnd(move _15, move _16)", + "assert(!move _17, \"attempt to compute the remainder of `{} % {}` which would overflow\", _14, const 2_i32)" + ] + }, + { + "label": "bb10", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb10", + "stmts": [ + "_13 = Rem(move _14, const 2_i32)", "StorageDead(_14)", + "switchInt(move _13)" + ] + }, + { + "label": "bb11", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb11", + "stmts": [ + "StorageDead(_13)", + "goto" + ] + }, + { + "label": "bb12", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb12", + "stmts": [ + "StorageDead(_13)", "StorageLive(_18)", "StorageLive(_19)", "_19 = &mut _1", "StorageLive(_20)", "_20 = _12", + "_18 = Vec::::push(move _19, move _20)" + ] + }, + { + "label": "bb13", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb13", + "stmts": [ + "StorageDead(_20)", "StorageDead(_19)", "StorageDead(_18)", + "goto" + ] + }, + { + "label": "bb14", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb14", + "stmts": [ + "StorageDead(_12)", "StorageDead(_5)", + "goto" + ] + }, + { + "label": "bb15", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb15", + "stmts": [ + "StorageDead(_22)", "StorageLive(_23)", "_23 = move _21", + "goto" + ] + }, + { + "label": "bb16", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb16", + "stmts": [ + "StorageLive(_24)", "StorageLive(_25)", "StorageLive(_26)", "StorageLive(_27)", "_27 = &mut _23", "_26 = &mut (*_27)", + "_25 = as Iterator>::next(move _26)" + ] + }, + { + "label": "bb17", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb17", + "stmts": [ + "StorageDead(_26)", "_28 = discriminant(_25)", + "switchInt(move _28)" + ] + }, + { + "label": "bb18", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb18", + "stmts": [ + "_0 = const ()", "StorageDead(_27)", "StorageDead(_25)", "StorageDead(_24)", "StorageDead(_23)", "StorageDead(_21)", + "drop(_1)" + ] + }, + { + "label": "bb19", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb19", + "stmts": [ + "unreachable" + ] + }, + { + "label": "bb20", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb20", + "stmts": [ + "StorageLive(_29)", "_29 = ((_25 as Some).0: i32)", "StorageLive(_30)", "_30 = _29", "_24 = move _30", "StorageDead(_30)", "StorageDead(_29)", "StorageDead(_27)", "StorageDead(_25)", "StorageLive(_31)", "_31 = _24", "StorageLive(_32)", "StorageLive(_33)", "_33 = _31", "_34 = const false", "_35 = Eq(_33, const i32::MIN)", "_36 = BitAnd(move _34, move _35)", + "assert(!move _36, \"attempt to compute the remainder of `{} % {}` which would overflow\", _33, const 3_i32)" + ] + }, + { + "label": "bb21", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb21", + "stmts": [ + "_32 = Rem(move _33, const 3_i32)", "StorageDead(_33)", + "switchInt(move _32)" + ] + }, + { + "label": "bb22", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb22", + "stmts": [ + "StorageDead(_32)", + "goto" + ] + }, + { + "label": "bb23", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb23", + "stmts": [ + "StorageDead(_32)", "StorageLive(_37)", "StorageLive(_38)", "_38 = &mut _1", "StorageLive(_39)", "_39 = _31", + "_37 = Vec::::push(move _38, move _39)" + ] + }, + { + "label": "bb24", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb24", + "stmts": [ + "StorageDead(_39)", "StorageDead(_38)", "StorageDead(_37)", + "goto" + ] + }, + { + "label": "bb25", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb25", + "stmts": [ + "StorageDead(_31)", "StorageDead(_24)", + "goto" + ] + }, + { + "label": "bb26", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb26", + "stmts": [ + "StorageDead(_1)", + "return" + ] + } + ], + "edges": [ + { + "from": "bb0", + "to": "bb2", + "label": "return" + }, + { + "from": "bb2", + "to": "bb3", + "label": "return" + }, + { + "from": "bb2", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb3", + "to": "bb5", + "label": "" + }, + { + "from": "bb4", + "to": "bb1", + "label": "return" + }, + { + "from": "bb5", + "to": "bb6", + "label": "return" + }, + { + "from": "bb5", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb6", + "to": "bb7", + "label": "0_isize" + }, + { + "from": "bb6", + "to": "bb9", + "label": "1_isize" + }, + { + "from": "bb6", + "to": "bb8", + "label": "otherwise" + }, + { + "from": "bb7", + "to": "bb15", + "label": "return" + }, + { + "from": "bb7", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb9", + "to": "bb10", + "label": "success" + }, + { + "from": "bb9", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb10", + "to": "bb12", + "label": "0_i32" + }, + { + "from": "bb10", + "to": "bb11", + "label": "otherwise" + }, + { + "from": "bb11", + "to": "bb14", + "label": "" + }, + { + "from": "bb12", + "to": "bb13", + "label": "return" + }, + { + "from": "bb12", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb13", + "to": "bb14", + "label": "" + }, + { + "from": "bb14", + "to": "bb5", + "label": "" + }, + { + "from": "bb15", + "to": "bb16", + "label": "" + }, + { + "from": "bb16", + "to": "bb17", + "label": "return" + }, + { + "from": "bb16", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb17", + "to": "bb18", + "label": "0_isize" + }, + { + "from": "bb17", + "to": "bb20", + "label": "1_isize" + }, + { + "from": "bb17", + "to": "bb19", + "label": "otherwise" + }, + { + "from": "bb18", + "to": "bb26", + "label": "return" + }, + { + "from": "bb20", + "to": "bb21", + "label": "success" + }, + { + "from": "bb20", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb21", + "to": "bb23", + "label": "0_i32" + }, + { + "from": "bb21", + "to": "bb22", + "label": "otherwise" + }, + { + "from": "bb22", + "to": "bb25", + "label": "" + }, + { + "from": "bb23", + "to": "bb24", + "label": "return" + }, + { + "from": "bb23", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb24", + "to": "bb25", + "label": "" + }, + { + "from": "bb25", + "to": "bb16", + "label": "" + } + ] +} diff --git a/vendor/gsgdt/tests/graph2.json b/vendor/gsgdt/tests/graph2.json new file mode 100644 index 0000000000..3ca1cac2e4 --- /dev/null +++ b/vendor/gsgdt/tests/graph2.json @@ -0,0 +1,297 @@ +{ + "name": "Mir_0_3", + "kind": "Digraph", + "nodes": [ + { + "label": "bb0", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb0", + "stmts": [ + "StorageLive(_1)", + "_1 = Vec::::new()" + ] + }, + { + "label": "bb1", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb1", + "stmts": [ + "resume" + ] + }, + { + "label": "bb2", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb2", + "stmts": [ + "StorageLive(_2)", "StorageLive(_3)", "(_3.0: i32) = const 1_i32", "(_3.1: i32) = const 10_i32", + "_2 = as IntoIterator>::into_iter(move _3)" + ] + }, + { + "label": "bb3", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb3", + "stmts": [ + "StorageDead(_3)", "StorageLive(_4)", "_4 = move _2", + "goto" + ] + }, + { + "label": "bb4", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb4", + "stmts": [ + "drop(_1)" + ] + }, + { + "label": "bb5", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb5", + "stmts": [ + "StorageLive(_5)", "StorageLive(_6)", "StorageLive(_7)", "StorageLive(_8)", "_8 = &mut _4", "_7 = &mut (*_8)", + "_6 = as Iterator>::next(move _7)" + ] + }, + { + "label": "bb6", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb6", + "stmts": [ + "StorageDead(_7)", "_9 = discriminant(_6)", + "switchInt(move _9)" + ] + }, + { + "label": "bb7", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb7", + "stmts": [ + "_0 = const ()", "StorageDead(_8)", "StorageDead(_6)", "StorageDead(_5)", "StorageDead(_4)", "StorageDead(_2)", + "drop(_1)" + ] + }, + { + "label": "bb8", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb8", + "stmts": [ + "unreachable" + ] + }, + { + "label": "bb9", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb9", + "stmts": [ + "StorageLive(_10)", "_10 = ((_6 as Some).0: i32)", "StorageLive(_11)", "_11 = _10", "_5 = move _11", "StorageDead(_11)", "StorageDead(_10)", "StorageDead(_8)", "StorageDead(_6)", "StorageLive(_12)", "_12 = _5", "StorageLive(_13)", "StorageLive(_14)", "_14 = _12", "_15 = const false", "_16 = Eq(_14, const i32::MIN)", "_17 = BitAnd(move _15, move _16)", + "assert(!move _17, \"attempt to compute the remainder of `{} % {}` which would overflow\", _14, const 3_i32)" + ] + }, + { + "label": "bb10", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb10", + "stmts": [ + "_13 = Rem(move _14, const 3_i32)", "StorageDead(_14)", + "switchInt(move _13)" + ] + }, + { + "label": "bb11", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb11", + "stmts": [ + "StorageDead(_13)", + "goto" + ] + }, + { + "label": "bb12", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb12", + "stmts": [ + "StorageDead(_13)", "StorageLive(_18)", "StorageLive(_19)", "_19 = &mut _1", "StorageLive(_20)", "_20 = _12", + "_18 = Vec::::push(move _19, move _20)" + ] + }, + { + "label": "bb13", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb13", + "stmts": [ + "StorageDead(_20)", "StorageDead(_19)", "StorageDead(_18)", + "goto" + ] + }, + { + "label": "bb14", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb14", + "stmts": [ + "StorageDead(_12)", "StorageDead(_5)", + "goto" + ] + }, + { + "label": "bb15", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb15", + "stmts": [ + "StorageDead(_1)", + "return" + ] + } + ], + "edges": [ + { + "from": "bb0", + "to": "bb2", + "label": "return" + }, + { + "from": "bb2", + "to": "bb3", + "label": "return" + }, + { + "from": "bb2", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb3", + "to": "bb5", + "label": "" + }, + { + "from": "bb4", + "to": "bb1", + "label": "return" + }, + { + "from": "bb5", + "to": "bb6", + "label": "return" + }, + { + "from": "bb5", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb6", + "to": "bb7", + "label": "0_isize" + }, + { + "from": "bb6", + "to": "bb9", + "label": "1_isize" + }, + { + "from": "bb6", + "to": "bb8", + "label": "otherwise" + }, + { + "from": "bb7", + "to": "bb15", + "label": "return" + }, + { + "from": "bb9", + "to": "bb10", + "label": "success" + }, + { + "from": "bb9", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb10", + "to": "bb12", + "label": "0_i32" + }, + { + "from": "bb10", + "to": "bb11", + "label": "otherwise" + }, + { + "from": "bb11", + "to": "bb14", + "label": "" + }, + { + "from": "bb12", + "to": "bb13", + "label": "return" + }, + { + "from": "bb12", + "to": "bb4", + "label": "unwind" + }, + { + "from": "bb13", + "to": "bb14", + "label": "" + }, + { + "from": "bb14", + "to": "bb5", + "label": "" + } + ] +} diff --git a/vendor/gsgdt/tests/helpers.rs b/vendor/gsgdt/tests/helpers.rs new file mode 100644 index 0000000000..2184e1c88d --- /dev/null +++ b/vendor/gsgdt/tests/helpers.rs @@ -0,0 +1,14 @@ +use gsgdt; +use serde_json; + +use std::fs::File; +use std::io::prelude::*; + +use gsgdt::*; + +pub fn read_graph_from_file(file: &str) -> Graph{ + let mut file = File::open(file).unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + serde_json::from_str(&contents).unwrap() +} diff --git a/vendor/gsgdt/tests/small_graph.json b/vendor/gsgdt/tests/small_graph.json new file mode 100644 index 0000000000..c12b2f3517 --- /dev/null +++ b/vendor/gsgdt/tests/small_graph.json @@ -0,0 +1,36 @@ +{ + "name": "small", + "kind": "Digraph", + "nodes": [ + { + "label": "bb0", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb0", + "stmts": [ + "StorageLive(_1)", + "_1 = Vec::::new()" + ] + }, + { + "label": "bb1", + "style": { + "title_bg": null, + "last_stmt_sep": false + }, + "title": "bb1", + "stmts": [ + "resume" + ] + } + ], + "edges": [ + { + "from": "bb0", + "to": "bb1", + "label": "return" + } + ] +} diff --git a/vendor/gsgdt/tests/test_diff.rs b/vendor/gsgdt/tests/test_diff.rs new file mode 100644 index 0000000000..cdca5609af --- /dev/null +++ b/vendor/gsgdt/tests/test_diff.rs @@ -0,0 +1,57 @@ +use gsgdt; +mod helpers; +use helpers::*; + +use gsgdt::*; + +#[test] +fn test_diff_2() { + let g1 = read_graph_from_file("tests/graph1.json"); + let g2 = read_graph_from_file("tests/graph2.json"); + + let d1 = DiffGraph::new(&g1); + let d2 = DiffGraph::new(&g2); + let mapping = match_graphs(&d1, &d2); + let expected = vec![ + Match::Full(Matching::new("bb0", "bb0")), + Match::Full(Matching::new("bb1", "bb1")), + Match::Full(Matching::new("bb10", "bb10")), + Match::Full(Matching::new("bb11", "bb11")), + Match::Full(Matching::new("bb12", "bb12")), + Match::Full(Matching::new("bb13", "bb13")), + Match::Full(Matching::new("bb14", "bb14")), + Match::Full(Matching::new("bb18", "bb7")), + Match::Full(Matching::new("bb2", "bb2")), + Match::Full(Matching::new("bb26", "bb15")), + Match::Full(Matching::new("bb3", "bb3")), + Match::Full(Matching::new("bb4", "bb4")), + Match::Full(Matching::new("bb5", "bb5")), + Match::Full(Matching::new("bb6", "bb6")), + Match::Full(Matching::new("bb8", "bb8")), + Match::Full(Matching::new("bb9", "bb9")), + ]; + + // dbg!("{:#?}", mapping); + assert_eq!(mapping, expected); + + let settings: GraphvizSettings = Default::default(); + let mut f1 = std::fs::File::create("test1.dot").expect("create failed"); + let mut f2 = std::fs::File::create("test2.dot").expect("create failed"); + g1.to_dot(&mut f1, &settings, false).expect("can't fail"); + g2.to_dot(&mut f2, &settings, false).expect("can't fail"); +} + +#[test] +fn test_diff_vis() { + let g1 = read_graph_from_file("tests/graph1.json"); + let g2 = read_graph_from_file("tests/graph2.json"); + + let d1 = DiffGraph::new(&g1); + let d2 = DiffGraph::new(&g2); + let settings: GraphvizSettings = Default::default(); + + let mut f1 = std::fs::File::create("test1.dot").expect("create failed"); + let mg = visualize_diff(&d2, &d1); + + mg.to_dot(&mut f1, &settings).unwrap(); +} diff --git a/vendor/gsgdt/tests/test_graph.rs b/vendor/gsgdt/tests/test_graph.rs new file mode 100644 index 0000000000..afd21c622b --- /dev/null +++ b/vendor/gsgdt/tests/test_graph.rs @@ -0,0 +1,18 @@ +use gsgdt::*; +mod helpers; +use helpers::*; + +#[test] +fn test_graph_render() { + let g1 = read_graph_from_file("tests/small_graph.json"); + let settings: GraphvizSettings = Default::default(); + let mut buf = Vec::new(); + let expected = r#"digraph small { + bb0 [shape="none", label=<
bb0
StorageLive(_1)
_1 = Vec::<i32>::new()
>]; + bb1 [shape="none", label=<
bb1
resume
>]; + bb0 -> bb1 [label="return"]; +} +"#; + g1.to_dot(&mut buf, &settings, false).unwrap(); + assert_eq!(String::from_utf8(buf).unwrap(), expected); +} diff --git a/vendor/gsgdt/tests/test_multigraph.rs b/vendor/gsgdt/tests/test_multigraph.rs new file mode 100644 index 0000000000..a46a18423b --- /dev/null +++ b/vendor/gsgdt/tests/test_multigraph.rs @@ -0,0 +1,28 @@ +use gsgdt::*; +mod helpers; +use helpers::*; + +#[test] +fn test_multigraph_render() { + let g1 = read_graph_from_file("tests/small_graph.json"); + let g2 = read_graph_from_file("tests/small_graph.json"); + let settings: GraphvizSettings = Default::default(); + + let mg = MultiGraph::new("testgraph".into(), vec![g1, g2]); + let mut buf = Vec::new(); + let expected = r#"digraph testgraph { +subgraph cluster_small { + bb0 [shape="none", label=<
bb0
StorageLive(_1)
_1 = Vec::<i32>::new()
>]; + bb1 [shape="none", label=<
bb1
resume
>]; + bb0 -> bb1 [label="return"]; +} +subgraph cluster_small { + bb0 [shape="none", label=<
bb0
StorageLive(_1)
_1 = Vec::<i32>::new()
>]; + bb1 [shape="none", label=<
bb1
resume
>]; + bb0 -> bb1 [label="return"]; +} +} +"#; + mg.to_dot(&mut buf, &settings).unwrap(); + assert_eq!(String::from_utf8(buf).unwrap(), expected); +} diff --git a/vendor/libc/.cargo-checksum.json b/vendor/libc/.cargo-checksum.json index 083640d91c..e97fa39f8c 100644 --- a/vendor/libc/.cargo-checksum.json +++ b/vendor/libc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"3a9f0037ad5f1198eada74a9d0363925ef09db664380b0e5a2840f03da260476","Cargo.toml":"2d34a451c2f1190e6eb72caa6387f7fd4947e1a60e7f248cff82a9f497867deb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"82011c39a455c4ba6fc81db69eac78225e697f4596eb29a1ac3da3a43a204f80","build.rs":"e487789ca77b0015d75cecb253286d4a1406f11b1ae538929414fc0506842bef","rustfmt.toml":"8a654d5787585ca8f2c20580737336fc327f411a07b0dbd4870adf6e9bdf624f","src/cloudabi/aarch64.rs":"b8550bf1fd7344972aa4db29441486f39f31482d0327534981dbb75959c29114","src/cloudabi/arm.rs":"c197e2781c2839808bd6fcef219a29705b27b992d3ef920e9cf6ac96e2022bbf","src/cloudabi/mod.rs":"d5d4488e8c0b8227f516fe13810f550a2a72af3bdfe769200ad8687c8755bdf6","src/cloudabi/x86.rs":"33eb97f272d2201f3838ae74d444583c7de8f67856852ca375293b20bbd05636","src/cloudabi/x86_64.rs":"400d85d4fe39e26cf2e6ece9ee31c75fe9e88c4bcf4d836ca9f765c05c9c5be3","src/fixed_width_ints.rs":"34c60f12ec5eeb90f13ec3b954427532111c2446e69617616a97aefc1086a9f1","src/fuchsia/aarch64.rs":"378776a9e40766154a54c94c2a7b4675b5c302a38e6e42da99e67bfbaee60e56","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"2bfb6ffad0170b3f56b9033a4c9ae2a3a3bb04b0ecb92cbdde7fafa7e868ca3e","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"d3bfce41e4463d4be8020a2d063c9bfa8b665f45f1cc6cbf3163f5d01e7cb21f","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"8aeb4106f57e956eb51f7a8dd06f299695c8738cf8adc20ac786b524615cedb5","src/macros.rs":"f024ec4ccd3762d4da198f14718d15a3ef70207f63aa3dceabf0de480fe780e9","src/psp.rs":"a621e34d2d31d9b29c725897b846122acce4763ac2017a1fe2200b133e5ad064","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"6a4ce300da0d2b0db04b18548286603ffe4b47d679a41cf60f1902895894aa1f","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"81254d89be1febc5bb20e787d014a624950d56e2e14973df5bbebfdabc95ae20","src/unix/bsd/apple/mod.rs":"9c6ba890cfd1f4ea834fc97260c79467cfcaaccf9c1d019347d50fec5c19f197","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"63f22519f7f4b18152f912c03b860532114b8726832c40b5590def6f02eeb13a","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"86a0e11f928db7c8587e94ea3ba5801025526ed9a35d8d592c2705f96df05c22","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"14f0bd6693967d4fedec904f7042bd51f2138cb843ec4df18c911b357417cdd2","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"16dd3e1a09f123d0aa544b3fd7c123654b4906cac94838fbed7f34a64413c930","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"c6152ce3db241d99e350d34352f3f3d167953ef0ee08bfbe2685cb9ebde2e83b","src/unix/bsd/freebsdlike/freebsd/mod.rs":"c4d73339fda63f145134e9dc21bb40d96ba15c84fc62fb27bf90ba4db5e0f5d8","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/x86.rs":"c5005e3249eb7c93cfbac72a9e9272320d80ce7983da990ceb05a447f59a02c5","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"6132aa0973454379674ea6cbc77e6eace1e1032dd9f38182071388a036f1bc08","src/unix/bsd/freebsdlike/mod.rs":"a45d3095966dff5142d0b292a416a004c78d5689bb38ab7c8d4497b9b310e02f","src/unix/bsd/mod.rs":"4fd08b1fe9c9f74b50e8405a60dd506a6910190fbfbae7e968f1d9848f2b328e","src/unix/bsd/netbsdlike/mod.rs":"48dd60524119c1e09b255d5472d091e7e7b2b29eab04be51b4b1e740bd022859","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"b38fc046f9a40fea28bd26328b96629f4d5d63d7524936bd6af1865d401a8716","src/unix/bsd/netbsdlike/netbsd/arm.rs":"58cdbb70b0d6f536551f0f3bb3725d2d75c4690db12c26c034e7d6ec4a924452","src/unix/bsd/netbsdlike/netbsd/mod.rs":"d22dafd49e3b760a7644a7722f73f80434ddf64ab40cd7c3bd476c2e62eaeb16","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"135509edeaf3fb3f102d89d51ff1a8f82323497336a8dc7e1f0f23b5c2434b73","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/mod.rs":"ebe8abc57672e55ab22d5ca5ef7735eb79a41a0fcae0020d0f9b52744b960693","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"e59b7fd65f68f8e857eec39e0c03bac1d3af6ddc26c9ba58494336b83659bb9b","src/unix/haiku/b32.rs":"69ae47fc52c6880e85416b4744500d5655c9ec6131cb737f3b649fceaadce15a","src/unix/haiku/b64.rs":"73e64db09275a8da8d50a13cce2cfa2b136036ddf3a930d2939f337fc995900b","src/unix/haiku/mod.rs":"ecd6139a3656a2fb13e66fed8bed9dfceafea48c169b1fa533b9e1b09a8b18eb","src/unix/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/unix/hermit/mod.rs":"2d8d3ce0299931199011bb73136bebbddf88edf7d263cc39d26dbfaaa1a14228","src/unix/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/unix/linux_like/android/b32/arm.rs":"155994121906903a2e0afad895f0b3b7546f6e54d6305a3336ce2c4dfafbfdfa","src/unix/linux_like/android/b32/mod.rs":"0325adf3364fed7157fff5b24fabe1b36d806c39ee04ec82dd29a606d28f91f6","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"5b1e9fcd77ca5f939acb7fb5f5da12f305b0377698d8b8989feb236e26360aa0","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/mod.rs":"655116966eb7846b933e5e28b073c329668588cd3c2120cc9ce60c697bd19978","src/unix/linux_like/android/b64/mod.rs":"6a71abfcbbcdae60c916de41cd4688d5f25bdbca83d1d9df49decd56ad726a06","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"e84176d838e663d351450bad218715db1fafbb531e47ea0e262cbb45829dae89","src/unix/linux_like/android/mod.rs":"c6de4534c41d296519f31bee06fd6f06c0a07cd766bb0bd3421c3f897d84caa2","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/mod.rs":"aeedf3c777bef979673f5bbaa373aa308ace6d25c33c23524d01cf7628587955","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"015ec9e064bf7dee63b5a16e6d87aef11aeeeea84a3b083f9e75a97bb7ab2f0b","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"9e18ad197709bce3aab40537b6ea371ff13f3be7be1d50ff97964f937c517646","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"5cf043f5342c37b1cf50bc09de9baaa8d120a8827640f328a74ebbff1fe5aca0","src/unix/linux_like/linux/gnu/b32/mod.rs":"d7e392843f0a9a838566015192dbb8af7d1a5883a85547fa888b6ded78882087","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"5457ff8f90fb777cfc3cbe6c0c6a3b3f8eaecb28e66fffc53390e82010030ebe","src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs":"7b2528fdcdbbfb5cd350b27a3f66a6950fb94be1c924c1156a1d93e8950496a1","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"796cf3eeb7319bef33afdb9c88caff8a3476842757381f75699e761aa01b89e3","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"b1005390da3ed2d95b612fdcc4b69f11165ce31cfbf50674fe877ed47ad1b431","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"e73a372b096951030ae7db4f0ad0c5a472ccd8f21973d61811b8441eaf5229af","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"e86403f310a14fc5355dd78746ac55056c91fa7cd3248d5d8a18430b4940cb2d","src/unix/linux_like/linux/gnu/b64/mod.rs":"b90d87f76bff37707a1725551fe45d70d0c106e01b1dbbcd5f60460e0a19b4c3","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"8aaaa4d9a5f79a7413930632c47382e845789dd9a191dc8bf084c8041ee350b1","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"b954a060f88cd03d0ca8bdeb864046230d0c52e2d2ab97394430f1356a357a82","src/unix/linux_like/linux/gnu/b64/s390x.rs":"818bdc54fdcb9d83190d78f31d0f4a082d06ded112ccb40daa1ab4c541ee58d5","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"22e57216290614616c671f35e24e881d6fcf9839dbfa8d2833a1a77ada28d156","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"e6197537739cb8628cad25827081c8bf6b371c02ad4b2132b30b9ae74143b1ef","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"74deaf2135168fd8a8fe3382a443d3800b95ea833e94150b265cc59a24872166","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"60ff6e9aca19226714cf0c7f58f4388f5f046cf099cc4f61f9a2913d94d7e846","src/unix/linux_like/linux/gnu/mod.rs":"714363d630eb8633390003721b5df6f49c867317077372254884d7537a3ecd3c","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"a8e9bd6e5567e81500ba9110b3d2835fd54572e7b7f33c1fd7740a09271d6ee9","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"45062a178b382ab17341a69d027b5c83325c4e79fecf45729ba9c47b1bcdc3da","src/unix/linux_like/linux/musl/b32/hexagon.rs":"7c6c481f70da1fe6ca759f363784e130041f3d87906c45910fc1142b5ef17970","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"9eb0e4953be5afaa0b9e3ac54c85ed40583cfb8cc0b03264b9bc8f763a8f3254","src/unix/linux_like/linux/musl/b32/mod.rs":"8ede3985e6243882814ce91e8ce543e7edbafc0cee5932816072b6f14207a671","src/unix/linux_like/linux/musl/b32/powerpc.rs":"cf286cbf4d2076aaa82662ace2b5c333480410fa59af5cb4542d59f04da84b31","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"9c3b6e98e7710d6c877a4e31726d36416115a58f53fc469bb173b7fe660b39e5","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"22da1c030c254c511bc335c824d40b693904975a4633f8243a8777ca68ef1c65","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"9870fd9a953c98b775c9e17a29a66bbe8019a6236eb69a0272f42232a226521d","src/unix/linux_like/linux/musl/b64/mips64.rs":"9d0158ac7a913222d0a62239ec043aa1aee73522a7a1e0e191d0642dde35c083","src/unix/linux_like/linux/musl/b64/mod.rs":"8b76e92a1505ad785d4aa0b7739e0b93647a1e81910949b49cedb6c88468be9c","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"ed9b879bb9cdc526ad83815875edeb4cad4e8829086dfba2578277c265336229","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"cfeb109c732ac6bc7d2be44069d3652e917a0509b8b545270b756ff2d52e27e8","src/unix/linux_like/linux/musl/mod.rs":"243e32b93641df7a77f970a32c0fb8e4fd4a13720e54e0e42a9da321fd169798","src/unix/linux_like/linux/no_align.rs":"5ed04c53bf9d27da9b4d65ba7625c6ac53330162683d1b3df98950caafa3507b","src/unix/linux_like/mod.rs":"377bf039b6bcdea77173687cb1e2d12d52548fd1b1b0d4113130da787684c145","src/unix/mod.rs":"856ba2bcba40d5d926ded8b6de9bf697bc5d2bd7e56ea01f73b10ea34b417435","src/unix/newlib/aarch64/mod.rs":"bb269c1468a9676442554600e87417079a787fe6220dfc23b3109639259e8710","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"c71be856bfd7f576b2db28af9f680211cbe6c1cac7d537bbc8020b39591af07c","src/unix/newlib/mod.rs":"2f771ab23df36ab0c7a117e854483a917aaf9c5cbb9eded1bdda35827cdaf734","src/unix/newlib/no_align.rs":"7123dcec13604a11b7765c380ff3a4d0da19c39f4b03919de7857723c0cf1502","src/unix/newlib/powerpc/mod.rs":"2d0f7af28b47f7a2a6c210ebd1c1f33ed8eac62e56b5af2b856de2ad3fdc5187","src/unix/newlib/xtensa/mod.rs":"4c72003c5e692e648c7e798358c49af6901e68850dbba0624af84c40baf208f5","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/redox/mod.rs":"c6ac0812f85046e40f691357da8a1cbd72572bdb0f913c24aac106d7aa4ac240","src/unix/solarish/compat.rs":"3f13657fc072462b85b5f937f0db1427c41acb2a714cc4f78fefba1ea8036846","src/unix/solarish/illumos.rs":"1088c45b238e7d398dbb140d238257d5b5f93aeded98652c3f6747f0c07b4fa7","src/unix/solarish/mod.rs":"0134ce769d06b1b1f50ad15d1aa7bd8d44bcd2f66c6318dd906de8bc4a4044c7","src/unix/solarish/solaris.rs":"5914ded3ce8ec5638bb023d4cde147f016d736d5006964a1ef9839752ecb45f8","src/unix/uclibc/align.rs":"a8540e1cce5913a45bc8d7422b79e86c0b12740e8a679478e0e4d863a31f8cc1","src/unix/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/arm/mod.rs":"d67dd46bc6f417169fc6a23832bde7ccdafc5d1bcb08b10debdd82edaf75d529","src/unix/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/mips/mips32/mod.rs":"a045ebc6619f540adf670b88a987abd2d6e42e440a552e8cfe9f8c77f397e873","src/unix/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/uclibc/mips/mips64/mod.rs":"e3085ba56cfbc528d7c3c55065880603238c333b6047ef51c58177508a487fcd","src/unix/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/uclibc/mips/mod.rs":"1054d0bfeb506b3346b9a4148564beced8a22da0d9c9a612101f6237756795fb","src/unix/uclibc/mod.rs":"907805e356738075844a704ef2eec8cfd628c59bb1408d3fff66e8f9ba36e4ba","src/unix/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/uclibc/x86_64/align.rs":"4e34cebb7955e9c98ae2f310be6f8ed16a861fc3817c08543867554aeec9524e","src/unix/uclibc/x86_64/l4re.rs":"bb31053d6403091e11f95ac2203982f279f8b984a19adf30796878c45fdd8c25","src/unix/uclibc/x86_64/mod.rs":"188fbaf06a8e23cac72718b1ef7eb4bd98bdfd946aa708151f3f7e3553b65876","src/unix/uclibc/x86_64/no_align.rs":"2ccc0107a6007c70dc49e656095b64a352ca5d8f9f3e65c1dba634effbc15636","src/unix/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"b7c57b72a0f312c20531ba393f6fab7331fb708170d141d898d705868a5ee780","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"11e1ca29d1a446845c551d5717ec5c6081459a2a850781c9194f557d53ecf44f","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"c7ab9793baaa3b6854d25fdf44266b7953533009e4fa722ca717b71d3e5d2c9d","src/windows/mod.rs":"7b74bf885712d16a3557df33ef02799dc03d4a1af953c7e6b4648954ce7a20fc","src/windows/msvc.rs":"2c2bfce66027d88021e7289139ebf5b0db258a7b6443f18872c84dbd4ef57131","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"3a9f0037ad5f1198eada74a9d0363925ef09db664380b0e5a2840f03da260476","Cargo.toml":"cf936c88d7ae9c45d8cf8c93983e67faffde29d20cfec334750998584a9c274c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"73041c7dda55cca7e18bcaf115d28090c8d3c2373a19ecef82fadeab292a607b","build.rs":"e487789ca77b0015d75cecb253286d4a1406f11b1ae538929414fc0506842bef","rustfmt.toml":"8a654d5787585ca8f2c20580737336fc327f411a07b0dbd4870adf6e9bdf624f","src/cloudabi/aarch64.rs":"b8550bf1fd7344972aa4db29441486f39f31482d0327534981dbb75959c29114","src/cloudabi/arm.rs":"c197e2781c2839808bd6fcef219a29705b27b992d3ef920e9cf6ac96e2022bbf","src/cloudabi/mod.rs":"d5d4488e8c0b8227f516fe13810f550a2a72af3bdfe769200ad8687c8755bdf6","src/cloudabi/x86.rs":"33eb97f272d2201f3838ae74d444583c7de8f67856852ca375293b20bbd05636","src/cloudabi/x86_64.rs":"400d85d4fe39e26cf2e6ece9ee31c75fe9e88c4bcf4d836ca9f765c05c9c5be3","src/fixed_width_ints.rs":"34c60f12ec5eeb90f13ec3b954427532111c2446e69617616a97aefc1086a9f1","src/fuchsia/aarch64.rs":"378776a9e40766154a54c94c2a7b4675b5c302a38e6e42da99e67bfbaee60e56","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"2bfb6ffad0170b3f56b9033a4c9ae2a3a3bb04b0ecb92cbdde7fafa7e868ca3e","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"d3bfce41e4463d4be8020a2d063c9bfa8b665f45f1cc6cbf3163f5d01e7cb21f","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"8aeb4106f57e956eb51f7a8dd06f299695c8738cf8adc20ac786b524615cedb5","src/macros.rs":"7844312c233a6889fa15395fe3106f6a8f6229211104a92f33ea3c9536eef763","src/psp.rs":"a621e34d2d31d9b29c725897b846122acce4763ac2017a1fe2200b133e5ad064","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"6a4ce300da0d2b0db04b18548286603ffe4b47d679a41cf60f1902895894aa1f","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"81254d89be1febc5bb20e787d014a624950d56e2e14973df5bbebfdabc95ae20","src/unix/bsd/apple/mod.rs":"9c6ba890cfd1f4ea834fc97260c79467cfcaaccf9c1d019347d50fec5c19f197","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"8295b8bb0dfd38d2cdb4d9192cdeeb534cc6c3b208170e64615fa3e0edb3e578","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"86a0e11f928db7c8587e94ea3ba5801025526ed9a35d8d592c2705f96df05c22","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"14f0bd6693967d4fedec904f7042bd51f2138cb843ec4df18c911b357417cdd2","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"45d8ba0bdca685ea6bc0c601f60a0d39cb1513c3ccb57edc6bc9d97a46040f3b","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"644cf25a8823d564dd75af5f5c7506febcf963a36b917c775f6045194647f87f","src/unix/bsd/freebsdlike/freebsd/mod.rs":"2d932d532f466ea0e476a4091ae3debe6d115807de934a22e38ae36cf1eace2d","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/x86.rs":"c5005e3249eb7c93cfbac72a9e9272320d80ce7983da990ceb05a447f59a02c5","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"6132aa0973454379674ea6cbc77e6eace1e1032dd9f38182071388a036f1bc08","src/unix/bsd/freebsdlike/mod.rs":"a45d3095966dff5142d0b292a416a004c78d5689bb38ab7c8d4497b9b310e02f","src/unix/bsd/mod.rs":"4fd08b1fe9c9f74b50e8405a60dd506a6910190fbfbae7e968f1d9848f2b328e","src/unix/bsd/netbsdlike/mod.rs":"48dd60524119c1e09b255d5472d091e7e7b2b29eab04be51b4b1e740bd022859","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"b38fc046f9a40fea28bd26328b96629f4d5d63d7524936bd6af1865d401a8716","src/unix/bsd/netbsdlike/netbsd/arm.rs":"58cdbb70b0d6f536551f0f3bb3725d2d75c4690db12c26c034e7d6ec4a924452","src/unix/bsd/netbsdlike/netbsd/mod.rs":"3ca4305fac136b475090a53dd39e1a77a522d1395c00caa01f8c6189ea04add0","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"135509edeaf3fb3f102d89d51ff1a8f82323497336a8dc7e1f0f23b5c2434b73","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/mod.rs":"ebe8abc57672e55ab22d5ca5ef7735eb79a41a0fcae0020d0f9b52744b960693","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"e59b7fd65f68f8e857eec39e0c03bac1d3af6ddc26c9ba58494336b83659bb9b","src/unix/haiku/b32.rs":"69ae47fc52c6880e85416b4744500d5655c9ec6131cb737f3b649fceaadce15a","src/unix/haiku/b64.rs":"73e64db09275a8da8d50a13cce2cfa2b136036ddf3a930d2939f337fc995900b","src/unix/haiku/mod.rs":"ecd6139a3656a2fb13e66fed8bed9dfceafea48c169b1fa533b9e1b09a8b18eb","src/unix/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/unix/hermit/mod.rs":"2d8d3ce0299931199011bb73136bebbddf88edf7d263cc39d26dbfaaa1a14228","src/unix/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/unix/linux_like/android/b32/arm.rs":"155994121906903a2e0afad895f0b3b7546f6e54d6305a3336ce2c4dfafbfdfa","src/unix/linux_like/android/b32/mod.rs":"0325adf3364fed7157fff5b24fabe1b36d806c39ee04ec82dd29a606d28f91f6","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"5b1e9fcd77ca5f939acb7fb5f5da12f305b0377698d8b8989feb236e26360aa0","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/mod.rs":"655116966eb7846b933e5e28b073c329668588cd3c2120cc9ce60c697bd19978","src/unix/linux_like/android/b64/mod.rs":"6a71abfcbbcdae60c916de41cd4688d5f25bdbca83d1d9df49decd56ad726a06","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"e84176d838e663d351450bad218715db1fafbb531e47ea0e262cbb45829dae89","src/unix/linux_like/android/mod.rs":"6a15896f6144fec95243728a0bbda92bec0f21883742054df1531b9d9cf41594","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/mod.rs":"65e4e632256087af0045bb095cd9e8dc1fee7f4458325aa07904f2ad16ca6af0","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"015ec9e064bf7dee63b5a16e6d87aef11aeeeea84a3b083f9e75a97bb7ab2f0b","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"9e18ad197709bce3aab40537b6ea371ff13f3be7be1d50ff97964f937c517646","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"5cf043f5342c37b1cf50bc09de9baaa8d120a8827640f328a74ebbff1fe5aca0","src/unix/linux_like/linux/gnu/b32/mod.rs":"d86a7bb02f97a1129c870905c536769770dfb233184e4cff6b395ad512e5300b","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"5457ff8f90fb777cfc3cbe6c0c6a3b3f8eaecb28e66fffc53390e82010030ebe","src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs":"7b2528fdcdbbfb5cd350b27a3f66a6950fb94be1c924c1156a1d93e8950496a1","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"0a4aec7eb78dcac864ed33a2a0d60ae285c7572ec9e475828e158fa6f43593a3","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"b1005390da3ed2d95b612fdcc4b69f11165ce31cfbf50674fe877ed47ad1b431","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"e73a372b096951030ae7db4f0ad0c5a472ccd8f21973d61811b8441eaf5229af","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"e86403f310a14fc5355dd78746ac55056c91fa7cd3248d5d8a18430b4940cb2d","src/unix/linux_like/linux/gnu/b64/mod.rs":"b90d87f76bff37707a1725551fe45d70d0c106e01b1dbbcd5f60460e0a19b4c3","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"8aaaa4d9a5f79a7413930632c47382e845789dd9a191dc8bf084c8041ee350b1","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"b954a060f88cd03d0ca8bdeb864046230d0c52e2d2ab97394430f1356a357a82","src/unix/linux_like/linux/gnu/b64/s390x.rs":"818bdc54fdcb9d83190d78f31d0f4a082d06ded112ccb40daa1ab4c541ee58d5","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"22e57216290614616c671f35e24e881d6fcf9839dbfa8d2833a1a77ada28d156","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"c084edff71fa74f7ceb743c116f76a9996d311c06475d53b0de68958991e1b9b","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"74deaf2135168fd8a8fe3382a443d3800b95ea833e94150b265cc59a24872166","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"60ff6e9aca19226714cf0c7f58f4388f5f046cf099cc4f61f9a2913d94d7e846","src/unix/linux_like/linux/gnu/mod.rs":"b456bd2d934ccd53c35ee6c6758709482e4cc868dd39caf1ff686dc38f5981f0","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"25e65f594e6ac672a9d261c8309833592efce99505c55fac8ebe424dc36b8ad1","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"45062a178b382ab17341a69d027b5c83325c4e79fecf45729ba9c47b1bcdc3da","src/unix/linux_like/linux/musl/b32/hexagon.rs":"7c6c481f70da1fe6ca759f363784e130041f3d87906c45910fc1142b5ef17970","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"9eb0e4953be5afaa0b9e3ac54c85ed40583cfb8cc0b03264b9bc8f763a8f3254","src/unix/linux_like/linux/musl/b32/mod.rs":"8ede3985e6243882814ce91e8ce543e7edbafc0cee5932816072b6f14207a671","src/unix/linux_like/linux/musl/b32/powerpc.rs":"cf286cbf4d2076aaa82662ace2b5c333480410fa59af5cb4542d59f04da84b31","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"9c3b6e98e7710d6c877a4e31726d36416115a58f53fc469bb173b7fe660b39e5","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"22da1c030c254c511bc335c824d40b693904975a4633f8243a8777ca68ef1c65","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"9870fd9a953c98b775c9e17a29a66bbe8019a6236eb69a0272f42232a226521d","src/unix/linux_like/linux/musl/b64/mips64.rs":"9d0158ac7a913222d0a62239ec043aa1aee73522a7a1e0e191d0642dde35c083","src/unix/linux_like/linux/musl/b64/mod.rs":"8b76e92a1505ad785d4aa0b7739e0b93647a1e81910949b49cedb6c88468be9c","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"ed9b879bb9cdc526ad83815875edeb4cad4e8829086dfba2578277c265336229","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"cfeb109c732ac6bc7d2be44069d3652e917a0509b8b545270b756ff2d52e27e8","src/unix/linux_like/linux/musl/mod.rs":"0314a270919e9c933d5f35b7520322a9fd89c53b640c1be2424476bdbcdfdb5e","src/unix/linux_like/linux/no_align.rs":"5ed04c53bf9d27da9b4d65ba7625c6ac53330162683d1b3df98950caafa3507b","src/unix/linux_like/mod.rs":"ef07910791fb4ee7cee85c4cb4dc7896eb119a4b1fff67220fe41dd5b046f0a8","src/unix/mod.rs":"0e0b5d5716883d89efb2a3628efdff49eda3467e5528ed6b4c4d162e7d8311ab","src/unix/newlib/aarch64/mod.rs":"bb269c1468a9676442554600e87417079a787fe6220dfc23b3109639259e8710","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"c71be856bfd7f576b2db28af9f680211cbe6c1cac7d537bbc8020b39591af07c","src/unix/newlib/mod.rs":"2f771ab23df36ab0c7a117e854483a917aaf9c5cbb9eded1bdda35827cdaf734","src/unix/newlib/no_align.rs":"7123dcec13604a11b7765c380ff3a4d0da19c39f4b03919de7857723c0cf1502","src/unix/newlib/powerpc/mod.rs":"2d0f7af28b47f7a2a6c210ebd1c1f33ed8eac62e56b5af2b856de2ad3fdc5187","src/unix/newlib/xtensa/mod.rs":"4c72003c5e692e648c7e798358c49af6901e68850dbba0624af84c40baf208f5","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/redox/mod.rs":"c6ac0812f85046e40f691357da8a1cbd72572bdb0f913c24aac106d7aa4ac240","src/unix/solarish/compat.rs":"3f13657fc072462b85b5f937f0db1427c41acb2a714cc4f78fefba1ea8036846","src/unix/solarish/illumos.rs":"1088c45b238e7d398dbb140d238257d5b5f93aeded98652c3f6747f0c07b4fa7","src/unix/solarish/mod.rs":"0134ce769d06b1b1f50ad15d1aa7bd8d44bcd2f66c6318dd906de8bc4a4044c7","src/unix/solarish/solaris.rs":"5914ded3ce8ec5638bb023d4cde147f016d736d5006964a1ef9839752ecb45f8","src/unix/uclibc/align.rs":"a8540e1cce5913a45bc8d7422b79e86c0b12740e8a679478e0e4d863a31f8cc1","src/unix/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/arm/mod.rs":"d67dd46bc6f417169fc6a23832bde7ccdafc5d1bcb08b10debdd82edaf75d529","src/unix/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/mips/mips32/mod.rs":"a045ebc6619f540adf670b88a987abd2d6e42e440a552e8cfe9f8c77f397e873","src/unix/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/uclibc/mips/mips64/mod.rs":"e3085ba56cfbc528d7c3c55065880603238c333b6047ef51c58177508a487fcd","src/unix/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/uclibc/mips/mod.rs":"1054d0bfeb506b3346b9a4148564beced8a22da0d9c9a612101f6237756795fb","src/unix/uclibc/mod.rs":"907805e356738075844a704ef2eec8cfd628c59bb1408d3fff66e8f9ba36e4ba","src/unix/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/uclibc/x86_64/align.rs":"4e34cebb7955e9c98ae2f310be6f8ed16a861fc3817c08543867554aeec9524e","src/unix/uclibc/x86_64/l4re.rs":"bb31053d6403091e11f95ac2203982f279f8b984a19adf30796878c45fdd8c25","src/unix/uclibc/x86_64/mod.rs":"188fbaf06a8e23cac72718b1ef7eb4bd98bdfd946aa708151f3f7e3553b65876","src/unix/uclibc/x86_64/no_align.rs":"2ccc0107a6007c70dc49e656095b64a352ca5d8f9f3e65c1dba634effbc15636","src/unix/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"b7c57b72a0f312c20531ba393f6fab7331fb708170d141d898d705868a5ee780","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"11e1ca29d1a446845c551d5717ec5c6081459a2a850781c9194f557d53ecf44f","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"c7ab9793baaa3b6854d25fdf44266b7953533009e4fa722ca717b71d3e5d2c9d","src/windows/mod.rs":"7b74bf885712d16a3557df33ef02799dc03d4a1af953c7e6b4648954ce7a20fc","src/windows/msvc.rs":"2c2bfce66027d88021e7289139ebf5b0db258a7b6443f18872c84dbd4ef57131","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4","triagebot.toml":"6795d38eccbdaf67e5870e01526a7cdc56c459f4028d8d5de570f336cef4b701"},"package":"4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"} \ No newline at end of file diff --git a/vendor/libc/Cargo.toml b/vendor/libc/Cargo.toml index e437b5fa3e..575beff468 100644 --- a/vendor/libc/Cargo.toml +++ b/vendor/libc/Cargo.toml @@ -12,13 +12,13 @@ [package] name = "libc" -version = "0.2.79" +version = "0.2.80" authors = ["The Rust Project Developers"] build = "build.rs" exclude = ["/ci/*", "/azure-pipelines.yml"] description = "Raw FFI bindings to platform libraries like libc.\n" homepage = "https://github.com/rust-lang/libc" -documentation = "http://doc.rust-lang.org/libc" +documentation = "https://docs.rs/libc/0.2.79/libc/" readme = "README.md" keywords = ["libc", "ffi", "bindings", "operating", "system"] categories = ["external-ffi-bindings", "no-std", "os"] diff --git a/vendor/libc/README.md b/vendor/libc/README.md index af31c25aee..f7b9669c45 100644 --- a/vendor/libc/README.md +++ b/vendor/libc/README.md @@ -1,6 +1,6 @@ # libc - Raw FFI bindings to platforms' system libraries -[![Azure Status]][Azure] [![Cirrus CI Status]][Cirrus CI] [![Latest Version]][crates.io] [![Documentation]][docs.rs] ![License] +[![GHA Status]][GitHub Actions] [![Cirrus CI Status]][Cirrus CI] [![Latest Version]][crates.io] [![Documentation]][docs.rs] ![License] `libc` provides all of the definitions necessary to easily interoperate with C code (or "C-like" code) on each of the platforms that Rust supports. This @@ -94,8 +94,8 @@ Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in `libc` by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. -[Azure Status]: https://dev.azure.com/rust-lang2/libc/_apis/build/status/rust-lang.libc%20(1)?branchName=master -[Azure]: https://dev.azure.com/rust-lang2/libc/_build/latest?definitionId=1&branchName=master +[GitHub Actions]: https://github.com/rust-lang/libc/actions +[GHA Status]: https://github.com/rust-lang/libc/workflows/CI/badge.svg [Cirrus CI]: https://cirrus-ci.com/github/rust-lang/libc [Cirrus CI Status]: https://api.cirrus-ci.com/github/rust-lang/libc.svg [crates.io]: https://crates.io/crates/libc diff --git a/vendor/libc/src/macros.rs b/vendor/libc/src/macros.rs index b314f60ff2..1871cfafda 100644 --- a/vendor/libc/src/macros.rs +++ b/vendor/libc/src/macros.rs @@ -40,12 +40,12 @@ macro_rules! cfg_if { // Internal and recursive macro to emit all the items // - // Collects all the negated cfgs in a list at the beginning and after the + // Collects all the negated `cfg`s in a list at the beginning and after the // semicolon is all the remaining items (@__items ($($not:meta,)*) ; ) => {}; (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { - // Emit all items within one block, applying an approprate #[cfg]. The + // Emit all items within one block, applying an appropriate #[cfg]. The // #[cfg] will require all `$m` matchers specified and must also negate // all previous matchers. cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } @@ -114,7 +114,9 @@ macro_rules! s_no_extra_traits { $(#[$attr])* pub struct $i { $($field)* } } + #[allow(deprecated)] impl ::Copy for $i {} + #[allow(deprecated)] impl ::Clone for $i { fn clone(&self) -> $i { *self } } @@ -167,7 +169,7 @@ macro_rules! s_paren { // so we need to avoid emitting it at all of 'const-extern-fn'. // // Specifically, moving the 'cfg_if' into the macro body will *not* work. -// Doing so would cause the '#[cfg(feature = "const-extern-fn")]' to be emiited +// Doing so would cause the '#[cfg(feature = "const-extern-fn")]' to be emitted // into user code. The 'cfg' gate will not stop Rust from trying to parse the // 'pub const unsafe extern fn', so users would get a compiler error even when // the 'const-extern-fn' feature is disabled @@ -175,19 +177,20 @@ macro_rules! s_paren { // Note that users of this macro need to place 'const' in a weird position // (after the closing ')' for the arguments, but before the return type). // This was the only way I could satisfy the following two requirements: -// 1. Avoid ambuguity errors from 'macro_rules!' (which happen when writing '$foo:ident fn' +// 1. Avoid ambiguity errors from 'macro_rules!' (which happen when writing '$foo:ident fn' // 2. Allow users of this macro to mix 'pub fn foo' and 'pub const fn bar' within the same // 'f!' block cfg_if! { if #[cfg(libc_const_extern_fn)] { #[allow(unused_macros)] macro_rules! f { - ($(pub $({$constness:ident})* fn $i:ident( + ($($(#[$attr:meta])* pub $({$constness:ident})* fn $i:ident( $($arg:ident: $argty:ty),* ) -> $ret:ty { $($body:stmt);* })*) => ($( #[inline] + $(#[$attr])* pub $($constness)* unsafe extern fn $i($($arg: $argty),* ) -> $ret { $($body);* @@ -197,12 +200,13 @@ cfg_if! { #[allow(unused_macros)] macro_rules! safe_f { - ($(pub $({$constness:ident})* fn $i:ident( + ($($(#[$attr:meta])* pub $({$constness:ident})* fn $i:ident( $($arg:ident: $argty:ty),* ) -> $ret:ty { $($body:stmt);* })*) => ($( #[inline] + $(#[$attr])* pub $($constness)* extern fn $i($($arg: $argty),* ) -> $ret { $($body);* @@ -212,12 +216,13 @@ cfg_if! { #[allow(unused_macros)] macro_rules! const_fn { - ($($({$constness:ident})* fn $i:ident( + ($($(#[$attr:meta])* $({$constness:ident})* fn $i:ident( $($arg:ident: $argty:ty),* ) -> $ret:ty { $($body:stmt);* })*) => ($( #[inline] + $(#[$attr])* $($constness)* fn $i($($arg: $argty),* ) -> $ret { $($body);* @@ -228,12 +233,13 @@ cfg_if! { } else { #[allow(unused_macros)] macro_rules! f { - ($(pub $({$constness:ident})* fn $i:ident( + ($($(#[$attr:meta])* pub $({$constness:ident})* fn $i:ident( $($arg:ident: $argty:ty),* ) -> $ret:ty { $($body:stmt);* })*) => ($( #[inline] + $(#[$attr])* pub unsafe extern fn $i($($arg: $argty),* ) -> $ret { $($body);* @@ -243,12 +249,13 @@ cfg_if! { #[allow(unused_macros)] macro_rules! safe_f { - ($(pub $({$constness:ident})* fn $i:ident( + ($($(#[$attr:meta])* pub $({$constness:ident})* fn $i:ident( $($arg:ident: $argty:ty),* ) -> $ret:ty { $($body:stmt);* })*) => ($( #[inline] + $(#[$attr])* pub extern fn $i($($arg: $argty),* ) -> $ret { $($body);* @@ -258,12 +265,13 @@ cfg_if! { #[allow(unused_macros)] macro_rules! const_fn { - ($($({$constness:ident})* fn $i:ident( + ($($(#[$attr:meta])* $({$constness:ident})* fn $i:ident( $($arg:ident: $argty:ty),* ) -> $ret:ty { $($body:stmt);* })*) => ($( #[inline] + $(#[$attr])* fn $i($($arg: $argty),* ) -> $ret { $($body);* diff --git a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs index 434ac63a3c..5fe6bb89cf 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs @@ -1,7 +1,7 @@ // DragonFlyBSD's __error function is declared with "static inline", so it must // be implemented in the libc crate, as a pointer to a static thread_local. f! { - #[deprecated(since = "0.2.77", "Use `__errno_location()` instead")] + #[deprecated(since = "0.2.77", note = "Use `__errno_location()` instead")] pub fn __error() -> *mut ::c_int { &mut errno } diff --git a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs index b443da3118..33c59e2a20 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs @@ -214,6 +214,8 @@ extern "C" { msgtyp: ::c_long, msgflg: ::c_int, ) -> ::c_int; + + pub fn fdatasync(fd: ::c_int) -> ::c_int; } cfg_if! { diff --git a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs index 982855ee5a..94baa09059 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs @@ -221,6 +221,14 @@ extern "C" { msgtyp: ::c_long, msgflg: ::c_int, ) -> ::ssize_t; + pub fn clock_nanosleep( + clk_id: ::clockid_t, + flags: ::c_int, + rqtp: *const ::timespec, + rmtp: *mut ::timespec, + ) -> ::c_int; + + pub fn fdatasync(fd: ::c_int) -> ::c_int; } cfg_if! { diff --git a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs index 6f3087836c..bfd60636fe 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -1299,7 +1299,6 @@ extern "C" { flags: ::c_int, ) -> ::c_int; - pub fn fdatasync(fd: ::c_int) -> ::c_int; pub fn posix_fallocate( fd: ::c_int, offset: ::off_t, @@ -1499,6 +1498,12 @@ extern "C" { needle: *const ::c_void, needlelen: ::size_t, ) -> *mut ::c_void; + + pub fn nmount( + iov: *mut ::iovec, + niov: ::c_uint, + flags: ::c_int + ) -> ::c_int; } #[link(name = "util")] diff --git a/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs b/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs index dfa5764ed3..ee9cda2487 100644 --- a/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs +++ b/vendor/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs @@ -919,6 +919,12 @@ pub const O_RSYNC: ::c_int = 0x00020000; pub const MS_SYNC: ::c_int = 0x4; pub const MS_INVALIDATE: ::c_int = 0x2; +// Here because they are not present on OpenBSD +// (https://github.com/openbsd/src/blob/master/sys/sys/resource.h) +pub const RLIMIT_SBSIZE: ::c_int = 9; +pub const RLIMIT_AS: ::c_int = 10; +pub const RLIMIT_NTHR: ::c_int = 11; + #[deprecated(since = "0.2.64", note = "Not stable across OS versions")] pub const RLIM_NLIMITS: ::c_int = 12; @@ -1737,6 +1743,12 @@ safe_f! { extern "C" { pub fn ntp_adjtime(buf: *mut timex) -> ::c_int; pub fn ntp_gettime(buf: *mut ntptimeval) -> ::c_int; + pub fn clock_nanosleep( + clk_id: ::clockid_t, + flags: ::c_int, + rqtp: *const ::timespec, + rmtp: *mut ::timespec, + ) -> ::c_int; } #[link(name = "rt")] diff --git a/vendor/libc/src/unix/linux_like/android/mod.rs b/vendor/libc/src/unix/linux_like/android/mod.rs index 079de283f8..1240e208be 100644 --- a/vendor/libc/src/unix/linux_like/android/mod.rs +++ b/vendor/libc/src/unix/linux_like/android/mod.rs @@ -306,6 +306,13 @@ s_no_extra_traits! { pub salg_name: [::c_uchar; 64], } + /// WARNING: The `PartialEq`, `Eq` and `Hash` implementations of this + /// type are unsound and will be removed in the future. + #[deprecated( + note = "this struct has unsafe trait implementations that will be \ + removed in the future", + since = "0.2.80" + )] pub struct af_alg_iv { pub ivlen: u32, pub iv: [::c_uchar; 0], @@ -591,6 +598,7 @@ cfg_if! { } } + #[allow(deprecated)] impl af_alg_iv { fn as_slice(&self) -> &[u8] { unsafe { @@ -602,22 +610,26 @@ cfg_if! { } } + #[allow(deprecated)] impl PartialEq for af_alg_iv { fn eq(&self, other: &af_alg_iv) -> bool { *self.as_slice() == *other.as_slice() } } + #[allow(deprecated)] impl Eq for af_alg_iv {} + #[allow(deprecated)] impl ::fmt::Debug for af_alg_iv { fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { f.debug_struct("af_alg_iv") - .field("iv", &self.as_slice()) + .field("ivlen", &self.ivlen) .finish() } } + #[allow(deprecated)] impl ::hash::Hash for af_alg_iv { fn hash(&self, state: &mut H) { self.as_slice().hash(state); @@ -841,6 +853,11 @@ pub const _SC_V7_LPBIG_OFFBIG: ::c_int = 140; pub const _SC_XOPEN_STREAMS: ::c_int = 141; pub const _SC_XOPEN_UUCP: ::c_int = 142; +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; + pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; @@ -1008,6 +1025,8 @@ pub const SOCK_SEQPACKET: ::c_int = 5; pub const SOCK_DCCP: ::c_int = 6; pub const SOCK_PACKET: ::c_int = 10; +pub const IPPROTO_MAX: ::c_int = 256; + pub const SOL_SOCKET: ::c_int = 1; pub const SOL_SCTP: ::c_int = 132; pub const SOL_IPX: ::c_int = 256; @@ -1068,6 +1087,8 @@ pub const SO_RXQ_OVFL: ::c_int = 40; pub const SO_PEEK_OFF: ::c_int = 42; pub const SO_BUSY_POLL: ::c_int = 46; +pub const TCP_ULP: ::c_int = 31; + pub const IPTOS_ECN_NOTECT: u8 = 0x00; pub const O_ACCMODE: ::c_int = 3; @@ -2129,6 +2150,13 @@ pub const ALG_SET_AEAD_AUTHSIZE: ::c_int = 5; pub const ALG_OP_DECRYPT: ::c_int = 0; pub const ALG_OP_ENCRYPT: ::c_int = 1; +// uapi/linux/vm_sockets.h +pub const VMADDR_CID_ANY: ::c_uint = 0xFFFFFFFF; +pub const VMADDR_CID_HYPERVISOR: ::c_uint = 0; +pub const VMADDR_CID_LOCAL: ::c_uint = 1; +pub const VMADDR_CID_HOST: ::c_uint = 2; +pub const VMADDR_PORT_ANY: ::c_uint = 0xFFFFFFFF; + // uapi/linux/inotify.h pub const IN_ACCESS: u32 = 0x0000_0001; pub const IN_MODIFY: u32 = 0x0000_0002; @@ -2380,6 +2408,34 @@ extern "C" { sevlen: ::size_t, flags: ::c_int, ) -> ::c_int; + pub fn preadv( + fd: ::c_int, + iov: *const ::iovec, + count: ::c_int, + offset: ::off_t, + ) -> ::ssize_t; + pub fn pwritev( + fd: ::c_int, + iov: *const ::iovec, + count: ::c_int, + offset: ::off_t, + ) -> ::ssize_t; + pub fn process_vm_readv( + pid: ::pid_t, + local_iov: *const ::iovec, + local_iov_count: ::c_ulong, + remote_iov: *const ::iovec, + remote_iov_count: ::c_ulong, + flags: ::c_ulong, + ) -> ::ssize_t; + pub fn process_vm_writev( + pid: ::pid_t, + local_iov: *const ::iovec, + local_iov_count: ::c_ulong, + remote_iov: *const ::iovec, + remote_iov_count: ::c_ulong, + flags: ::c_ulong, + ) -> ::ssize_t; pub fn ptrace(request: ::c_int, ...) -> ::c_long; pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int; pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int; diff --git a/vendor/libc/src/unix/linux_like/emscripten/mod.rs b/vendor/libc/src/unix/linux_like/emscripten/mod.rs index 2584a3ba07..945efeea74 100644 --- a/vendor/libc/src/unix/linux_like/emscripten/mod.rs +++ b/vendor/libc/src/unix/linux_like/emscripten/mod.rs @@ -1557,6 +1557,8 @@ pub const SOCK_STREAM: ::c_int = 1; pub const SOCK_DGRAM: ::c_int = 2; pub const SOCK_SEQPACKET: ::c_int = 5; +pub const IPPROTO_MAX: ::c_int = 256; + pub const SOL_SOCKET: ::c_int = 1; pub const SO_REUSEADDR: ::c_int = 2; diff --git a/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs b/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs index 28e9f7fee7..5e0076ea84 100644 --- a/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/gnu/b32/mod.rs @@ -140,74 +140,128 @@ s! { } } -pub const O_NOATIME: ::c_int = 0o1000000; -pub const O_PATH: ::c_int = 0o10000000; -pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; - pub const SO_PRIORITY: ::c_int = 12; pub const SO_BSDCOMPAT: ::c_int = 14; -pub const SO_BINDTODEVICE: ::c_int = 25; pub const SO_TIMESTAMP: ::c_int = 29; -pub const SO_MARK: ::c_int = 36; -pub const SO_RXQ_OVFL: ::c_int = 40; -pub const SO_PEEK_OFF: ::c_int = 42; -pub const SO_BUSY_POLL: ::c_int = 46; - -pub const SA_ONSTACK: ::c_int = 0x08000000; -pub const PTRACE_DETACH: ::c_uint = 17; pub const POSIX_FADV_DONTNEED: ::c_int = 4; pub const POSIX_FADV_NOREUSE: ::c_int = 5; -pub const F_SETLK: ::c_int = 6; -pub const F_SETLKW: ::c_int = 7; - -pub const F_RDLCK: ::c_int = 0; -pub const F_WRLCK: ::c_int = 1; -pub const F_UNLCK: ::c_int = 2; - pub const F_OFD_GETLK: ::c_int = 36; pub const F_OFD_SETLK: ::c_int = 37; pub const F_OFD_SETLKW: ::c_int = 38; -pub const SFD_CLOEXEC: ::c_int = 0x080000; - -pub const NCCS: usize = 32; - -pub const O_TRUNC: ::c_int = 512; - -pub const O_CLOEXEC: ::c_int = 0x80000; - -pub const EBFONT: ::c_int = 59; -pub const ENOSTR: ::c_int = 60; -pub const ENODATA: ::c_int = 61; -pub const ETIME: ::c_int = 62; -pub const ENOSR: ::c_int = 63; -pub const ENONET: ::c_int = 64; -pub const ENOPKG: ::c_int = 65; -pub const EREMOTE: ::c_int = 66; -pub const ENOLINK: ::c_int = 67; -pub const EADV: ::c_int = 68; -pub const ESRMNT: ::c_int = 69; -pub const ECOMM: ::c_int = 70; -pub const EPROTO: ::c_int = 71; -pub const EDOTDOT: ::c_int = 73; - -pub const SA_NODEFER: ::c_int = 0x40000000; -pub const SA_RESETHAND: ::c_int = 0x80000000; -pub const SA_RESTART: ::c_int = 0x10000000; -pub const SA_NOCLDSTOP: ::c_int = 0x00000001; - -pub const EPOLL_CLOEXEC: ::c_int = 0x80000; - -pub const EFD_CLOEXEC: ::c_int = 0x80000; - pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +cfg_if! { + if #[cfg(target_arch = "sparc")] { + pub const O_NOATIME: ::c_int = 0x200000; + pub const O_PATH: ::c_int = 0x1000000; + pub const O_TMPFILE: ::c_int = 0x2000000 | O_DIRECTORY; + pub const SO_BINDTODEVICE: ::c_int = 0x000d; + pub const SO_MARK: ::c_int = 0x0022; + pub const SO_RXQ_OVFL: ::c_int = 0x0024; + pub const SO_PEEK_OFF: ::c_int = 0x0026; + pub const SO_BUSY_POLL: ::c_int = 0x0030; + + pub const SA_ONSTACK: ::c_int = 1; + + pub const PTRACE_DETACH: ::c_uint = 11; + + pub const F_SETLK: ::c_int = 8; + pub const F_SETLKW: ::c_int = 9; + + pub const F_RDLCK: ::c_int = 1; + pub const F_WRLCK: ::c_int = 2; + pub const F_UNLCK: ::c_int = 3; + + pub const SFD_CLOEXEC: ::c_int = 0x400000; + + pub const NCCS: usize = 17; + + pub const O_TRUNC: ::c_int = 0x400; + pub const O_CLOEXEC: ::c_int = 0x400000; + + pub const EBFONT: ::c_int = 109; + pub const ENOSTR: ::c_int = 72; + pub const ENODATA: ::c_int = 111; + pub const ETIME: ::c_int = 73; + pub const ENOSR: ::c_int = 74; + pub const ENONET: ::c_int = 80; + pub const ENOPKG: ::c_int = 113; + pub const EREMOTE: ::c_int = 71; + pub const ENOLINK: ::c_int = 82; + pub const EADV: ::c_int = 83; + pub const ESRMNT: ::c_int = 84; + pub const ECOMM: ::c_int = 85; + pub const EPROTO: ::c_int = 86; + pub const EDOTDOT: ::c_int = 88; + + pub const SA_NODEFER: ::c_int = 0x20; + pub const SA_RESETHAND: ::c_int = 0x4; + pub const SA_RESTART: ::c_int = 0x2; + pub const SA_NOCLDSTOP: ::c_int = 0x00000008; + + pub const EPOLL_CLOEXEC: ::c_int = 0x400000; + + pub const EFD_CLOEXEC: ::c_int = 0x400000; + } else { + pub const O_NOATIME: ::c_int = 0o1000000; + pub const O_PATH: ::c_int = 0o10000000; + pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + pub const SO_BINDTODEVICE: ::c_int = 25; + pub const SO_MARK: ::c_int = 36; + pub const SO_RXQ_OVFL: ::c_int = 40; + pub const SO_PEEK_OFF: ::c_int = 42; + pub const SO_BUSY_POLL: ::c_int = 46; + + pub const SA_ONSTACK: ::c_int = 0x08000000; + + pub const PTRACE_DETACH: ::c_uint = 17; + + pub const F_SETLK: ::c_int = 6; + pub const F_SETLKW: ::c_int = 7; + + pub const F_RDLCK: ::c_int = 0; + pub const F_WRLCK: ::c_int = 1; + pub const F_UNLCK: ::c_int = 2; + + pub const SFD_CLOEXEC: ::c_int = 0x080000; + + pub const NCCS: usize = 32; + + pub const O_TRUNC: ::c_int = 512; + pub const O_CLOEXEC: ::c_int = 0x80000; + pub const EBFONT: ::c_int = 59; + pub const ENOSTR: ::c_int = 60; + pub const ENODATA: ::c_int = 61; + pub const ETIME: ::c_int = 62; + pub const ENOSR: ::c_int = 63; + pub const ENONET: ::c_int = 64; + pub const ENOPKG: ::c_int = 65; + pub const EREMOTE: ::c_int = 66; + pub const ENOLINK: ::c_int = 67; + pub const EADV: ::c_int = 68; + pub const ESRMNT: ::c_int = 69; + pub const ECOMM: ::c_int = 70; + pub const EPROTO: ::c_int = 71; + pub const EDOTDOT: ::c_int = 73; + + pub const SA_NODEFER: ::c_int = 0x40000000; + pub const SA_RESETHAND: ::c_int = 0x80000000; + pub const SA_RESTART: ::c_int = 0x10000000; + pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + + pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + + pub const EFD_CLOEXEC: ::c_int = 0x80000; + } +} + align_const! { #[cfg(target_endian = "little")] pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = diff --git a/vendor/libc/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs b/vendor/libc/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs index 041e3f40ae..4c329027d7 100644 --- a/vendor/libc/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs @@ -204,9 +204,6 @@ s! { } } -pub const POSIX_FADV_DONTNEED: ::c_int = 4; -pub const POSIX_FADV_NOREUSE: ::c_int = 5; - pub const RLIM_INFINITY: ::rlim_t = !0; pub const VEOF: usize = 4; pub const RTLD_DEEPBIND: ::c_int = 0x8; @@ -231,9 +228,6 @@ pub const O_SYNC: ::c_int = 0x802000; pub const O_RSYNC: ::c_int = 0x802000; pub const O_DSYNC: ::c_int = 0x2000; pub const O_FSYNC: ::c_int = 0x802000; -pub const O_NOATIME: ::c_int = 0x200000; -pub const O_PATH: ::c_int = 0x1000000; -pub const O_TMPFILE: ::c_int = 0x2000000 | O_DIRECTORY; pub const MADV_SOFT_OFFLINE: ::c_int = 101; pub const MAP_GROWSDOWN: ::c_int = 0x0200; @@ -330,12 +324,6 @@ pub const SOL_SOCKET: ::c_int = 0xffff; pub const SO_PASSCRED: ::c_int = 2; pub const SO_REUSEADDR: ::c_int = 4; -pub const SO_BINDTODEVICE: ::c_int = 0x000d; -pub const SO_TIMESTAMP: ::c_int = 0x001d; -pub const SO_MARK: ::c_int = 0x0022; -pub const SO_RXQ_OVFL: ::c_int = 0x0024; -pub const SO_PEEK_OFF: ::c_int = 0x0026; -pub const SO_BUSY_POLL: ::c_int = 0x0030; pub const SO_TYPE: ::c_int = 0x1008; pub const SO_ERROR: ::c_int = 0x1007; pub const SO_DONTROUTE: ::c_int = 16; @@ -354,7 +342,6 @@ pub const SO_ACCEPTCONN: ::c_int = 0x8000; pub const SOCK_STREAM: ::c_int = 1; pub const SOCK_DGRAM: ::c_int = 2; -pub const SA_ONSTACK: ::c_int = 1; pub const SA_SIGINFO: ::c_int = 0x200; pub const SA_NOCLDWAIT: ::c_int = 0x100; @@ -387,22 +374,11 @@ pub const POLLWRBAND: ::c_short = 0x100; pub const O_ASYNC: ::c_int = 0x40; pub const O_NDELAY: ::c_int = 0x4004; -pub const PTRACE_DETACH: ::c_uint = 11; - pub const EFD_NONBLOCK: ::c_int = 0x4000; pub const F_GETLK: ::c_int = 7; pub const F_GETOWN: ::c_int = 5; pub const F_SETOWN: ::c_int = 6; -pub const F_SETLK: ::c_int = 8; -pub const F_SETLKW: ::c_int = 9; -pub const F_OFD_GETLK: ::c_int = 36; -pub const F_OFD_SETLK: ::c_int = 37; -pub const F_OFD_SETLKW: ::c_int = 38; - -pub const F_RDLCK: ::c_int = 1; -pub const F_WRLCK: ::c_int = 2; -pub const F_UNLCK: ::c_int = 3; pub const SFD_NONBLOCK: ::c_int = 0x4000; @@ -429,37 +405,6 @@ pub const TIOCM_CAR: ::c_int = 0x040; pub const TIOCM_RNG: ::c_int = 0x080; pub const TIOCM_DSR: ::c_int = 0x100; -pub const SFD_CLOEXEC: ::c_int = 0x400000; - -pub const NCCS: usize = 17; -pub const O_TRUNC: ::c_int = 0x400; - -pub const O_CLOEXEC: ::c_int = 0x400000; - -pub const EBFONT: ::c_int = 109; -pub const ENOSTR: ::c_int = 72; -pub const ENODATA: ::c_int = 111; -pub const ETIME: ::c_int = 73; -pub const ENOSR: ::c_int = 74; -pub const ENONET: ::c_int = 80; -pub const ENOPKG: ::c_int = 113; -pub const EREMOTE: ::c_int = 71; -pub const ENOLINK: ::c_int = 82; -pub const EADV: ::c_int = 83; -pub const ESRMNT: ::c_int = 84; -pub const ECOMM: ::c_int = 85; -pub const EPROTO: ::c_int = 86; -pub const EDOTDOT: ::c_int = 88; - -pub const SA_NODEFER: ::c_int = 0x20; -pub const SA_RESETHAND: ::c_int = 0x4; -pub const SA_RESTART: ::c_int = 0x2; -pub const SA_NOCLDSTOP: ::c_int = 0x00000008; - -pub const EPOLL_CLOEXEC: ::c_int = 0x400000; - -pub const EFD_CLOEXEC: ::c_int = 0x400000; - pub const O_DIRECTORY: ::c_int = 0o200000; pub const O_NOFOLLOW: ::c_int = 0o400000; pub const O_LARGEFILE: ::c_int = 0x40000; @@ -965,18 +910,6 @@ pub const SYS_pidfd_open: ::c_long = 434; // Reserved in the kernel, but not actually implemented yet pub const SYS_clone3: ::c_long = 435; -#[link(name = "util")] -extern "C" { - pub fn sysctl( - name: *mut ::c_int, - namelen: ::c_int, - oldp: *mut ::c_void, - oldlenp: *mut ::size_t, - newp: *mut ::c_void, - newlen: ::size_t, - ) -> ::c_int; -} - cfg_if! { if #[cfg(libc_align)] { mod align; diff --git a/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs b/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs index f48d659f58..5197c520aa 100644 --- a/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs @@ -569,6 +569,25 @@ pub const SO_BPF_EXTENSIONS: ::c_int = 48; pub const SO_INCOMING_CPU: ::c_int = 49; pub const SO_ATTACH_BPF: ::c_int = 50; pub const SO_DETACH_BPF: ::c_int = SO_DETACH_FILTER; +pub const SO_ATTACH_REUSEPORT_CBPF: ::c_int = 51; +pub const SO_ATTACH_REUSEPORT_EBPF: ::c_int = 52; +pub const SO_CNX_ADVICE: ::c_int = 53; +pub const SCM_TIMESTAMPING_OPT_STATS: ::c_int = 54; +pub const SO_MEMINFO: ::c_int = 55; +pub const SO_INCOMING_NAPI_ID: ::c_int = 56; +pub const SO_COOKIE: ::c_int = 57; +pub const SCM_TIMESTAMPING_PKTINFO: ::c_int = 58; +pub const SO_PEERGROUPS: ::c_int = 59; +pub const SO_ZEROCOPY: ::c_int = 60; +pub const SO_TXTIME: ::c_int = 61; +pub const SCM_TXTIME: ::c_int = SO_TXTIME; +pub const SO_BINDTOIFINDEX: ::c_int = 62; +pub const SO_TIMESTAMP_NEW: ::c_int = 63; +pub const SO_TIMESTAMPNS_NEW: ::c_int = 64; +pub const SO_TIMESTAMPING_NEW: ::c_int = 65; +pub const SO_RCVTIMEO_NEW: ::c_int = 66; +pub const SO_SNDTIMEO_NEW: ::c_int = 67; +pub const SO_DETACH_REUSEPORT_BPF: ::c_int = 68; pub const SOCK_STREAM: ::c_int = 1; pub const SOCK_DGRAM: ::c_int = 2; diff --git a/vendor/libc/src/unix/linux_like/linux/gnu/mod.rs b/vendor/libc/src/unix/linux_like/linux/gnu/mod.rs index 41cb0df0e8..d54dd57444 100644 --- a/vendor/libc/src/unix/linux_like/linux/gnu/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/gnu/mod.rs @@ -729,11 +729,13 @@ pub const AFFS_SUPER_MAGIC: ::c_long = 0x0000adff; pub const AFS_SUPER_MAGIC: ::c_long = 0x5346414f; pub const AUTOFS_SUPER_MAGIC: ::c_long = 0x0187; pub const BINDERFS_SUPER_MAGIC: ::c_long = 0x6c6f6f70; +pub const BPF_FS_MAGIC: ::c_long = 0xcafe4a11; pub const BTRFS_SUPER_MAGIC: ::c_long = 0x9123683e; pub const CGROUP2_SUPER_MAGIC: ::c_long = 0x63677270; pub const CGROUP_SUPER_MAGIC: ::c_long = 0x27e0eb; pub const CODA_SUPER_MAGIC: ::c_long = 0x73757245; pub const CRAMFS_MAGIC: ::c_long = 0x28cd3d45; +pub const DEBUGFS_MAGIC: ::c_long = 0x64626720; pub const DEVPTS_SUPER_MAGIC: ::c_long = 0x1cd1; pub const ECRYPTFS_SUPER_MAGIC: ::c_long = 0xf15f; pub const EFS_SUPER_MAGIC: ::c_long = 0x00414a53; @@ -765,7 +767,9 @@ pub const QNX6_SUPER_MAGIC: ::c_long = 0x68191122; pub const RDTGROUP_SUPER_MAGIC: ::c_long = 0x7655821; pub const REISERFS_SUPER_MAGIC: ::c_long = 0x52654973; pub const SMB_SUPER_MAGIC: ::c_long = 0x0000517b; +pub const SYSFS_MAGIC: ::c_long = 0x62656572; pub const TMPFS_MAGIC: ::c_long = 0x01021994; +pub const TRACEFS_MAGIC: ::c_long = 0x74726163; pub const UDF_SUPER_MAGIC: ::c_long = 0x15013346; pub const USBDEVICE_SUPER_MAGIC: ::c_long = 0x00009fa2; pub const XENFS_SUPER_MAGIC: ::c_long = 0xabba1974; diff --git a/vendor/libc/src/unix/linux_like/linux/mod.rs b/vendor/libc/src/unix/linux_like/linux/mod.rs index d6962778e7..249c98bce2 100644 --- a/vendor/libc/src/unix/linux_like/linux/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/mod.rs @@ -538,6 +538,13 @@ s_no_extra_traits! { pub salg_name: [::c_uchar; 64], } + /// WARNING: The `PartialEq`, `Eq` and `Hash` implementations of this + /// type are unsound and will be removed in the future. + #[deprecated( + note = "this struct has unsafe trait implementations that will be \ + removed in the future", + since = "0.2.80" + )] pub struct af_alg_iv { pub ivlen: u32, pub iv: [::c_uchar; 0], @@ -781,6 +788,7 @@ cfg_if! { } } + #[allow(deprecated)] impl af_alg_iv { fn as_slice(&self) -> &[u8] { unsafe { @@ -792,22 +800,26 @@ cfg_if! { } } + #[allow(deprecated)] impl PartialEq for af_alg_iv { fn eq(&self, other: &af_alg_iv) -> bool { *self.as_slice() == *other.as_slice() } } + #[allow(deprecated)] impl Eq for af_alg_iv {} + #[allow(deprecated)] impl ::fmt::Debug for af_alg_iv { fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { f.debug_struct("af_alg_iv") - .field("iv", &self.as_slice()) + .field("ivlen", &self.ivlen) .finish() } } + #[allow(deprecated)] impl ::hash::Hash for af_alg_iv { fn hash(&self, state: &mut H) { self.as_slice().hash(state); @@ -1228,6 +1240,7 @@ pub const RTLD_NOW: ::c_int = 0x2; pub const AT_EACCESS: ::c_int = 0x200; pub const TCP_MD5SIG: ::c_int = 14; +pub const TCP_ULP: ::c_int = 31; align_const! { pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { @@ -1262,6 +1275,17 @@ pub const SCHED_RESET_ON_FORK: ::c_int = 0x40000000; // netinet/in.h // NOTE: These are in addition to the constants defined in src/unix/mod.rs + +/// Multipath TCP +pub const IPPROTO_MPTCP: ::c_int = 262; +#[deprecated( + since = "0.2.80", + note = "This value was increased in the newer kernel \ + and we'll change this following upstream in the future release. \ + See #1896 for more info." +)] +pub const IPPROTO_MAX: ::c_int = 256; + pub const AF_IB: ::c_int = 27; pub const AF_MPLS: ::c_int = 28; pub const AF_NFC: ::c_int = 39; @@ -3218,6 +3242,12 @@ extern "C" { offset: *mut off_t, count: ::size_t, ) -> ::ssize_t; + pub fn sendfile64( + out_fd: ::c_int, + in_fd: ::c_int, + offset: *mut off64_t, + count: ::size_t, + ) -> ::ssize_t; pub fn sigsuspend(mask: *const ::sigset_t) -> ::c_int; pub fn getgrgid_r( gid: ::gid_t, diff --git a/vendor/libc/src/unix/linux_like/linux/musl/mod.rs b/vendor/libc/src/unix/linux_like/linux/musl/mod.rs index 0d427ae389..3fbd389403 100644 --- a/vendor/libc/src/unix/linux_like/linux/musl/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/musl/mod.rs @@ -1,5 +1,11 @@ pub type pthread_t = *mut ::c_void; pub type clock_t = c_long; +#[deprecated( + since = "0.2.80", + note = "This type is changed to 64-bit in musl 1.2.0, \ + we'll follow that change in the future release. \ + See #1848 for more info." +)] pub type time_t = c_long; pub type suseconds_t = c_long; pub type ino_t = u64; @@ -24,7 +30,6 @@ impl siginfo_t { _si_code: ::c_int, si_addr: *mut ::c_void, } - (*(self as *const siginfo_t as *const siginfo_sigfault)).si_addr } @@ -38,11 +43,72 @@ impl siginfo_t { _si_overrun: ::c_int, si_value: ::sigval, } - (*(self as *const siginfo_t as *const siginfo_si_value)).si_value } } +cfg_if! { + if #[cfg(libc_union)] { + // Internal, for casts to access union fields + #[repr(C)] + struct sifields_sigchld { + si_pid: ::pid_t, + si_uid: ::uid_t, + si_status: ::c_int, + si_utime: ::c_long, + si_stime: ::c_long, + } + impl ::Copy for sifields_sigchld {} + impl ::Clone for sifields_sigchld { + fn clone(&self) -> sifields_sigchld { + *self + } + } + + // Internal, for casts to access union fields + #[repr(C)] + union sifields { + _align_pointer: *mut ::c_void, + sigchld: sifields_sigchld, + } + + // Internal, for casts to access union fields. Note that some variants + // of sifields start with a pointer, which makes the alignment of + // sifields vary on 32-bit and 64-bit architectures. + #[repr(C)] + struct siginfo_f { + _siginfo_base: [::c_int; 3], + sifields: sifields, + } + + impl siginfo_t { + unsafe fn sifields(&self) -> &sifields { + &(*(self as *const siginfo_t as *const siginfo_f)).sifields + } + + pub unsafe fn si_pid(&self) -> ::pid_t { + self.sifields().sigchld.si_pid + } + + pub unsafe fn si_uid(&self) -> ::uid_t { + self.sifields().sigchld.si_uid + } + + pub unsafe fn si_status(&self) -> ::c_int { + self.sifields().sigchld.si_status + } + + pub unsafe fn si_utime(&self) -> ::c_long { + self.sifields().sigchld.si_utime + } + + pub unsafe fn si_stime(&self) -> ::c_long { + self.sifields().sigchld.si_stime + } + } + } +} + s! { pub struct aiocb { pub aio_fildes: ::c_int, diff --git a/vendor/libc/src/unix/linux_like/mod.rs b/vendor/libc/src/unix/linux_like/mod.rs index 08f7222ee9..80c4f5bc0b 100644 --- a/vendor/libc/src/unix/linux_like/mod.rs +++ b/vendor/libc/src/unix/linux_like/mod.rs @@ -869,7 +869,6 @@ pub const IPPROTO_UDPLITE: ::c_int = 136; pub const IPPROTO_MPLS: ::c_int = 137; /// raw IP packet pub const IPPROTO_RAW: ::c_int = 255; -pub const IPPROTO_MAX: ::c_int = 256; pub const MCAST_EXCLUDE: ::c_int = 0; pub const MCAST_INCLUDE: ::c_int = 1; diff --git a/vendor/libc/src/unix/mod.rs b/vendor/libc/src/unix/mod.rs index 21439c8a49..d3b43769fe 100644 --- a/vendor/libc/src/unix/mod.rs +++ b/vendor/libc/src/unix/mod.rs @@ -508,6 +508,7 @@ extern "C" { pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; pub fn feof(stream: *mut FILE) -> c_int; pub fn ferror(stream: *mut FILE) -> c_int; + pub fn clearerr(stream: *mut FILE); pub fn perror(s: *const c_char); pub fn atoi(s: *const c_char) -> c_int; #[cfg_attr( @@ -1314,23 +1315,33 @@ extern "C" { pub fn res_init() -> ::c_int; #[cfg_attr(target_os = "netbsd", link_name = "__gmtime_r50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` pub fn gmtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; #[cfg_attr(target_os = "netbsd", link_name = "__localtime_r50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` pub fn localtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; #[cfg_attr( all(target_os = "macos", target_arch = "x86"), link_name = "mktime$UNIX2003" )] #[cfg_attr(target_os = "netbsd", link_name = "__mktime50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` pub fn mktime(tm: *mut tm) -> time_t; #[cfg_attr(target_os = "netbsd", link_name = "__time50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` pub fn time(time: *mut time_t) -> time_t; #[cfg_attr(target_os = "netbsd", link_name = "__gmtime50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` pub fn gmtime(time_p: *const time_t) -> *mut tm; #[cfg_attr(target_os = "netbsd", link_name = "__locatime50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` pub fn localtime(time_p: *const time_t) -> *mut tm; #[cfg_attr(target_os = "netbsd", link_name = "__difftime50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` pub fn difftime(time1: time_t, time0: time_t) -> ::c_double; + #[cfg_attr(target_os = "netbsd", link_name = "__timegm50")] + #[cfg_attr(target_env = "musl", allow(deprecated))] // FIXME: for `time_t` + pub fn timegm(tm: *mut ::tm) -> time_t; #[cfg_attr(target_os = "netbsd", link_name = "__mknod50")] #[cfg_attr( @@ -1445,9 +1456,6 @@ extern "C" { #[cfg_attr(target_os = "netbsd", link_name = "__sigpending14")] pub fn sigpending(set: *mut sigset_t) -> ::c_int; - #[cfg_attr(target_os = "netbsd", link_name = "__timegm50")] - pub fn timegm(tm: *mut ::tm) -> time_t; - pub fn sysconf(name: ::c_int) -> ::c_long; pub fn mkfifo(path: *const c_char, mode: mode_t) -> ::c_int; diff --git a/vendor/libc/src/vxworks/mod.rs b/vendor/libc/src/vxworks/mod.rs old mode 100755 new mode 100644 diff --git a/vendor/libc/triagebot.toml b/vendor/libc/triagebot.toml index fa0824ac53..702ee90f89 100644 --- a/vendor/libc/triagebot.toml +++ b/vendor/libc/triagebot.toml @@ -1 +1,6 @@ +[relabel] +allow-unauthenticated = [ + "C-*", "O-*", "S-*" +] + [assign] diff --git a/vendor/mdbook/.cargo-checksum.json b/vendor/mdbook/.cargo-checksum.json index 5de6dc20d4..67188d69fd 100644 --- a/vendor/mdbook/.cargo-checksum.json +++ b/vendor/mdbook/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"01fe77b97e8d5a11bd70a48929efabbf2d29964a7ee55126fa2bdfbada00db8b","CONTRIBUTING.md":"680cef0c70325c2e45ede352422ae249ed212c65fc5f502c2267243b89187595","Cargo.lock":"b74e22f840ba0528d5f6b3118936fb26bce080216d6f3a3e57af278c89e2e0f1","Cargo.toml":"db76847db3a06a0b46319ed5d71a83fa0fb85c1cae97030b50e21ef0eeabfe0f","LICENSE":"af175b9d96ee93c21a036152e1b905b0b95304d4ae8c2c921c7609100ba8df7e","README.md":"00d699272528d6a208e8d03f5f99911340c130504aa3e6b04a1905f189433f14","ci/install-hub.sh":"ef529e66465dd624d502f4bd4a1092a741f788b948a98625b1f01375149f4ff7","ci/install-rust.sh":"c7b63b4aff867d6da241c23b45121f3efa9cf62b43f839f0eb0d4d0f86580dd6","ci/make-release.sh":"fcf307a3d28ebd60b4b339f960bc0533dfb1bafe37f3c041fac72b49c279bb3b","examples/nop-preprocessor.rs":"db48153fed353c761ec6a64774f4340a91b4ea8c07236ef571bd7601dc5bd17b","release.toml":"25e91966f4a77515244adf5775d638590916c550f9d25bba6024d629b71840e8","src/book/book.rs":"ea53860086d73d81dcbc72d2f3acddf66786ae4486674e0550396998bb10afa9","src/book/init.rs":"fad0ae98277a8b6e9eb4f79776316f2492be4866702ba32ea9745659f6087a05","src/book/mod.rs":"9f2e291b2110dd91dac88801520772122c0d9aa346c531686e9a541e935e01b2","src/book/summary.rs":"7f5f0b45a5b31dbdfc70c4fbcde60a60d1a2a771b0f2130c2d62cb06a8af0f29","src/cmd/build.rs":"7a87f609ad245a808137c9ff67a92b14238c8b01c3afc834ce166f3ff161a58f","src/cmd/clean.rs":"411579d00103568b8e904db647b6360bd8f9b11d209f595d0a6de0a6e08f8915","src/cmd/init.rs":"3161219d9c4375d296c2f39fdb9cffdad09b373b46f1af5b9543173671a58e5b","src/cmd/mod.rs":"29116e5ca90e916a5f4ce62581a29508670ef184ec3e20569e2ad90b57472abe","src/cmd/serve.rs":"a15a0d7a7cbe9e0421fb2948e6e88e7c1206602dd211d666129e67bc973ad626","src/cmd/test.rs":"405e82cc63f212ec6f41e2017d34aba369c8d581b9c1431c8696d787aa2ee1cf","src/cmd/watch.rs":"86bcf487612c03a3d30c48094aa9b23350226e3e6fbb5850799e61d6f741b81e","src/config.rs":"d2e10952cd4da18685b600aad5696cb41aa38d1c134e1d21a240f0b402e1286f","src/lib.rs":"5f14dc00233be5b80d41530dd44d09f46bff30fbdf418a97e8e237f53e14ea6a","src/main.rs":"867f696a76921341ab1f0664c20f3efb90c2c5cbdf8da34d5a52205b33481c84","src/preprocess/cmd.rs":"cf5a35406e0804df391c90a004e3f8624c518517a3e0b136c5341fac067068ea","src/preprocess/index.rs":"d6d34bc61165dd5f42005e5d601d6729c40cacd656358ede17798effa309e508","src/preprocess/links.rs":"ad161e8545ec7198afc98da2cb8935ed0eb242f88f36494738932c50ba0633ab","src/preprocess/mod.rs":"b699f993473abdf6e4abbe038c8286b14312003e5d4713d946b9ae87047270e7","src/renderer/html_handlebars/hbs_renderer.rs":"27bb7bb89f9f2abbe234f7266e9d2840f9f4f86711da1329e0033ef50e8ca189","src/renderer/html_handlebars/helpers/mod.rs":"d83520feecce350b03b7ffaa9f34d6db2fe7316a46562be694b8eef537124191","src/renderer/html_handlebars/helpers/navigation.rs":"51d6fed8f4af42af10a66bf24804337c87cf93daba893f2f3664b3683a24a9e1","src/renderer/html_handlebars/helpers/theme.rs":"06713b5de794eaf68538e929cce58fe55a6e48afd5e9d3bb211ef47809d18af2","src/renderer/html_handlebars/helpers/toc.rs":"b3d86fa13d1508eaae9f25a685802273048a5c22b6bf094abbad0b7c19cc0afc","src/renderer/html_handlebars/mod.rs":"b6be4801cf49040edc9dad216ed12c26dce87e2dc4724ee24729e4a8b67734b0","src/renderer/html_handlebars/search.rs":"626e3cbec3587b90a8209a314e555533cc9b3e98f54270aafc4ab9f471847599","src/renderer/markdown_renderer.rs":"319453627fa416d44e5459a3f9f4cf07b87a4133ff97df5fc962768c9235c65f","src/renderer/mod.rs":"56c11e129556e7f22750a1ad30785719f761ff98a1ca1409b5981e95a6986429","src/theme/FontAwesome/css/font-awesome.min.css":"799aeb25cc0373fdee0e1b1db7ad6c2f6a0e058dfadaa3379689f583213190bd","src/theme/FontAwesome/fonts/FontAwesome.otf":"444dd4366615ffc4a16d012b2fa90137065d3ccb410fa6fd5e4ddd7b5e4ffcd5","src/theme/FontAwesome/fonts/fontawesome-webfont.eot":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","src/theme/FontAwesome/fonts/fontawesome-webfont.svg":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","src/theme/FontAwesome/fonts/fontawesome-webfont.ttf":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","src/theme/FontAwesome/fonts/fontawesome-webfont.woff":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","src/theme/FontAwesome/fonts/fontawesome-webfont.woff2":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","src/theme/ayu-highlight.css":"c141251b5888ccc185c31976e6cb9234f7827ae6bc4975926cafc8bca5e8f83d","src/theme/book.js":"418a647fcdc6ed5388e5c669e10cb796a8d851c2b24d97c416bcb050fdaa9008","src/theme/clipboard.min.js":"1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44","src/theme/css/chrome.css":"576bd3d1e4748ab1a7e000eb110f83f1b643fa4f8339b90a9305302e5c68aaeb","src/theme/css/general.css":"4c89e3e531bc5ca322e4210c8d1868d5a97df0f2a2726a7d60c192f7d933fe19","src/theme/css/print.css":"a4278dff9af38765eb9d344aa56dcc652ac79c73afc408385b62a4b611b89c14","src/theme/css/variables.css":"ccf9aa3f3dcb79b967e13658d101b3f7b9efa914ae0c5e05ac5ed322af33c5bf","src/theme/favicon.png":"8114d1fc74f4b5621ad9afde7746ed9cf7e420be317a6e29023d2298d58aa15b","src/theme/favicon.svg":"de23e50b1c4dd6e052b3e21d444fcd4b13568b3840ac3c99d9be4e9263c0ef59","src/theme/fonts/OPEN-SANS-LICENSE.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","src/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt":"d1e6d465a83ba1a3be52db6484868cf5812ae9bbf91abdad3900ba0165afcf93","src/theme/fonts/fonts.css":"2db113e6ebede8403c607db3dceb5acc53c247720d5955d22f7db56beb7139b6","src/theme/fonts/mod.rs":"9b97835fbc610c46245ac52f8d40df8f28ace0c4fe7aca0847835ee83cc21a15","src/theme/fonts/open-sans-v17-all-charsets-300.woff2":"7736aa3596c468515c3209f2f9d68cfae96d94c05689bcc11a5dce426a6ee2e8","src/theme/fonts/open-sans-v17-all-charsets-300italic.woff2":"2c7b95c08df0d228caec6d4bfed06da0f7ab6b76ea5cc3f75b5c6ae416bc571b","src/theme/fonts/open-sans-v17-all-charsets-600.woff2":"486c67592731a0b36a89dba1fd0b97aeb73f236bbf60dbf28d7c6b5723c07989","src/theme/fonts/open-sans-v17-all-charsets-600italic.woff2":"1a3e865977024f444834a75a1b33b89b93134c93007ae3d6e14f24e6c88d8dfb","src/theme/fonts/open-sans-v17-all-charsets-700.woff2":"c22fe8c70c36f1d862903b772eaed864d3a8fa849473c9caff224fdb852428e4","src/theme/fonts/open-sans-v17-all-charsets-700italic.woff2":"238ae9593944112bee8dd65f8ebc5f3d3862160a8a245fbe1ee3150bc9a2fd81","src/theme/fonts/open-sans-v17-all-charsets-800.woff2":"3d2c812adf74deb36fead3ff8469800d3c0b23eb2c858ae49310291f89490146","src/theme/fonts/open-sans-v17-all-charsets-800italic.woff2":"ba1521ec219db9bc5bfec0e3e7a897369d98b30d4e853ee4aa525322784428b8","src/theme/fonts/open-sans-v17-all-charsets-italic.woff2":"6c9463f7096c0b9d610e095ed248ac1e8a8da7e92d17e9be544f3baced7b62b2","src/theme/fonts/open-sans-v17-all-charsets-regular.woff2":"2e3b1d34ac67763ab50652da19305d4b3694c6b6e6bf35f4b98411ce4af646d2","src/theme/fonts/source-code-pro-v11-all-charsets-500.woff2":"2bdd9410b0141db3cbbf4cfc3818cc6fad279e8e63940940e06cd6af76ccbfcf","src/theme/head.hbs":"56b3ab3c6eabd4723d4794ecd0a7452aa8903c55a2106d60bceacc74d76311c3","src/theme/header.hbs":"1fd27c9ccd016060dc4d6e77f12bf58b26e7c604aebe2577a67097f95a3de70a","src/theme/highlight.css":"6ebb896cc720d92a56def939b787cb25a2facfcfa9d95eeac9f979b092f15716","src/theme/highlight.js":"5a2b5dadd60831dd1f82220223e2ab18e627061912cc89b5c450ab2c8f26ff90","src/theme/index.hbs":"4698beb607dd1c5571ecc60256bf6858265b4ac546548805f2345ea679dd5976","src/theme/mod.rs":"b8224089da80257f2a6550691ef4334b5f746520dfcbf61906224e4afbcf44ba","src/theme/playground_editor/ace.js":"2a3cd908c9619862b52f621ce2a40f76b772eb51c17308b14bd26d1809af8f87","src/theme/playground_editor/editor.js":"16ca416ca77428fe23cb8e18afbd3626a6a86723d6b6e189c47da95d9e9bdc31","src/theme/playground_editor/mod.rs":"b6b0f99f00ccb83cedfe5ce892834b46936a468611d056eae0f146e59711dc5c","src/theme/playground_editor/mode-rust.js":"2c9d5c9af5ae32612aef1ca5653e3473ed40747d36ecb4a97719ff14707d8535","src/theme/playground_editor/theme-dawn.js":"4493f9c88ed7185f7bb4195be77018d21cdc439a34bd4e5da64b566eb996fbe8","src/theme/playground_editor/theme-tomorrow_night.js":"9dbe62a913ebe3fd9667f41f69c0301bacd963081c69abb0219e4acac4710f60","src/theme/redirect.hbs":"c10b6e36dda1a4f222aa61cd1c6180a2f2937397379adba2c10b9b41e446709e","src/theme/searcher/elasticlunr.min.js":"ef4e11c157b1e2e89782d30bd726f2d5ff7834ea5e26ad02474325f8b1f126c9","src/theme/searcher/mark.min.js":"09e88c2cfaf23ea8a37b5681433eafea97033af632ecc948c8c1ee9944647743","src/theme/searcher/mod.rs":"36979040719b2fa39d1b78808e41cdb6e52e0ea5137c84820b437ed015278072","src/theme/searcher/searcher.js":"5fa8ef792186dcb36dea668de68d6472b899b56ddfb1a1aa8015f4dc7e16af09","src/theme/tomorrow-night.css":"243cb61aa526cef79b3545b1c7f2b681747dd346867c8ceb36c69487acc390fb","src/utils/fs.rs":"4d00080337802a355df25c85a378eae00fb3b8016f80fe71413d6e20463eca60","src/utils/mod.rs":"e4476a3afda9964cb57e29f87ee03f4d8860cdb17a7b3fe5b56e108420adc2f6","src/utils/string.rs":"34ac2235625b52530d335b318a2bea1007c6ae56f39d2e0e5f1013a23ec1ef6f","src/utils/toml_ext.rs":"77e7cb18786cdccf19983a25a3c1b44a18166fe440c3233ccb0303003f105bee","tests/alternative_backends.rs":"1453a25311e8da9d81809381f22382a93f4f2d16bb710b8c566831cea37b15ca","tests/build_process.rs":"a958404fc41ff5c00b08b4c69d26f0862160e20c781b4bea88977d85304b6ef5","tests/custom_preprocessors.rs":"22a5da0ed34ab2fe85d87ceb70e06c2a5065d66c363a39ce7d45715ae974ad1c","tests/dummy_book/mod.rs":"9b4353da9156697787cca654092c0509fec2a8bfa292bbe5d0a5414234c6f6af","tests/dummy_book/src/README.md":"2f6e578b9f31ff5e1d18ae40865355d59e56a23e02798bd8166751245ef4eb9b","tests/dummy_book/src/SUMMARY.md":"3384fd28e2974749eedf385bd3a996b71cc248abf545a696a3fda6180d22d31a","tests/dummy_book/src/conclusion.md":"eca0543344979e938b43debf3d310290a628e8b7b45d3d9bec63c21e61284a4c","tests/dummy_book/src/example.rs":"3be109d6faa3c6104c8fb5e8ffdfe3eba73d0a5ed4f537685fe2cf2c36e657d0","tests/dummy_book/src/first/includes.md":"747f8f1eb4d394c1fdb773acddb7ffdc641e3ad71b0d15afb0f4e2de13a729ed","tests/dummy_book/src/first/index.md":"e7d1af4cb454c0be73bf1e2f01a97541fba385cd04ac5c9a7acc99809adedee8","tests/dummy_book/src/first/markdown.md":"461753f7f5105e35bc246c752065a44ea1d238f6890bd01b7c34d0a5746f7902","tests/dummy_book/src/first/nested-test-with-anchors.rs":"6fdecb4c62201f2dae36ea7e35693238edca03dcfc42d33eaf1685bc957a6d1d","tests/dummy_book/src/first/nested-test.rs":"ca4cdf552842a957be49ffc753f7585dba3c0036a076fea68174719599d426fa","tests/dummy_book/src/first/nested.md":"485d24764340c0413939e52533ab304c07bb55bd23d0ad9e31151ff889425048","tests/dummy_book/src/first/partially-included-test-with-anchors.rs":"501d96562da17cbec46444a004340e711b3fac4b3384f12d7c4844909742c8c8","tests/dummy_book/src/first/partially-included-test.rs":"1bdd1a4f8fdc41ea10868f97de0fe315b2cc592d4cf4aabd784f17dc8c0a6e90","tests/dummy_book/src/first/recursive.md":"9b574239c94c24412dbd918d7b85f557a80cec44d245663cfe1ecdd8ed16765e","tests/dummy_book/src/first/unicode.md":"04a548a642ba5cbc346670a8b38c1aeb5ad23d5a967849783171c634b682de63","tests/dummy_book/src/intro.md":"2749920beee7f563f3ace2bbef204dc66382e052c7945bf27e66912351959a90","tests/dummy_book/src/second.md":"b1344cb47f69621ed68197b81652df1f86254b71b4e3dcbdcf707a4e1fee3340","tests/dummy_book/src/second/nested.md":"b0da2ce6ce1ac5fbda92b5cf7a6a09d39abd267095a29f177e44cd4e8d333d45","tests/dummy_book/src2/README.md":"1bcffb061e737e022f132f78a2dd3193fc0951d0b104e50ddc860d9bc260f505","tests/dummy_book/src2/SUMMARY.md":"4354bec1cae7db3c48dfe869e28e8e29958daef937b33da5e729211372ccb9c9","tests/dummy_book/src2/first/README.md":"ba505ed6c1e18c85ce2ca7070021c719933ce2cf9f28de8565c188c0e4a95d87","tests/dummy_book/src2/second/README.md":"2fb4a90a1359fe3725c3d95888452afd514b0b86bdc4e2768442a71bf5b642a0","tests/dummy_book/src2/second/index.md":"5bf990bec982b9e87d8dfb230fb2dfc96318d9065f97a3d3c5cf27bd134c8bdd","tests/init.rs":"087f4e2814ddc55b4726e2491c460191c387e930d86b2b9716f28baa8fa54ff9","tests/parse_existing_summary_files.rs":"f4b019e66ffc7f59efd7ec9da73bb70180e4cc23ff27904bf4dfd26491ef64a3","tests/rendered_output.rs":"79373359eaa8fd03e8bd278b576fd076d7d30450a13fa69fa40bf0f472100bdd","tests/searchindex_fixture.json":"3bedb596b17e0b74ac4e146de884594ea2a92e45ff2fe24d423c94bead8288d5","tests/summary_md_files/example_book.md":"e1dd09043d9548612b0bb4e607a8796317272aa1fe7a2bda55db6e6f47d3fc5a","tests/summary_md_files/rust_by_example.md":"c46c8eab64780297b851be196a04d573da69553f4d9c33e24fbd5fb2867efbfd","tests/summary_md_files/rust_ffi_guide.md":"26874d9ad22cfdc2a587e7a495a4404247821d2b6e8eabe07334cacc5a4ea365","tests/summary_md_files/the_book-2nd_edition.md":"7ae64929c45aa7d67560c77e5280a540c22d1b0d2f8fd85f8392ce064c2d5f0a","tests/testing.rs":"c80d579682b969045d0c067f7ae5ab425255f83642f9dfd11a42f3de75e1b4a8"},"package":"29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff"} \ No newline at end of file +{"files":{"CHANGELOG.md":"734e222608d4c30f5147804ab04eda29e486ae519dd71dd7b177a1dda0d205ab","CONTRIBUTING.md":"680cef0c70325c2e45ede352422ae249ed212c65fc5f502c2267243b89187595","Cargo.lock":"111e48842738dfa9c63ba5644387e9a772c15d13a4fb07aea5e9c7ccedcf043c","Cargo.toml":"1028176fe03655577929c1d4c220d7187eb918839bbcfc7eef4864e8132ab927","LICENSE":"af175b9d96ee93c21a036152e1b905b0b95304d4ae8c2c921c7609100ba8df7e","README.md":"fd36367d2aaab60b4f7596343e0abf62c2c77a02715c44833c23278820a2455e","ci/install-hub.sh":"d229a71892d2f622fecfefe3c3046efc127b25d5aa95baea2cce3391213198fb","ci/install-rust.sh":"c7b63b4aff867d6da241c23b45121f3efa9cf62b43f839f0eb0d4d0f86580dd6","ci/make-release.sh":"8d9fc60ef6445518a58c4a3ed71156d080c1f7093cf9d499754ba7afb54d61c0","examples/nop-preprocessor.rs":"db48153fed353c761ec6a64774f4340a91b4ea8c07236ef571bd7601dc5bd17b","release.toml":"25e91966f4a77515244adf5775d638590916c550f9d25bba6024d629b71840e8","src/book/book.rs":"ea53860086d73d81dcbc72d2f3acddf66786ae4486674e0550396998bb10afa9","src/book/init.rs":"cd8a4632d3b78c9d4770495d1e916f7462ed12b3ea4138d2f7dfa043608568d9","src/book/mod.rs":"9f2e291b2110dd91dac88801520772122c0d9aa346c531686e9a541e935e01b2","src/book/summary.rs":"7f5f0b45a5b31dbdfc70c4fbcde60a60d1a2a771b0f2130c2d62cb06a8af0f29","src/cmd/build.rs":"7a87f609ad245a808137c9ff67a92b14238c8b01c3afc834ce166f3ff161a58f","src/cmd/clean.rs":"411579d00103568b8e904db647b6360bd8f9b11d209f595d0a6de0a6e08f8915","src/cmd/init.rs":"3161219d9c4375d296c2f39fdb9cffdad09b373b46f1af5b9543173671a58e5b","src/cmd/mod.rs":"29116e5ca90e916a5f4ce62581a29508670ef184ec3e20569e2ad90b57472abe","src/cmd/serve.rs":"a15a0d7a7cbe9e0421fb2948e6e88e7c1206602dd211d666129e67bc973ad626","src/cmd/test.rs":"405e82cc63f212ec6f41e2017d34aba369c8d581b9c1431c8696d787aa2ee1cf","src/cmd/watch.rs":"86bcf487612c03a3d30c48094aa9b23350226e3e6fbb5850799e61d6f741b81e","src/config.rs":"978e9de905f71c5b6d41f5cc0363b2e2a923318b6a7780d27f6762aa07ed7b2b","src/lib.rs":"5f14dc00233be5b80d41530dd44d09f46bff30fbdf418a97e8e237f53e14ea6a","src/main.rs":"867f696a76921341ab1f0664c20f3efb90c2c5cbdf8da34d5a52205b33481c84","src/preprocess/cmd.rs":"efe671d1ebcb00c32f6eff55bcc9beb0b53bde9e0787e1ce8c4e4f9df5b7cf23","src/preprocess/index.rs":"d6d34bc61165dd5f42005e5d601d6729c40cacd656358ede17798effa309e508","src/preprocess/links.rs":"ad161e8545ec7198afc98da2cb8935ed0eb242f88f36494738932c50ba0633ab","src/preprocess/mod.rs":"b699f993473abdf6e4abbe038c8286b14312003e5d4713d946b9ae87047270e7","src/renderer/html_handlebars/hbs_renderer.rs":"c264054bd143c8d1a50cdaffebf73998f2ad107b63835e0ffc09f310e8cad31c","src/renderer/html_handlebars/helpers/mod.rs":"d83520feecce350b03b7ffaa9f34d6db2fe7316a46562be694b8eef537124191","src/renderer/html_handlebars/helpers/navigation.rs":"51d6fed8f4af42af10a66bf24804337c87cf93daba893f2f3664b3683a24a9e1","src/renderer/html_handlebars/helpers/theme.rs":"06713b5de794eaf68538e929cce58fe55a6e48afd5e9d3bb211ef47809d18af2","src/renderer/html_handlebars/helpers/toc.rs":"b3d86fa13d1508eaae9f25a685802273048a5c22b6bf094abbad0b7c19cc0afc","src/renderer/html_handlebars/mod.rs":"b6be4801cf49040edc9dad216ed12c26dce87e2dc4724ee24729e4a8b67734b0","src/renderer/html_handlebars/search.rs":"626e3cbec3587b90a8209a314e555533cc9b3e98f54270aafc4ab9f471847599","src/renderer/markdown_renderer.rs":"319453627fa416d44e5459a3f9f4cf07b87a4133ff97df5fc962768c9235c65f","src/renderer/mod.rs":"56c11e129556e7f22750a1ad30785719f761ff98a1ca1409b5981e95a6986429","src/theme/FontAwesome/css/font-awesome.min.css":"799aeb25cc0373fdee0e1b1db7ad6c2f6a0e058dfadaa3379689f583213190bd","src/theme/FontAwesome/fonts/FontAwesome.otf":"444dd4366615ffc4a16d012b2fa90137065d3ccb410fa6fd5e4ddd7b5e4ffcd5","src/theme/FontAwesome/fonts/fontawesome-webfont.eot":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","src/theme/FontAwesome/fonts/fontawesome-webfont.svg":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","src/theme/FontAwesome/fonts/fontawesome-webfont.ttf":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","src/theme/FontAwesome/fonts/fontawesome-webfont.woff":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","src/theme/FontAwesome/fonts/fontawesome-webfont.woff2":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","src/theme/ayu-highlight.css":"c141251b5888ccc185c31976e6cb9234f7827ae6bc4975926cafc8bca5e8f83d","src/theme/book.js":"418a647fcdc6ed5388e5c669e10cb796a8d851c2b24d97c416bcb050fdaa9008","src/theme/clipboard.min.js":"1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44","src/theme/css/chrome.css":"576bd3d1e4748ab1a7e000eb110f83f1b643fa4f8339b90a9305302e5c68aaeb","src/theme/css/general.css":"4c89e3e531bc5ca322e4210c8d1868d5a97df0f2a2726a7d60c192f7d933fe19","src/theme/css/print.css":"a4278dff9af38765eb9d344aa56dcc652ac79c73afc408385b62a4b611b89c14","src/theme/css/variables.css":"ccf9aa3f3dcb79b967e13658d101b3f7b9efa914ae0c5e05ac5ed322af33c5bf","src/theme/favicon.png":"8114d1fc74f4b5621ad9afde7746ed9cf7e420be317a6e29023d2298d58aa15b","src/theme/favicon.svg":"de23e50b1c4dd6e052b3e21d444fcd4b13568b3840ac3c99d9be4e9263c0ef59","src/theme/fonts/OPEN-SANS-LICENSE.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","src/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt":"d1e6d465a83ba1a3be52db6484868cf5812ae9bbf91abdad3900ba0165afcf93","src/theme/fonts/fonts.css":"2db113e6ebede8403c607db3dceb5acc53c247720d5955d22f7db56beb7139b6","src/theme/fonts/mod.rs":"9b97835fbc610c46245ac52f8d40df8f28ace0c4fe7aca0847835ee83cc21a15","src/theme/fonts/open-sans-v17-all-charsets-300.woff2":"7736aa3596c468515c3209f2f9d68cfae96d94c05689bcc11a5dce426a6ee2e8","src/theme/fonts/open-sans-v17-all-charsets-300italic.woff2":"2c7b95c08df0d228caec6d4bfed06da0f7ab6b76ea5cc3f75b5c6ae416bc571b","src/theme/fonts/open-sans-v17-all-charsets-600.woff2":"486c67592731a0b36a89dba1fd0b97aeb73f236bbf60dbf28d7c6b5723c07989","src/theme/fonts/open-sans-v17-all-charsets-600italic.woff2":"1a3e865977024f444834a75a1b33b89b93134c93007ae3d6e14f24e6c88d8dfb","src/theme/fonts/open-sans-v17-all-charsets-700.woff2":"c22fe8c70c36f1d862903b772eaed864d3a8fa849473c9caff224fdb852428e4","src/theme/fonts/open-sans-v17-all-charsets-700italic.woff2":"238ae9593944112bee8dd65f8ebc5f3d3862160a8a245fbe1ee3150bc9a2fd81","src/theme/fonts/open-sans-v17-all-charsets-800.woff2":"3d2c812adf74deb36fead3ff8469800d3c0b23eb2c858ae49310291f89490146","src/theme/fonts/open-sans-v17-all-charsets-800italic.woff2":"ba1521ec219db9bc5bfec0e3e7a897369d98b30d4e853ee4aa525322784428b8","src/theme/fonts/open-sans-v17-all-charsets-italic.woff2":"6c9463f7096c0b9d610e095ed248ac1e8a8da7e92d17e9be544f3baced7b62b2","src/theme/fonts/open-sans-v17-all-charsets-regular.woff2":"2e3b1d34ac67763ab50652da19305d4b3694c6b6e6bf35f4b98411ce4af646d2","src/theme/fonts/source-code-pro-v11-all-charsets-500.woff2":"2bdd9410b0141db3cbbf4cfc3818cc6fad279e8e63940940e06cd6af76ccbfcf","src/theme/head.hbs":"56b3ab3c6eabd4723d4794ecd0a7452aa8903c55a2106d60bceacc74d76311c3","src/theme/header.hbs":"1fd27c9ccd016060dc4d6e77f12bf58b26e7c604aebe2577a67097f95a3de70a","src/theme/highlight.css":"6ebb896cc720d92a56def939b787cb25a2facfcfa9d95eeac9f979b092f15716","src/theme/highlight.js":"5a2b5dadd60831dd1f82220223e2ab18e627061912cc89b5c450ab2c8f26ff90","src/theme/index.hbs":"42a8d00d81d2afa370a0f727e1a08ddeecb0a73ae860f51baed2531816e6e662","src/theme/mod.rs":"b8224089da80257f2a6550691ef4334b5f746520dfcbf61906224e4afbcf44ba","src/theme/playground_editor/ace.js":"2a3cd908c9619862b52f621ce2a40f76b772eb51c17308b14bd26d1809af8f87","src/theme/playground_editor/editor.js":"16ca416ca77428fe23cb8e18afbd3626a6a86723d6b6e189c47da95d9e9bdc31","src/theme/playground_editor/mod.rs":"b6b0f99f00ccb83cedfe5ce892834b46936a468611d056eae0f146e59711dc5c","src/theme/playground_editor/mode-rust.js":"2c9d5c9af5ae32612aef1ca5653e3473ed40747d36ecb4a97719ff14707d8535","src/theme/playground_editor/theme-dawn.js":"4493f9c88ed7185f7bb4195be77018d21cdc439a34bd4e5da64b566eb996fbe8","src/theme/playground_editor/theme-tomorrow_night.js":"9dbe62a913ebe3fd9667f41f69c0301bacd963081c69abb0219e4acac4710f60","src/theme/redirect.hbs":"c10b6e36dda1a4f222aa61cd1c6180a2f2937397379adba2c10b9b41e446709e","src/theme/searcher/elasticlunr.min.js":"ef4e11c157b1e2e89782d30bd726f2d5ff7834ea5e26ad02474325f8b1f126c9","src/theme/searcher/mark.min.js":"09e88c2cfaf23ea8a37b5681433eafea97033af632ecc948c8c1ee9944647743","src/theme/searcher/mod.rs":"36979040719b2fa39d1b78808e41cdb6e52e0ea5137c84820b437ed015278072","src/theme/searcher/searcher.js":"012d7f0ad896c931b24c559c45093aeac5cb29984f11e4ce6e278efb478d212c","src/theme/tomorrow-night.css":"243cb61aa526cef79b3545b1c7f2b681747dd346867c8ceb36c69487acc390fb","src/utils/fs.rs":"f064d9989c142fe0aa6fd0fafa89a59417ecd08facf59003d6b658ca5dec75b0","src/utils/mod.rs":"e4476a3afda9964cb57e29f87ee03f4d8860cdb17a7b3fe5b56e108420adc2f6","src/utils/string.rs":"34ac2235625b52530d335b318a2bea1007c6ae56f39d2e0e5f1013a23ec1ef6f","src/utils/toml_ext.rs":"77e7cb18786cdccf19983a25a3c1b44a18166fe440c3233ccb0303003f105bee","tests/alternative_backends.rs":"1453a25311e8da9d81809381f22382a93f4f2d16bb710b8c566831cea37b15ca","tests/build_process.rs":"a958404fc41ff5c00b08b4c69d26f0862160e20c781b4bea88977d85304b6ef5","tests/custom_preprocessors.rs":"22a5da0ed34ab2fe85d87ceb70e06c2a5065d66c363a39ce7d45715ae974ad1c","tests/dummy_book/mod.rs":"b474756f39c442ecd973a3abe3b88834d745b38db40f6c290cdce6c12c8beb91","tests/dummy_book/src/README.md":"2f6e578b9f31ff5e1d18ae40865355d59e56a23e02798bd8166751245ef4eb9b","tests/dummy_book/src/SUMMARY.md":"3384fd28e2974749eedf385bd3a996b71cc248abf545a696a3fda6180d22d31a","tests/dummy_book/src/conclusion.md":"eca0543344979e938b43debf3d310290a628e8b7b45d3d9bec63c21e61284a4c","tests/dummy_book/src/example.rs":"3be109d6faa3c6104c8fb5e8ffdfe3eba73d0a5ed4f537685fe2cf2c36e657d0","tests/dummy_book/src/first/includes.md":"747f8f1eb4d394c1fdb773acddb7ffdc641e3ad71b0d15afb0f4e2de13a729ed","tests/dummy_book/src/first/index.md":"e7d1af4cb454c0be73bf1e2f01a97541fba385cd04ac5c9a7acc99809adedee8","tests/dummy_book/src/first/markdown.md":"461753f7f5105e35bc246c752065a44ea1d238f6890bd01b7c34d0a5746f7902","tests/dummy_book/src/first/nested-test-with-anchors.rs":"6fdecb4c62201f2dae36ea7e35693238edca03dcfc42d33eaf1685bc957a6d1d","tests/dummy_book/src/first/nested-test.rs":"ca4cdf552842a957be49ffc753f7585dba3c0036a076fea68174719599d426fa","tests/dummy_book/src/first/nested.md":"485d24764340c0413939e52533ab304c07bb55bd23d0ad9e31151ff889425048","tests/dummy_book/src/first/partially-included-test-with-anchors.rs":"501d96562da17cbec46444a004340e711b3fac4b3384f12d7c4844909742c8c8","tests/dummy_book/src/first/partially-included-test.rs":"1bdd1a4f8fdc41ea10868f97de0fe315b2cc592d4cf4aabd784f17dc8c0a6e90","tests/dummy_book/src/first/recursive.md":"9b574239c94c24412dbd918d7b85f557a80cec44d245663cfe1ecdd8ed16765e","tests/dummy_book/src/first/unicode.md":"04a548a642ba5cbc346670a8b38c1aeb5ad23d5a967849783171c634b682de63","tests/dummy_book/src/intro.md":"2749920beee7f563f3ace2bbef204dc66382e052c7945bf27e66912351959a90","tests/dummy_book/src/second.md":"b1344cb47f69621ed68197b81652df1f86254b71b4e3dcbdcf707a4e1fee3340","tests/dummy_book/src/second/nested.md":"b0da2ce6ce1ac5fbda92b5cf7a6a09d39abd267095a29f177e44cd4e8d333d45","tests/dummy_book/src2/README.md":"1bcffb061e737e022f132f78a2dd3193fc0951d0b104e50ddc860d9bc260f505","tests/dummy_book/src2/SUMMARY.md":"4354bec1cae7db3c48dfe869e28e8e29958daef937b33da5e729211372ccb9c9","tests/dummy_book/src2/first/README.md":"ba505ed6c1e18c85ce2ca7070021c719933ce2cf9f28de8565c188c0e4a95d87","tests/dummy_book/src2/second/README.md":"2fb4a90a1359fe3725c3d95888452afd514b0b86bdc4e2768442a71bf5b642a0","tests/dummy_book/src2/second/index.md":"5bf990bec982b9e87d8dfb230fb2dfc96318d9065f97a3d3c5cf27bd134c8bdd","tests/init.rs":"087f4e2814ddc55b4726e2491c460191c387e930d86b2b9716f28baa8fa54ff9","tests/parse_existing_summary_files.rs":"f4b019e66ffc7f59efd7ec9da73bb70180e4cc23ff27904bf4dfd26491ef64a3","tests/rendered_output.rs":"1d3089ecf9c72bbc783b74adb478fdbf8e122320a9e9347fcb0bbe1e5d49470f","tests/searchindex_fixture.json":"3bedb596b17e0b74ac4e146de884594ea2a92e45ff2fe24d423c94bead8288d5","tests/summary_md_files/example_book.md":"e1dd09043d9548612b0bb4e607a8796317272aa1fe7a2bda55db6e6f47d3fc5a","tests/summary_md_files/rust_by_example.md":"c46c8eab64780297b851be196a04d573da69553f4d9c33e24fbd5fb2867efbfd","tests/summary_md_files/rust_ffi_guide.md":"26874d9ad22cfdc2a587e7a495a4404247821d2b6e8eabe07334cacc5a4ea365","tests/summary_md_files/the_book-2nd_edition.md":"7ae64929c45aa7d67560c77e5280a540c22d1b0d2f8fd85f8392ce064c2d5f0a","tests/testing.rs":"c80d579682b969045d0c067f7ae5ab425255f83642f9dfd11a42f3de75e1b4a8"},"package":"21251d3eb9ca5e8ac5b73384ddaa483a9bbc7d7dcd656b1fa8f266634810334a"} \ No newline at end of file diff --git a/vendor/mdbook/CHANGELOG.md b/vendor/mdbook/CHANGELOG.md index 3f90557fce..fd233be870 100644 --- a/vendor/mdbook/CHANGELOG.md +++ b/vendor/mdbook/CHANGELOG.md @@ -1,7 +1,22 @@ # Changelog +## mdBook 0.4.4 +[4df9ec9...01836ba](https://github.com/rust-lang/mdBook/compare/4df9ec9...01836ba) + +### Added +- Added the `output.html.print.enable` configuration value to disable the + "print" page. + [#1169](https://github.com/rust-lang/mdBook/pull/1169) +- Added a list of supported languages for syntax-highlighting to the + documentation. + [#1345](https://github.com/rust-lang/mdBook/pull/1345) + +### Fixed +- Now supports symbolic links for files in the `src` directory. + [#1323](https://github.com/rust-lang/mdBook/pull/1323) + ## mdBook 0.4.3 -[9278b83...9278b83](https://github.com/rust-lang/mdBook/compare/9278b83...4df9ec9) +[9278b83...4df9ec9](https://github.com/rust-lang/mdBook/compare/9278b83...4df9ec9) ### Added - Added `output.html.cname` option to emit a `CNAME` file which is used by diff --git a/vendor/mdbook/Cargo.lock b/vendor/mdbook/Cargo.lock index f9619fabff..a26997b959 100644 --- a/vendor/mdbook/Cargo.lock +++ b/vendor/mdbook/Cargo.lock @@ -723,7 +723,7 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "mdbook" -version = "0.4.3" +version = "0.4.5" dependencies = [ "ammonia", "anyhow", diff --git a/vendor/mdbook/Cargo.toml b/vendor/mdbook/Cargo.toml index e7215f4d0c..b16bc42cea 100644 --- a/vendor/mdbook/Cargo.toml +++ b/vendor/mdbook/Cargo.toml @@ -13,9 +13,9 @@ [package] edition = "2018" name = "mdbook" -version = "0.4.3" +version = "0.4.5" authors = ["Mathieu David ", "Michael-F-Bryan ", "Matt Ickstadt "] -exclude = ["/book-example/*"] +exclude = ["/guide/*"] description = "Creates a book from markdown files" documentation = "http://rust-lang.github.io/mdBook/index.html" readme = "README.md" diff --git a/vendor/mdbook/README.md b/vendor/mdbook/README.md index 392180dfd5..07bea61387 100644 --- a/vendor/mdbook/README.md +++ b/vendor/mdbook/README.md @@ -85,7 +85,7 @@ There are multiple ways to install mdBook. ## Usage -mdBook will primarily be used as a command line tool, even though it exposes +mdBook is primarily used as a command line tool, even though it exposes all its functionality as a Rust crate for integration in other projects. Here are the main commands you will want to run. For a more exhaustive diff --git a/vendor/mdbook/ci/install-hub.sh b/vendor/mdbook/ci/install-hub.sh index 1c98299e85..38da2c8cbc 100755 --- a/vendor/mdbook/ci/install-hub.sh +++ b/vendor/mdbook/ci/install-hub.sh @@ -21,4 +21,4 @@ case $1 in ;; esac -echo "##[add-path]$PWD/hub/bin" +echo "$PWD/hub/bin" >> $GITHUB_PATH diff --git a/vendor/mdbook/ci/make-release.sh b/vendor/mdbook/ci/make-release.sh index 8d9fa34dd0..761923bf98 100755 --- a/vendor/mdbook/ci/make-release.sh +++ b/vendor/mdbook/ci/make-release.sh @@ -15,10 +15,20 @@ export CARGO_PROFILE_RELEASE_LTO=true cargo build --bin mdbook --release cd target/release case $1 in - ubuntu* | macos*) + ubuntu*) asset="mdbook-$TAG-$host.tar.gz" tar czf ../../$asset mdbook ;; + macos*) + asset="mdbook-$TAG-$host.tar.gz" + # There is a bug with BSD tar on macOS where the first 8MB of the file are + # sometimes all NUL bytes. See https://github.com/actions/cache/issues/403 + # and https://github.com/rust-lang/cargo/issues/8603 for some more + # information. An alternative solution here is to install GNU tar, but + # flushing the disk cache seems to work, too. + sudo /usr/sbin/purge + tar czf ../../$asset mdbook + ;; windows*) asset="mdbook-$TAG-$host.zip" 7z a ../../$asset mdbook.exe diff --git a/vendor/mdbook/src/book/init.rs b/vendor/mdbook/src/book/init.rs index 7ae00b65a2..ea1911db9e 100644 --- a/vendor/mdbook/src/book/init.rs +++ b/vendor/mdbook/src/book/init.rs @@ -109,10 +109,9 @@ impl BookBuilder { fn copy_across_theme(&self) -> Result<()> { debug!("Copying theme"); - let themedir = self - .config - .html_config() - .and_then(|html| html.theme) + let html_config = self.config.html_config().unwrap_or_default(); + let themedir = html_config + .theme .unwrap_or_else(|| self.config.book.src.join("theme")); let themedir = self.root.join(themedir); @@ -136,8 +135,10 @@ impl BookBuilder { let mut chrome_css = File::create(cssdir.join("chrome.css"))?; chrome_css.write_all(theme::CHROME_CSS)?; - let mut print_css = File::create(cssdir.join("print.css"))?; - print_css.write_all(theme::PRINT_CSS)?; + if html_config.print.enable { + let mut print_css = File::create(cssdir.join("print.css"))?; + print_css.write_all(theme::PRINT_CSS)?; + } let mut variables_css = File::create(cssdir.join("variables.css"))?; variables_css.write_all(theme::VARIABLES_CSS)?; diff --git a/vendor/mdbook/src/config.rs b/vendor/mdbook/src/config.rs index ef6bc6876e..91d4030004 100644 --- a/vendor/mdbook/src/config.rs +++ b/vendor/mdbook/src/config.rs @@ -495,6 +495,8 @@ pub struct HtmlConfig { /// Playground settings. #[serde(alias = "playpen")] pub playground: Playground, + /// Print settings. + pub print: Print, /// Don't render section labels. pub no_section_label: bool, /// Search settings. If `None`, the default will be used. @@ -542,6 +544,7 @@ impl Default for HtmlConfig { additional_js: Vec::new(), fold: Fold::default(), playground: Playground::default(), + print: Print::default(), no_section_label: false, search: None, git_repository_url: None, @@ -566,6 +569,20 @@ impl HtmlConfig { } } +/// Configuration for how to render the print icon, print.html, and print.css. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct Print { + /// Whether print support is enabled. + pub enable: bool, +} + +impl Default for Print { + fn default() -> Self { + Self { enable: true } + } +} + /// Configuration for how to fold chapters of sidebar. #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(default, rename_all = "kebab-case")] diff --git a/vendor/mdbook/src/preprocess/cmd.rs b/vendor/mdbook/src/preprocess/cmd.rs index 625c143bd4..f9c64e28cb 100644 --- a/vendor/mdbook/src/preprocess/cmd.rs +++ b/vendor/mdbook/src/preprocess/cmd.rs @@ -171,15 +171,15 @@ mod tests { use crate::MDBook; use std::path::Path; - fn book_example() -> MDBook { - let example = Path::new(env!("CARGO_MANIFEST_DIR")).join("book-example"); + fn guide() -> MDBook { + let example = Path::new(env!("CARGO_MANIFEST_DIR")).join("guide"); MDBook::load(example).unwrap() } #[test] fn round_trip_write_and_parse_input() { let cmd = CmdPreprocessor::new("test".to_string(), "test".to_string()); - let md = book_example(); + let md = guide(); let ctx = PreprocessorContext::new( md.root.clone(), md.config.clone(), diff --git a/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs b/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs index 4992730e69..918ec29e5e 100644 --- a/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs +++ b/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs @@ -194,7 +194,9 @@ impl HtmlHandlebars { write_file(destination, "book.js", &theme.js)?; write_file(destination, "css/general.css", &theme.general_css)?; write_file(destination, "css/chrome.css", &theme.chrome_css)?; - write_file(destination, "css/print.css", &theme.print_css)?; + if html_config.print.enable { + write_file(destination, "css/print.css", &theme.print_css)?; + } write_file(destination, "css/variables.css", &theme.variables_css)?; if let Some(contents) = &theme.favicon_png { write_file(destination, "favicon.png", &contents)?; @@ -516,14 +518,16 @@ impl Renderer for HtmlHandlebars { } // Render the handlebars template with the data - debug!("Render template"); - let rendered = handlebars.render("index", &data)?; + if html_config.print.enable { + debug!("Render template"); + let rendered = handlebars.render("index", &data)?; - let rendered = - self.post_process(rendered, &html_config.playground, ctx.config.rust.edition); + let rendered = + self.post_process(rendered, &html_config.playground, ctx.config.rust.edition); - utils::fs::write_file(&destination, "print.html", rendered.as_bytes())?; - debug!("Creating print.html ✓"); + utils::fs::write_file(&destination, "print.html", rendered.as_bytes())?; + debug!("Creating print.html ✓"); + } debug!("Copy static files"); self.copy_static_files(&destination, &theme, &html_config) @@ -644,8 +648,9 @@ fn make_data( data.insert("playground_copyable".to_owned(), json!(true)); } - data.insert("fold_enable".to_owned(), json!((html_config.fold.enable))); - data.insert("fold_level".to_owned(), json!((html_config.fold.level))); + data.insert("print_enable".to_owned(), json!(html_config.print.enable)); + data.insert("fold_enable".to_owned(), json!(html_config.fold.enable)); + data.insert("fold_level".to_owned(), json!(html_config.fold.level)); let search = html_config.search.clone(); if cfg!(feature = "search") { diff --git a/vendor/mdbook/src/theme/index.hbs b/vendor/mdbook/src/theme/index.hbs index 7ad4cbf75b..e9e6cff8b2 100644 --- a/vendor/mdbook/src/theme/index.hbs +++ b/vendor/mdbook/src/theme/index.hbs @@ -29,7 +29,9 @@ + {{#if print_enable}} + {{/if}} @@ -136,9 +138,11 @@

{{ book_title }}

+ {{#if print_enable}} + {{/if}} {{#if git_repository_url}} diff --git a/vendor/mdbook/src/theme/searcher/searcher.js b/vendor/mdbook/src/theme/searcher/searcher.js index e1cc806b8e..acf3d50cbc 100644 --- a/vendor/mdbook/src/theme/searcher/searcher.js +++ b/vendor/mdbook/src/theme/searcher/searcher.js @@ -145,6 +145,11 @@ window.search = window.search || {}; url.push(""); } + // encodeURIComponent escapes all chars that could allow an XSS except + // for '. Due to that we also manually replace ' with its url-encoded + // representation (%27). + var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27"); + return '' + result.doc.breadcrumbs + '' + '' diff --git a/vendor/mdbook/src/utils/fs.rs b/vendor/mdbook/src/utils/fs.rs index 7a7aa63a4c..dd1ec218fa 100644 --- a/vendor/mdbook/src/utils/fs.rs +++ b/vendor/mdbook/src/utils/fs.rs @@ -110,7 +110,7 @@ pub fn copy_files_except_ext( for entry in fs::read_dir(from)? { let entry = entry?; - let metadata = entry.metadata()?; + let metadata = entry.path().metadata()?; // If the entry is a dir and the recursive option is enabled, call itself if metadata.is_dir() && recursive { @@ -187,7 +187,17 @@ pub fn get_404_output_file(input_404: &Option) -> String { #[cfg(test)] mod tests { use super::copy_files_except_ext; - use std::fs; + use std::{fs, io::Result, path::Path}; + + #[cfg(target_os = "windows")] + fn symlink, Q: AsRef>(src: P, dst: Q) -> Result<()> { + std::os::windows::fs::symlink_file(src, dst) + } + + #[cfg(not(target_os = "windows"))] + fn symlink, Q: AsRef>(src: P, dst: Q) -> Result<()> { + std::os::unix::fs::symlink(src, dst) + } #[test] fn copy_files_except_ext_test() { @@ -218,6 +228,12 @@ mod tests { if let Err(err) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { panic!("Could not create sub_dir_exists/file.txt: {}", err); } + if let Err(err) = symlink( + &tmp.path().join("file.png"), + &tmp.path().join("symlink.png"), + ) { + panic!("Could not symlink file.png: {}", err); + } // Create output dir if let Err(err) = fs::create_dir(&tmp.path().join("output")) { @@ -249,5 +265,8 @@ mod tests { if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { panic!("output/sub_dir/file.png should exist") } + if !(&tmp.path().join("output/symlink.png")).exists() { + panic!("output/symlink.png should exist") + } } } diff --git a/vendor/mdbook/tests/dummy_book/mod.rs b/vendor/mdbook/tests/dummy_book/mod.rs index a395c2dfd1..d9d9a068de 100644 --- a/vendor/mdbook/tests/dummy_book/mod.rs +++ b/vendor/mdbook/tests/dummy_book/mod.rs @@ -135,11 +135,11 @@ fn recursive_copy, B: AsRef>(from: A, to: B) -> Result<()> } pub fn new_copy_of_example_book() -> Result { - let temp = TempFileBuilder::new().prefix("book-example").tempdir()?; + let temp = TempFileBuilder::new().prefix("guide").tempdir()?; - let book_example = Path::new(env!("CARGO_MANIFEST_DIR")).join("book-example"); + let guide = Path::new(env!("CARGO_MANIFEST_DIR")).join("guide"); - recursive_copy(book_example, temp.path())?; + recursive_copy(guide, temp.path())?; Ok(temp) } diff --git a/vendor/mdbook/tests/rendered_output.rs b/vendor/mdbook/tests/rendered_output.rs index 4f0568dcc7..6234c29b12 100644 --- a/vendor/mdbook/tests/rendered_output.rs +++ b/vendor/mdbook/tests/rendered_output.rs @@ -345,7 +345,7 @@ fn create_missing_file_with_config() { } /// This makes sure you can include a Rust file with `{{#playground example.rs}}`. -/// Specification is in `book-example/src/format/rust.md` +/// Specification is in `guide/src/format/rust.md` #[test] fn able_to_include_playground_files_in_chapters() { let temp = DummyBook::new().build().unwrap(); diff --git a/vendor/miow/.cargo-checksum.json b/vendor/miow/.cargo-checksum.json index 585da7fbcf..8b333c1784 100644 --- a/vendor/miow/.cargo-checksum.json +++ b/vendor/miow/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"7fd778bb1c8367443ae8d1836c4e2e7d253137f51150ef72171cd8cced067d4e","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"29c9533fc9a32ee529e928bcb12308f0745d237fdea80d83c0258f23243d65d1","README.md":"0af34e4879667a4982661e6280068609564b8fc6d89e09c9866eaabe34aba5cf","appveyor.yml":"fb66b571a883ab956a3d2ac2e3ebbe5f6fd858fb6a278c7e873782bf879f882e","src/handle.rs":"8c0c632f241f98c124991a6d16a88985ef45b5341b7b08232677aaa90c54aa24","src/iocp.rs":"c7c7d8622eb219049c9c87eca383c4dc056b1fb8edf48b3e0500f23699f23ba3","src/lib.rs":"0858df55af42c3bdbbc66b7f97e25ee2e806ebed8ae827b34643256d2ea1b089","src/net.rs":"18e485200cde5a553e5fd8c52309118a965515c57ec3fbe086fd74cf9151837c","src/overlapped.rs":"6531dfc5447381770b8521cce4c7b0876d7cb3c5e671962b7321aff685e4cf92","src/pipe.rs":"b9a4ee10aff2457aad4e2a3b815d3929f41add6fbdc122a7c36b086d2e110273"},"package":"07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"} \ No newline at end of file +{"files":{"Cargo.toml":"0fe59ead1468db233456bb3f46436c5a62bcc85ce89258a3de706ba9ae17afcf","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"3ea75d353de268b9dbec44e2e9f56c12cd391579ec4ac5855a4eb68dea216ef2","appveyor.yml":"ffdfb9572a6362866bea6787a726b0d4e43f6bb6516f3a38ebdd561859531602","src/handle.rs":"683af650dcd2975e066891bcd570454e14958f9fb291e0d6ee1d563d2ac1e4ce","src/iocp.rs":"7d11b2269ec05288f0ad693142186f90da60a11dcda264aca3f4ff2f2f78fc57","src/lib.rs":"88aac05a61313b02cf69653392d70c725a805477cb897416d31a02ce7b26d1f1","src/net.rs":"dbb48873bed9921ebbd5227cce9e853d711719972503608d9892da90435881c9","src/overlapped.rs":"90c65c36dbeb95fb1b402b06e97f957c01be2ebb9d43b612bd735ca6e60d3c14","src/pipe.rs":"2a205f04302c3209ba90e6336635525f2fd3ceecad2687f7321a1b2c0188427b"},"package":"5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"} \ No newline at end of file diff --git a/vendor/miow/Cargo.toml b/vendor/miow/Cargo.toml index 5b91c77384..b0b39494b1 100644 --- a/vendor/miow/Cargo.toml +++ b/vendor/miow/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "miow" -version = "0.3.5" +version = "0.3.6" authors = ["Alex Crichton "] description = "A zero overhead I/O library for Windows, focusing on IOCP and Async I/O\nabstractions.\n" homepage = "https://github.com/yoshuawuyts/miow" @@ -26,7 +26,7 @@ repository = "https://github.com/yoshuawuyts/miow" default-target = "x86_64-pc-windows-msvc" targets = ["aarch64-pc-windows-msvc", "i686-pc-windows-msvc", "x86_64-pc-windows-msvc"] [dependencies.socket2] -version = "0.3" +version = "0.3.16" [dependencies.winapi] version = "0.3.3" diff --git a/vendor/miow/LICENSE-APACHE b/vendor/miow/LICENSE-APACHE index f47c941141..16fe87b06e 100644 --- a/vendor/miow/LICENSE-APACHE +++ b/vendor/miow/LICENSE-APACHE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/miow/LICENSE-MIT b/vendor/miow/LICENSE-MIT index a22128a47b..39e0ed6602 100644 --- a/vendor/miow/LICENSE-MIT +++ b/vendor/miow/LICENSE-MIT @@ -1,25 +1,25 @@ -Copyright (c) 2014 Alex Crichton - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/miow/README.md b/vendor/miow/README.md index 6ff771b873..e6cdddb227 100644 --- a/vendor/miow/README.md +++ b/vendor/miow/README.md @@ -1,31 +1,31 @@ -# miow - -[![Build status](https://ci.appveyor.com/api/projects/status/tc5lsxokjk86949l?svg=true)](https://ci.appveyor.com/project/alexcrichton/miow) - -[Documentation](https://docs.rs/miow/0.3/x86_64-pc-windows-msvc/miow/) - -A zero overhead Windows I/O library focusing on IOCP and other async I/O -features. - -```toml -# Cargo.toml -[dependencies] -miow = "0.3" -``` - -# License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in miow by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. +# miow + +[![Build status](https://ci.appveyor.com/api/projects/status/tc5lsxokjk86949l?svg=true)](https://ci.appveyor.com/project/alexcrichton/miow) + +[Documentation](https://docs.rs/miow/0.3/x86_64-pc-windows-msvc/miow/) + +A zero overhead Windows I/O library focusing on IOCP and other async I/O +features. + +```toml +# Cargo.toml +[dependencies] +miow = "0.3.6" +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in miow by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/vendor/miow/appveyor.yml b/vendor/miow/appveyor.yml index a832e68134..2700e425c7 100644 --- a/vendor/miow/appveyor.yml +++ b/vendor/miow/appveyor.yml @@ -1,20 +1,20 @@ -environment: - matrix: - - TARGET: x86_64-pc-windows-msvc - - TARGET: i686-pc-windows-msvc - - TARGET: i686-pc-windows-gnu - GH_TOKEN: - secure: nHB4fVo+y/Aak+L0nYfrT8Rcs8OfUNm0F2xcIVFVYJ9ehf0CzvCmSMUvWguM0kKp - -install: - - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" - - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin - - SET PATH=%PATH%;C:\MinGW\bin - - rustc -V - - cargo -V - -build: false - -test_script: - - cargo test --target %TARGET% +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu + GH_TOKEN: + secure: nHB4fVo+y/Aak+L0nYfrT8Rcs8OfUNm0F2xcIVFVYJ9ehf0CzvCmSMUvWguM0kKp + +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --target %TARGET% diff --git a/vendor/miow/src/handle.rs b/vendor/miow/src/handle.rs index e84b7a0026..a749fb3269 100644 --- a/vendor/miow/src/handle.rs +++ b/vendor/miow/src/handle.rs @@ -1,177 +1,177 @@ -use std::cmp; -use std::io; -use std::ptr; - -use winapi::shared::minwindef::*; -use winapi::shared::ntdef::{BOOLEAN, FALSE, HANDLE, TRUE}; -use winapi::shared::winerror::*; -use winapi::um::fileapi::*; -use winapi::um::handleapi::*; -use winapi::um::ioapiset::*; -use winapi::um::minwinbase::*; - -#[derive(Debug)] -pub struct Handle(HANDLE); - -unsafe impl Send for Handle {} -unsafe impl Sync for Handle {} - -impl Handle { - pub fn new(handle: HANDLE) -> Handle { - Handle(handle) - } - - pub fn raw(&self) -> HANDLE { - self.0 - } - - pub fn into_raw(self) -> HANDLE { - use std::mem; - - let ret = self.0; - mem::forget(self); - ret - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - let mut bytes = 0; - let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; - crate::cvt(unsafe { - WriteFile( - self.0, - buf.as_ptr() as *const _, - len, - &mut bytes, - 0 as *mut _, - ) - })?; - Ok(bytes as usize) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - let mut bytes = 0; - let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; - crate::cvt(unsafe { - ReadFile( - self.0, - buf.as_mut_ptr() as *mut _, - len, - &mut bytes, - 0 as *mut _, - ) - })?; - Ok(bytes as usize) - } - - pub unsafe fn read_overlapped( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - self.read_overlapped_helper(buf, overlapped, FALSE) - } - - pub unsafe fn read_overlapped_wait( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result { - match self.read_overlapped_helper(buf, overlapped, TRUE) { - Ok(Some(bytes)) => Ok(bytes), - Ok(None) => panic!("logic error"), - Err(e) => Err(e), - } - } - - pub unsafe fn read_overlapped_helper( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - wait: BOOLEAN, - ) -> io::Result> { - let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; - let res = crate::cvt({ - ReadFile( - self.0, - buf.as_mut_ptr() as *mut _, - len, - ptr::null_mut(), - overlapped, - ) - }); - match res { - Ok(_) => (), - Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) => (), - Err(e) => return Err(e), - } - - let mut bytes = 0; - let res = crate::cvt({ GetOverlappedResult(self.0, overlapped, &mut bytes, wait as BOOL) }); - match res { - Ok(_) => Ok(Some(bytes as usize)), - Err(ref e) if e.raw_os_error() == Some(ERROR_IO_INCOMPLETE as i32) && wait == FALSE => { - Ok(None) - } - Err(e) => Err(e), - } - } - - pub unsafe fn write_overlapped( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - self.write_overlapped_helper(buf, overlapped, FALSE) - } - - pub unsafe fn write_overlapped_wait( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result { - match self.write_overlapped_helper(buf, overlapped, TRUE) { - Ok(Some(bytes)) => Ok(bytes), - Ok(None) => panic!("logic error"), - Err(e) => Err(e), - } - } - - unsafe fn write_overlapped_helper( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - wait: BOOLEAN, - ) -> io::Result> { - let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; - let res = crate::cvt({ - WriteFile( - self.0, - buf.as_ptr() as *const _, - len, - ptr::null_mut(), - overlapped, - ) - }); - match res { - Ok(_) => (), - Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) => (), - Err(e) => return Err(e), - } - - let mut bytes = 0; - let res = crate::cvt({ GetOverlappedResult(self.0, overlapped, &mut bytes, wait as BOOL) }); - match res { - Ok(_) => Ok(Some(bytes as usize)), - Err(ref e) if e.raw_os_error() == Some(ERROR_IO_INCOMPLETE as i32) && wait == FALSE => { - Ok(None) - } - Err(e) => Err(e), - } - } -} - -impl Drop for Handle { - fn drop(&mut self) { - unsafe { CloseHandle(self.0) }; - } -} +use std::cmp; +use std::io; +use std::ptr; + +use winapi::shared::minwindef::*; +use winapi::shared::ntdef::{BOOLEAN, FALSE, HANDLE, TRUE}; +use winapi::shared::winerror::*; +use winapi::um::fileapi::*; +use winapi::um::handleapi::*; +use winapi::um::ioapiset::*; +use winapi::um::minwinbase::*; + +#[derive(Debug)] +pub struct Handle(HANDLE); + +unsafe impl Send for Handle {} +unsafe impl Sync for Handle {} + +impl Handle { + pub fn new(handle: HANDLE) -> Handle { + Handle(handle) + } + + pub fn raw(&self) -> HANDLE { + self.0 + } + + pub fn into_raw(self) -> HANDLE { + use std::mem; + + let ret = self.0; + mem::forget(self); + ret + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + let mut bytes = 0; + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + crate::cvt(unsafe { + WriteFile( + self.0, + buf.as_ptr() as *const _, + len, + &mut bytes, + 0 as *mut _, + ) + })?; + Ok(bytes as usize) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + let mut bytes = 0; + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + crate::cvt(unsafe { + ReadFile( + self.0, + buf.as_mut_ptr() as *mut _, + len, + &mut bytes, + 0 as *mut _, + ) + })?; + Ok(bytes as usize) + } + + pub unsafe fn read_overlapped( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + self.read_overlapped_helper(buf, overlapped, FALSE) + } + + pub unsafe fn read_overlapped_wait( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result { + match self.read_overlapped_helper(buf, overlapped, TRUE) { + Ok(Some(bytes)) => Ok(bytes), + Ok(None) => panic!("logic error"), + Err(e) => Err(e), + } + } + + pub unsafe fn read_overlapped_helper( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + wait: BOOLEAN, + ) -> io::Result> { + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + let res = crate::cvt({ + ReadFile( + self.0, + buf.as_mut_ptr() as *mut _, + len, + ptr::null_mut(), + overlapped, + ) + }); + match res { + Ok(_) => (), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) => (), + Err(e) => return Err(e), + } + + let mut bytes = 0; + let res = crate::cvt({ GetOverlappedResult(self.0, overlapped, &mut bytes, wait as BOOL) }); + match res { + Ok(_) => Ok(Some(bytes as usize)), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_INCOMPLETE as i32) && wait == FALSE => { + Ok(None) + } + Err(e) => Err(e), + } + } + + pub unsafe fn write_overlapped( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + self.write_overlapped_helper(buf, overlapped, FALSE) + } + + pub unsafe fn write_overlapped_wait( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result { + match self.write_overlapped_helper(buf, overlapped, TRUE) { + Ok(Some(bytes)) => Ok(bytes), + Ok(None) => panic!("logic error"), + Err(e) => Err(e), + } + } + + unsafe fn write_overlapped_helper( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + wait: BOOLEAN, + ) -> io::Result> { + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + let res = crate::cvt({ + WriteFile( + self.0, + buf.as_ptr() as *const _, + len, + ptr::null_mut(), + overlapped, + ) + }); + match res { + Ok(_) => (), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) => (), + Err(e) => return Err(e), + } + + let mut bytes = 0; + let res = crate::cvt({ GetOverlappedResult(self.0, overlapped, &mut bytes, wait as BOOL) }); + match res { + Ok(_) => Ok(Some(bytes as usize)), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_INCOMPLETE as i32) && wait == FALSE => { + Ok(None) + } + Err(e) => Err(e), + } + } +} + +impl Drop for Handle { + fn drop(&mut self) { + unsafe { CloseHandle(self.0) }; + } +} diff --git a/vendor/miow/src/iocp.rs b/vendor/miow/src/iocp.rs index 50effcfe32..d862d6bcfa 100644 --- a/vendor/miow/src/iocp.rs +++ b/vendor/miow/src/iocp.rs @@ -1,328 +1,328 @@ -//! Bindings to IOCP, I/O Completion Ports - -use std::cmp; -use std::fmt; -use std::io; -use std::mem; -use std::os::windows::io::*; -use std::time::Duration; - -use crate::handle::Handle; -use winapi::shared::basetsd::*; -use winapi::shared::ntdef::*; -use winapi::um::handleapi::*; -use winapi::um::ioapiset::*; -use winapi::um::minwinbase::*; -use crate::Overlapped; - -/// A handle to an Windows I/O Completion Port. -#[derive(Debug)] -pub struct CompletionPort { - handle: Handle, -} - -/// A status message received from an I/O completion port. -/// -/// These statuses can be created via the `new` or `empty` constructors and then -/// provided to a completion port, or they are read out of a completion port. -/// The fields of each status are read through its accessor methods. -#[derive(Clone, Copy)] -pub struct CompletionStatus(OVERLAPPED_ENTRY); - -impl fmt::Debug for CompletionStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CompletionStatus(OVERLAPPED_ENTRY)") - } -} - -unsafe impl Send for CompletionStatus {} -unsafe impl Sync for CompletionStatus {} - -impl CompletionPort { - /// Creates a new I/O completion port with the specified concurrency value. - /// - /// The number of threads given corresponds to the level of concurrency - /// allowed for threads associated with this port. Consult the Windows - /// documentation for more information about this value. - pub fn new(threads: u32) -> io::Result { - let ret = unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0 as *mut _, 0, threads) }; - if ret.is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(CompletionPort { - handle: Handle::new(ret), - }) - } - } - - /// Associates a new `HANDLE` to this I/O completion port. - /// - /// This function will associate the given handle to this port with the - /// given `token` to be returned in status messages whenever it receives a - /// notification. - /// - /// Any object which is convertible to a `HANDLE` via the `AsRawHandle` - /// trait can be provided to this function, such as `std::fs::File` and - /// friends. - pub fn add_handle(&self, token: usize, t: &T) -> io::Result<()> { - self._add(token, t.as_raw_handle()) - } - - /// Associates a new `SOCKET` to this I/O completion port. - /// - /// This function will associate the given socket to this port with the - /// given `token` to be returned in status messages whenever it receives a - /// notification. - /// - /// Any object which is convertible to a `SOCKET` via the `AsRawSocket` - /// trait can be provided to this function, such as `std::net::TcpStream` - /// and friends. - pub fn add_socket(&self, token: usize, t: &T) -> io::Result<()> { - self._add(token, t.as_raw_socket() as HANDLE) - } - - fn _add(&self, token: usize, handle: HANDLE) -> io::Result<()> { - assert_eq!(mem::size_of_val(&token), mem::size_of::()); - let ret = - unsafe { CreateIoCompletionPort(handle, self.handle.raw(), token as ULONG_PTR, 0) }; - if ret.is_null() { - Err(io::Error::last_os_error()) - } else { - debug_assert_eq!(ret, self.handle.raw()); - Ok(()) - } - } - - /// Dequeue a completion status from this I/O completion port. - /// - /// This function will associate the calling thread with this completion - /// port and then wait for a status message to become available. The precise - /// semantics on when this function returns depends on the concurrency value - /// specified when the port was created. - /// - /// A timeout can optionally be specified to this function. If `None` is - /// provided this function will not time out, and otherwise it will time out - /// after the specified duration has passed. - /// - /// On success this will return the status message which was dequeued from - /// this completion port. - pub fn get(&self, timeout: Option) -> io::Result { - let mut bytes = 0; - let mut token = 0; - let mut overlapped = 0 as *mut _; - let timeout = crate::dur2ms(timeout); - let ret = unsafe { - GetQueuedCompletionStatus( - self.handle.raw(), - &mut bytes, - &mut token, - &mut overlapped, - timeout, - ) - }; - crate::cvt(ret).map(|_| { - CompletionStatus(OVERLAPPED_ENTRY { - dwNumberOfBytesTransferred: bytes, - lpCompletionKey: token, - lpOverlapped: overlapped, - Internal: 0, - }) - }) - } - - /// Dequeues a number of completion statuses from this I/O completion port. - /// - /// This function is the same as `get` except that it may return more than - /// one status. A buffer of "zero" statuses is provided (the contents are - /// not read) and then on success this function will return a sub-slice of - /// statuses which represent those which were dequeued from this port. This - /// function does not wait to fill up the entire list of statuses provided. - /// - /// Like with `get`, a timeout may be specified for this operation. - pub fn get_many<'a>( - &self, - list: &'a mut [CompletionStatus], - timeout: Option, - ) -> io::Result<&'a mut [CompletionStatus]> { - debug_assert_eq!( - mem::size_of::(), - mem::size_of::() - ); - let mut removed = 0; - let timeout = crate::dur2ms(timeout); - let len = cmp::min(list.len(), ::max_value() as usize) as ULONG; - let ret = unsafe { - GetQueuedCompletionStatusEx( - self.handle.raw(), - list.as_ptr() as *mut _, - len, - &mut removed, - timeout, - FALSE as i32, - ) - }; - match crate::cvt(ret) { - Ok(_) => Ok(&mut list[..removed as usize]), - Err(e) => Err(e), - } - } - - /// Posts a new completion status onto this I/O completion port. - /// - /// This function will post the given status, with custom parameters, to the - /// port. Threads blocked in `get` or `get_many` will eventually receive - /// this status. - pub fn post(&self, status: CompletionStatus) -> io::Result<()> { - let ret = unsafe { - PostQueuedCompletionStatus( - self.handle.raw(), - status.0.dwNumberOfBytesTransferred, - status.0.lpCompletionKey, - status.0.lpOverlapped, - ) - }; - crate::cvt(ret).map(|_| ()) - } -} - -impl AsRawHandle for CompletionPort { - fn as_raw_handle(&self) -> HANDLE { - self.handle.raw() - } -} - -impl FromRawHandle for CompletionPort { - unsafe fn from_raw_handle(handle: HANDLE) -> CompletionPort { - CompletionPort { - handle: Handle::new(handle), - } - } -} - -impl IntoRawHandle for CompletionPort { - fn into_raw_handle(self) -> HANDLE { - self.handle.into_raw() - } -} - -impl CompletionStatus { - /// Creates a new completion status with the provided parameters. - /// - /// This function is useful when creating a status to send to a port with - /// the `post` method. The parameters are opaquely passed through and not - /// interpreted by the system at all. - pub fn new(bytes: u32, token: usize, overlapped: *mut Overlapped) -> CompletionStatus { - assert_eq!(mem::size_of_val(&token), mem::size_of::()); - CompletionStatus(OVERLAPPED_ENTRY { - dwNumberOfBytesTransferred: bytes, - lpCompletionKey: token as ULONG_PTR, - lpOverlapped: overlapped as *mut _, - Internal: 0, - }) - } - - /// Creates a new borrowed completion status from the borrowed - /// `OVERLAPPED_ENTRY` argument provided. - /// - /// This method will wrap the `OVERLAPPED_ENTRY` in a `CompletionStatus`, - /// returning the wrapped structure. - pub fn from_entry(entry: &OVERLAPPED_ENTRY) -> &CompletionStatus { - unsafe { &*(entry as *const _ as *const _) } - } - - /// Creates a new "zero" completion status. - /// - /// This function is useful when creating a stack buffer or vector of - /// completion statuses to be passed to the `get_many` function. - pub fn zero() -> CompletionStatus { - CompletionStatus::new(0, 0, 0 as *mut _) - } - - /// Returns the number of bytes that were transferred for the I/O operation - /// associated with this completion status. - pub fn bytes_transferred(&self) -> u32 { - self.0.dwNumberOfBytesTransferred - } - - /// Returns the completion key value associated with the file handle whose - /// I/O operation has completed. - /// - /// A completion key is a per-handle key that is specified when it is added - /// to an I/O completion port via `add_handle` or `add_socket`. - pub fn token(&self) -> usize { - self.0.lpCompletionKey as usize - } - - /// Returns a pointer to the `Overlapped` structure that was specified when - /// the I/O operation was started. - pub fn overlapped(&self) -> *mut OVERLAPPED { - self.0.lpOverlapped - } - - /// Returns a pointer to the internal `OVERLAPPED_ENTRY` object. - pub fn entry(&self) -> &OVERLAPPED_ENTRY { - &self.0 - } -} - -#[cfg(test)] -mod tests { - use std::mem; - use std::time::Duration; - - use winapi::shared::basetsd::*; - use winapi::shared::winerror::*; - - use crate::iocp::{CompletionPort, CompletionStatus}; - - #[test] - fn is_send_sync() { - fn is_send_sync() {} - is_send_sync::(); - } - - #[test] - fn token_right_size() { - assert_eq!(mem::size_of::(), mem::size_of::()); - } - - #[test] - fn timeout() { - let c = CompletionPort::new(1).unwrap(); - let err = c.get(Some(Duration::from_millis(1))).unwrap_err(); - assert_eq!(err.raw_os_error(), Some(WAIT_TIMEOUT as i32)); - } - - #[test] - fn get() { - let c = CompletionPort::new(1).unwrap(); - c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap(); - let s = c.get(None).unwrap(); - assert_eq!(s.bytes_transferred(), 1); - assert_eq!(s.token(), 2); - assert_eq!(s.overlapped(), 3 as *mut _); - } - - #[test] - fn get_many() { - let c = CompletionPort::new(1).unwrap(); - - c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap(); - c.post(CompletionStatus::new(4, 5, 6 as *mut _)).unwrap(); - - let mut s = vec![CompletionStatus::zero(); 4]; - { - let s = c.get_many(&mut s, None).unwrap(); - assert_eq!(s.len(), 2); - assert_eq!(s[0].bytes_transferred(), 1); - assert_eq!(s[0].token(), 2); - assert_eq!(s[0].overlapped(), 3 as *mut _); - assert_eq!(s[1].bytes_transferred(), 4); - assert_eq!(s[1].token(), 5); - assert_eq!(s[1].overlapped(), 6 as *mut _); - } - assert_eq!(s[2].bytes_transferred(), 0); - assert_eq!(s[2].token(), 0); - assert_eq!(s[2].overlapped(), 0 as *mut _); - } -} +//! Bindings to IOCP, I/O Completion Ports + +use std::cmp; +use std::fmt; +use std::io; +use std::mem; +use std::os::windows::io::*; +use std::time::Duration; + +use crate::handle::Handle; +use crate::Overlapped; +use winapi::shared::basetsd::*; +use winapi::shared::ntdef::*; +use winapi::um::handleapi::*; +use winapi::um::ioapiset::*; +use winapi::um::minwinbase::*; + +/// A handle to an Windows I/O Completion Port. +#[derive(Debug)] +pub struct CompletionPort { + handle: Handle, +} + +/// A status message received from an I/O completion port. +/// +/// These statuses can be created via the `new` or `empty` constructors and then +/// provided to a completion port, or they are read out of a completion port. +/// The fields of each status are read through its accessor methods. +#[derive(Clone, Copy)] +pub struct CompletionStatus(OVERLAPPED_ENTRY); + +impl fmt::Debug for CompletionStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CompletionStatus(OVERLAPPED_ENTRY)") + } +} + +unsafe impl Send for CompletionStatus {} +unsafe impl Sync for CompletionStatus {} + +impl CompletionPort { + /// Creates a new I/O completion port with the specified concurrency value. + /// + /// The number of threads given corresponds to the level of concurrency + /// allowed for threads associated with this port. Consult the Windows + /// documentation for more information about this value. + pub fn new(threads: u32) -> io::Result { + let ret = unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0 as *mut _, 0, threads) }; + if ret.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(CompletionPort { + handle: Handle::new(ret), + }) + } + } + + /// Associates a new `HANDLE` to this I/O completion port. + /// + /// This function will associate the given handle to this port with the + /// given `token` to be returned in status messages whenever it receives a + /// notification. + /// + /// Any object which is convertible to a `HANDLE` via the `AsRawHandle` + /// trait can be provided to this function, such as `std::fs::File` and + /// friends. + pub fn add_handle(&self, token: usize, t: &T) -> io::Result<()> { + self._add(token, t.as_raw_handle()) + } + + /// Associates a new `SOCKET` to this I/O completion port. + /// + /// This function will associate the given socket to this port with the + /// given `token` to be returned in status messages whenever it receives a + /// notification. + /// + /// Any object which is convertible to a `SOCKET` via the `AsRawSocket` + /// trait can be provided to this function, such as `std::net::TcpStream` + /// and friends. + pub fn add_socket(&self, token: usize, t: &T) -> io::Result<()> { + self._add(token, t.as_raw_socket() as HANDLE) + } + + fn _add(&self, token: usize, handle: HANDLE) -> io::Result<()> { + assert_eq!(mem::size_of_val(&token), mem::size_of::()); + let ret = + unsafe { CreateIoCompletionPort(handle, self.handle.raw(), token as ULONG_PTR, 0) }; + if ret.is_null() { + Err(io::Error::last_os_error()) + } else { + debug_assert_eq!(ret, self.handle.raw()); + Ok(()) + } + } + + /// Dequeue a completion status from this I/O completion port. + /// + /// This function will associate the calling thread with this completion + /// port and then wait for a status message to become available. The precise + /// semantics on when this function returns depends on the concurrency value + /// specified when the port was created. + /// + /// A timeout can optionally be specified to this function. If `None` is + /// provided this function will not time out, and otherwise it will time out + /// after the specified duration has passed. + /// + /// On success this will return the status message which was dequeued from + /// this completion port. + pub fn get(&self, timeout: Option) -> io::Result { + let mut bytes = 0; + let mut token = 0; + let mut overlapped = 0 as *mut _; + let timeout = crate::dur2ms(timeout); + let ret = unsafe { + GetQueuedCompletionStatus( + self.handle.raw(), + &mut bytes, + &mut token, + &mut overlapped, + timeout, + ) + }; + crate::cvt(ret).map(|_| { + CompletionStatus(OVERLAPPED_ENTRY { + dwNumberOfBytesTransferred: bytes, + lpCompletionKey: token, + lpOverlapped: overlapped, + Internal: 0, + }) + }) + } + + /// Dequeues a number of completion statuses from this I/O completion port. + /// + /// This function is the same as `get` except that it may return more than + /// one status. A buffer of "zero" statuses is provided (the contents are + /// not read) and then on success this function will return a sub-slice of + /// statuses which represent those which were dequeued from this port. This + /// function does not wait to fill up the entire list of statuses provided. + /// + /// Like with `get`, a timeout may be specified for this operation. + pub fn get_many<'a>( + &self, + list: &'a mut [CompletionStatus], + timeout: Option, + ) -> io::Result<&'a mut [CompletionStatus]> { + debug_assert_eq!( + mem::size_of::(), + mem::size_of::() + ); + let mut removed = 0; + let timeout = crate::dur2ms(timeout); + let len = cmp::min(list.len(), ::max_value() as usize) as ULONG; + let ret = unsafe { + GetQueuedCompletionStatusEx( + self.handle.raw(), + list.as_ptr() as *mut _, + len, + &mut removed, + timeout, + FALSE as i32, + ) + }; + match crate::cvt(ret) { + Ok(_) => Ok(&mut list[..removed as usize]), + Err(e) => Err(e), + } + } + + /// Posts a new completion status onto this I/O completion port. + /// + /// This function will post the given status, with custom parameters, to the + /// port. Threads blocked in `get` or `get_many` will eventually receive + /// this status. + pub fn post(&self, status: CompletionStatus) -> io::Result<()> { + let ret = unsafe { + PostQueuedCompletionStatus( + self.handle.raw(), + status.0.dwNumberOfBytesTransferred, + status.0.lpCompletionKey, + status.0.lpOverlapped, + ) + }; + crate::cvt(ret).map(|_| ()) + } +} + +impl AsRawHandle for CompletionPort { + fn as_raw_handle(&self) -> HANDLE { + self.handle.raw() + } +} + +impl FromRawHandle for CompletionPort { + unsafe fn from_raw_handle(handle: HANDLE) -> CompletionPort { + CompletionPort { + handle: Handle::new(handle), + } + } +} + +impl IntoRawHandle for CompletionPort { + fn into_raw_handle(self) -> HANDLE { + self.handle.into_raw() + } +} + +impl CompletionStatus { + /// Creates a new completion status with the provided parameters. + /// + /// This function is useful when creating a status to send to a port with + /// the `post` method. The parameters are opaquely passed through and not + /// interpreted by the system at all. + pub fn new(bytes: u32, token: usize, overlapped: *mut Overlapped) -> CompletionStatus { + assert_eq!(mem::size_of_val(&token), mem::size_of::()); + CompletionStatus(OVERLAPPED_ENTRY { + dwNumberOfBytesTransferred: bytes, + lpCompletionKey: token as ULONG_PTR, + lpOverlapped: overlapped as *mut _, + Internal: 0, + }) + } + + /// Creates a new borrowed completion status from the borrowed + /// `OVERLAPPED_ENTRY` argument provided. + /// + /// This method will wrap the `OVERLAPPED_ENTRY` in a `CompletionStatus`, + /// returning the wrapped structure. + pub fn from_entry(entry: &OVERLAPPED_ENTRY) -> &CompletionStatus { + unsafe { &*(entry as *const _ as *const _) } + } + + /// Creates a new "zero" completion status. + /// + /// This function is useful when creating a stack buffer or vector of + /// completion statuses to be passed to the `get_many` function. + pub fn zero() -> CompletionStatus { + CompletionStatus::new(0, 0, 0 as *mut _) + } + + /// Returns the number of bytes that were transferred for the I/O operation + /// associated with this completion status. + pub fn bytes_transferred(&self) -> u32 { + self.0.dwNumberOfBytesTransferred + } + + /// Returns the completion key value associated with the file handle whose + /// I/O operation has completed. + /// + /// A completion key is a per-handle key that is specified when it is added + /// to an I/O completion port via `add_handle` or `add_socket`. + pub fn token(&self) -> usize { + self.0.lpCompletionKey as usize + } + + /// Returns a pointer to the `Overlapped` structure that was specified when + /// the I/O operation was started. + pub fn overlapped(&self) -> *mut OVERLAPPED { + self.0.lpOverlapped + } + + /// Returns a pointer to the internal `OVERLAPPED_ENTRY` object. + pub fn entry(&self) -> &OVERLAPPED_ENTRY { + &self.0 + } +} + +#[cfg(test)] +mod tests { + use std::mem; + use std::time::Duration; + + use winapi::shared::basetsd::*; + use winapi::shared::winerror::*; + + use crate::iocp::{CompletionPort, CompletionStatus}; + + #[test] + fn is_send_sync() { + fn is_send_sync() {} + is_send_sync::(); + } + + #[test] + fn token_right_size() { + assert_eq!(mem::size_of::(), mem::size_of::()); + } + + #[test] + fn timeout() { + let c = CompletionPort::new(1).unwrap(); + let err = c.get(Some(Duration::from_millis(1))).unwrap_err(); + assert_eq!(err.raw_os_error(), Some(WAIT_TIMEOUT as i32)); + } + + #[test] + fn get() { + let c = CompletionPort::new(1).unwrap(); + c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap(); + let s = c.get(None).unwrap(); + assert_eq!(s.bytes_transferred(), 1); + assert_eq!(s.token(), 2); + assert_eq!(s.overlapped(), 3 as *mut _); + } + + #[test] + fn get_many() { + let c = CompletionPort::new(1).unwrap(); + + c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap(); + c.post(CompletionStatus::new(4, 5, 6 as *mut _)).unwrap(); + + let mut s = vec![CompletionStatus::zero(); 4]; + { + let s = c.get_many(&mut s, None).unwrap(); + assert_eq!(s.len(), 2); + assert_eq!(s[0].bytes_transferred(), 1); + assert_eq!(s[0].token(), 2); + assert_eq!(s[0].overlapped(), 3 as *mut _); + assert_eq!(s[1].bytes_transferred(), 4); + assert_eq!(s[1].token(), 5); + assert_eq!(s[1].overlapped(), 6 as *mut _); + } + assert_eq!(s[2].bytes_transferred(), 0); + assert_eq!(s[2].token(), 0); + assert_eq!(s[2].overlapped(), 0 as *mut _); + } +} diff --git a/vendor/miow/src/lib.rs b/vendor/miow/src/lib.rs index f970d15930..e1139a3f4f 100644 --- a/vendor/miow/src/lib.rs +++ b/vendor/miow/src/lib.rs @@ -1,58 +1,58 @@ -//! A zero overhead Windows I/O library - -#![cfg(windows)] -#![deny(missing_docs)] -#![allow(bad_style)] -#![doc(html_root_url = "https://docs.rs/miow/0.3/x86_64-pc-windows-msvc/")] - -extern crate socket2; -extern crate winapi; - -#[cfg(test)] -extern crate rand; - -use std::cmp; -use std::io; -use std::time::Duration; - -use winapi::shared::minwindef::*; -use winapi::um::winbase::*; - -#[cfg(test)] -macro_rules! t { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {:?}", stringify!($e), e), - } - }; -} - -mod handle; -mod overlapped; - -pub mod iocp; -pub mod net; -pub mod pipe; - -pub use crate::overlapped::Overlapped; - -fn cvt(i: BOOL) -> io::Result { - if i == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(i) - } -} - -fn dur2ms(dur: Option) -> u32 { - let dur = match dur { - Some(dur) => dur, - None => return INFINITE, - }; - let ms = dur.as_secs().checked_mul(1_000); - let ms_extra = dur.subsec_nanos() / 1_000_000; - ms.and_then(|ms| ms.checked_add(ms_extra as u64)) - .map(|ms| cmp::min(u32::max_value() as u64, ms) as u32) - .unwrap_or(INFINITE - 1) -} +//! A zero overhead Windows I/O library + +#![cfg(windows)] +#![deny(missing_docs)] +#![allow(bad_style)] +#![doc(html_root_url = "https://docs.rs/miow/0.3/x86_64-pc-windows-msvc/")] + +extern crate socket2; +extern crate winapi; + +#[cfg(test)] +extern crate rand; + +use std::cmp; +use std::io; +use std::time::Duration; + +use winapi::shared::minwindef::*; +use winapi::um::winbase::*; + +#[cfg(test)] +macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + } + }; +} + +mod handle; +mod overlapped; + +pub mod iocp; +pub mod net; +pub mod pipe; + +pub use crate::overlapped::Overlapped; + +fn cvt(i: BOOL) -> io::Result { + if i == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(i) + } +} + +fn dur2ms(dur: Option) -> u32 { + let dur = match dur { + Some(dur) => dur, + None => return INFINITE, + }; + let ms = dur.as_secs().checked_mul(1_000); + let ms_extra = dur.subsec_nanos() / 1_000_000; + ms.and_then(|ms| ms.checked_add(ms_extra as u64)) + .map(|ms| cmp::min(u32::max_value() as u64, ms) as u32) + .unwrap_or(INFINITE - 1) +} diff --git a/vendor/miow/src/net.rs b/vendor/miow/src/net.rs index 237a8949e1..def109c0a4 100644 --- a/vendor/miow/src/net.rs +++ b/vendor/miow/src/net.rs @@ -1,1242 +1,1338 @@ -//! Extensions and types for the standard networking primitives. -//! -//! This module contains a number of extension traits for the types in -//! `std::net` for Windows-specific functionality. - -use std::cmp; -use std::io; -use std::mem; -use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; -use std::net::{SocketAddr, TcpListener, TcpStream, UdpSocket}; -use std::os::windows::prelude::*; -use std::sync::atomic::{AtomicUsize, Ordering}; - -use winapi::ctypes::*; -use winapi::shared::guiddef::*; -use winapi::shared::minwindef::*; -use winapi::shared::minwindef::{FALSE, TRUE}; -use winapi::shared::ntdef::*; -use winapi::shared::ws2def::SOL_SOCKET; -use winapi::shared::ws2def::*; -use winapi::shared::ws2ipdef::*; -use winapi::um::minwinbase::*; -use winapi::um::winsock2::*; - -/// A type to represent a buffer in which a socket address will be stored. -/// -/// This type is used with the `recv_from_overlapped` function on the -/// `UdpSocketExt` trait to provide space for the overlapped I/O operation to -/// fill in the address upon completion. -#[derive(Clone, Copy)] -pub struct SocketAddrBuf { - buf: SOCKADDR_STORAGE, - len: c_int, -} - -/// A type to represent a buffer in which an accepted socket's address will be -/// stored. -/// -/// This type is used with the `accept_overlapped` method on the -/// `TcpListenerExt` trait to provide space for the overlapped I/O operation to -/// fill in the socket addresses upon completion. -#[repr(C)] -pub struct AcceptAddrsBuf { - // For AcceptEx we've got the restriction that the addresses passed in that - // buffer need to be at least 16 bytes more than the maximum address length - // for the protocol in question, so add some extra here and there - local: SOCKADDR_STORAGE, - _pad1: [u8; 16], - remote: SOCKADDR_STORAGE, - _pad2: [u8; 16], -} - -/// The parsed return value of `AcceptAddrsBuf`. -pub struct AcceptAddrs<'a> { - local: LPSOCKADDR, - local_len: c_int, - remote: LPSOCKADDR, - remote_len: c_int, - _data: &'a AcceptAddrsBuf, -} - -struct WsaExtension { - guid: GUID, - val: AtomicUsize, -} - -/// Additional methods for the `TcpStream` type in the standard library. -pub trait TcpStreamExt { - /// Execute an overlapped read I/O operation on this TCP stream. - /// - /// This function will issue an overlapped I/O read (via `WSARecv`) on this - /// socket. The provided buffer will be filled in when the operation - /// completes and the given `OVERLAPPED` instance is used to track the - /// overlapped operation. - /// - /// If the operation succeeds, `Ok(Some(n))` is returned indicating how - /// many bytes were read. If the operation returns an error indicating that - /// the I/O is currently pending, `Ok(None)` is returned. Otherwise, the - /// error associated with the operation is returned and no overlapped - /// operation is enqueued. - /// - /// The number of bytes read will be returned as part of the completion - /// notification when the I/O finishes. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf` and - /// `overlapped` pointers are valid until the end of the I/O operation. The - /// kernel also requires that `overlapped` is unique for this I/O operation - /// and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that these two input - /// pointers are valid until the I/O operation is completed, typically via - /// completion ports and waiting to receive the completion notification on - /// the port. - unsafe fn read_overlapped( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result>; - - /// Execute an overlapped write I/O operation on this TCP stream. - /// - /// This function will issue an overlapped I/O write (via `WSASend`) on this - /// socket. The provided buffer will be written when the operation completes - /// and the given `OVERLAPPED` instance is used to track the overlapped - /// operation. - /// - /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the - /// number of bytes that were written. If the operation returns an error - /// indicating that the I/O is currently pending, `Ok(None)` is returned. - /// Otherwise, the error associated with the operation is returned and no - /// overlapped operation is enqueued. - /// - /// The number of bytes written will be returned as part of the completion - /// notification when the I/O finishes. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf` and - /// `overlapped` pointers are valid until the end of the I/O operation. The - /// kernel also requires that `overlapped` is unique for this I/O operation - /// and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that these two input - /// pointers are valid until the I/O operation is completed, typically via - /// completion ports and waiting to receive the completion notification on - /// the port. - unsafe fn write_overlapped( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result>; - - /// Attempt to consume the internal socket in this builder by executing an - /// overlapped connect operation. - /// - /// This function will issue a connect operation to the address specified on - /// the underlying socket, flagging it as an overlapped operation which will - /// complete asynchronously. If successful this function will return the - /// corresponding TCP stream. - /// - /// The `buf` argument provided is an initial buffer of data that should be - /// sent after the connection is initiated. It's acceptable to - /// pass an empty slice here. - /// - /// This function will also return whether the connect immediately - /// succeeded or not. If `None` is returned then the I/O operation is still - /// pending and will complete at a later date, and if `Some(bytes)` is - /// returned then that many bytes were transferred. - /// - /// Note that to succeed this requires that the underlying socket has - /// previously been bound via a call to `bind` to a local address. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the - /// `overlapped` and `buf` pointers to be valid until the end of the I/O - /// operation. The kernel also requires that `overlapped` is unique for - /// this I/O operation and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that this pointer is - /// valid until the I/O operation is completed, typically via completion - /// ports and waiting to receive the completion notification on the port. - unsafe fn connect_overlapped( - &self, - addr: &SocketAddr, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result>; - - /// Once a `connect_overlapped` has finished, this function needs to be - /// called to finish the connect operation. - /// - /// Currently this just calls `setsockopt` with `SO_UPDATE_CONNECT_CONTEXT` - /// to ensure that further functions like `getpeername` and `getsockname` - /// work correctly. - fn connect_complete(&self) -> io::Result<()>; - - /// Calls the `GetOverlappedResult` function to get the result of an - /// overlapped operation for this handle. - /// - /// This function takes the `OVERLAPPED` argument which must have been used - /// to initiate an overlapped I/O operation, and returns either the - /// successful number of bytes transferred during the operation or an error - /// if one occurred, along with the results of the `lpFlags` parameter of - /// the relevant operation, if applicable. - /// - /// # Unsafety - /// - /// This function is unsafe as `overlapped` must have previously been used - /// to execute an operation for this handle, and it must also be a valid - /// pointer to an `OVERLAPPED` instance. - /// - /// # Panics - /// - /// This function will panic - unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)>; -} - -/// Additional methods for the `UdpSocket` type in the standard library. -pub trait UdpSocketExt { - /// Execute an overlapped receive I/O operation on this UDP socket. - /// - /// This function will issue an overlapped I/O read (via `WSARecvFrom`) on - /// this socket. The provided buffer will be filled in when the operation - /// completes, the source from where the data came from will be written to - /// `addr`, and the given `OVERLAPPED` instance is used to track the - /// overlapped operation. - /// - /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the - /// number of bytes that were read. If the operation returns an error - /// indicating that the I/O is currently pending, `Ok(None)` is returned. - /// Otherwise, the error associated with the operation is returned and no - /// overlapped operation is enqueued. - /// - /// The number of bytes read will be returned as part of the completion - /// notification when the I/O finishes. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf`, - /// `addr`, and `overlapped` pointers are valid until the end of the I/O - /// operation. The kernel also requires that `overlapped` is unique for this - /// I/O operation and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that these two input - /// pointers are valid until the I/O operation is completed, typically via - /// completion ports and waiting to receive the completion notification on - /// the port. - unsafe fn recv_from_overlapped( - &self, - buf: &mut [u8], - addr: *mut SocketAddrBuf, - overlapped: *mut OVERLAPPED, - ) -> io::Result>; - - /// Execute an overlapped receive I/O operation on this UDP socket. - /// - /// This function will issue an overlapped I/O read (via `WSARecv`) on - /// this socket. The provided buffer will be filled in when the operation - /// completes, the source from where the data came from will be written to - /// `addr`, and the given `OVERLAPPED` instance is used to track the - /// overlapped operation. - /// - /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the - /// number of bytes that were read. If the operation returns an error - /// indicating that the I/O is currently pending, `Ok(None)` is returned. - /// Otherwise, the error associated with the operation is returned and no - /// overlapped operation is enqueued. - /// - /// The number of bytes read will be returned as part of the completion - /// notification when the I/O finishes. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf`, - /// and `overlapped` pointers are valid until the end of the I/O - /// operation. The kernel also requires that `overlapped` is unique for this - /// I/O operation and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that these two input - /// pointers are valid until the I/O operation is completed, typically via - /// completion ports and waiting to receive the completion notification on - /// the port. - unsafe fn recv_overlapped( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result>; - - /// Execute an overlapped send I/O operation on this UDP socket. - /// - /// This function will issue an overlapped I/O write (via `WSASendTo`) on - /// this socket to the address specified by `addr`. The provided buffer will - /// be written when the operation completes and the given `OVERLAPPED` - /// instance is used to track the overlapped operation. - /// - /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte - /// were written. If the operation returns an error indicating that the I/O - /// is currently pending, `Ok(None)` is returned. Otherwise, the error - /// associated with the operation is returned and no overlapped operation - /// is enqueued. - /// - /// The number of bytes written will be returned as part of the completion - /// notification when the I/O finishes. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf` and - /// `overlapped` pointers are valid until the end of the I/O operation. The - /// kernel also requires that `overlapped` is unique for this I/O operation - /// and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that these two input - /// pointers are valid until the I/O operation is completed, typically via - /// completion ports and waiting to receive the completion notification on - /// the port. - unsafe fn send_to_overlapped( - &self, - buf: &[u8], - addr: &SocketAddr, - overlapped: *mut OVERLAPPED, - ) -> io::Result>; - - /// Execute an overlapped send I/O operation on this UDP socket. - /// - /// This function will issue an overlapped I/O write (via `WSASend`) on - /// this socket to the address it was previously connected to. The provided - /// buffer will be written when the operation completes and the given `OVERLAPPED` - /// instance is used to track the overlapped operation. - /// - /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte - /// were written. If the operation returns an error indicating that the I/O - /// is currently pending, `Ok(None)` is returned. Otherwise, the error - /// associated with the operation is returned and no overlapped operation - /// is enqueued. - /// - /// The number of bytes written will be returned as part of the completion - /// notification when the I/O finishes. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf` and - /// `overlapped` pointers are valid until the end of the I/O operation. The - /// kernel also requires that `overlapped` is unique for this I/O operation - /// and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that these two input - /// pointers are valid until the I/O operation is completed, typically via - /// completion ports and waiting to receive the completion notification on - /// the port. - unsafe fn send_overlapped( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result>; - - /// Calls the `GetOverlappedResult` function to get the result of an - /// overlapped operation for this handle. - /// - /// This function takes the `OVERLAPPED` argument which must have been used - /// to initiate an overlapped I/O operation, and returns either the - /// successful number of bytes transferred during the operation or an error - /// if one occurred, along with the results of the `lpFlags` parameter of - /// the relevant operation, if applicable. - /// - /// # Unsafety - /// - /// This function is unsafe as `overlapped` must have previously been used - /// to execute an operation for this handle, and it must also be a valid - /// pointer to an `OVERLAPPED` instance. - /// - /// # Panics - /// - /// This function will panic - unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)>; -} - -/// Additional methods for the `TcpListener` type in the standard library. -pub trait TcpListenerExt { - /// Perform an accept operation on this listener, accepting a connection in - /// an overlapped fashion. - /// - /// This function will issue an I/O request to accept an incoming connection - /// with the specified overlapped instance. The `socket` provided must be a - /// configured but not bound or connected socket, and if successful this - /// will consume the internal socket of the builder to return a TCP stream. - /// - /// The `addrs` buffer provided will be filled in with the local and remote - /// addresses of the connection upon completion. - /// - /// If the accept succeeds immediately, `Ok(true)` is returned. If - /// the connect indicates that the I/O is currently pending, `Ok(false)` is - /// returned. Otherwise, the error associated with the operation is - /// returned and no overlapped operation is enqueued. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the - /// `addrs` and `overlapped` pointers are valid until the end of the I/O - /// operation. The kernel also requires that `overlapped` is unique for this - /// I/O operation and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that the pointers are - /// valid until the I/O operation is completed, typically via completion - /// ports and waiting to receive the completion notification on the port. - unsafe fn accept_overlapped( - &self, - socket: &TcpStream, - addrs: &mut AcceptAddrsBuf, - overlapped: *mut OVERLAPPED, - ) -> io::Result; - - /// Once an `accept_overlapped` has finished, this function needs to be - /// called to finish the accept operation. - /// - /// Currently this just calls `setsockopt` with `SO_UPDATE_ACCEPT_CONTEXT` - /// to ensure that further functions like `getpeername` and `getsockname` - /// work correctly. - fn accept_complete(&self, socket: &TcpStream) -> io::Result<()>; - - /// Calls the `GetOverlappedResult` function to get the result of an - /// overlapped operation for this handle. - /// - /// This function takes the `OVERLAPPED` argument which must have been used - /// to initiate an overlapped I/O operation, and returns either the - /// successful number of bytes transferred during the operation or an error - /// if one occurred, along with the results of the `lpFlags` parameter of - /// the relevant operation, if applicable. - /// - /// # Unsafety - /// - /// This function is unsafe as `overlapped` must have previously been used - /// to execute an operation for this handle, and it must also be a valid - /// pointer to an `OVERLAPPED` instance. - /// - /// # Panics - /// - /// This function will panic - unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)>; -} - -#[doc(hidden)] -trait NetInt { - fn from_be(i: Self) -> Self; - fn to_be(&self) -> Self; -} -macro_rules! doit { - ($($t:ident)*) => ($(impl NetInt for $t { - fn from_be(i: Self) -> Self { <$t>::from_be(i) } - fn to_be(&self) -> Self { <$t>::to_be(*self) } - })*) -} -doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } - -// fn hton(i: I) -> I { i.to_be() } -fn ntoh(i: I) -> I { - I::from_be(i) -} - -fn last_err() -> io::Result> { - let err = unsafe { WSAGetLastError() }; - if err == WSA_IO_PENDING as i32 { - Ok(None) - } else { - Err(io::Error::from_raw_os_error(err)) - } -} - -fn cvt(i: c_int, size: DWORD) -> io::Result> { - if i == SOCKET_ERROR { - last_err() - } else { - Ok(Some(size as usize)) - } -} - -fn socket_addr_to_ptrs(addr: &SocketAddr) -> (*const SOCKADDR, c_int) { - match *addr { - SocketAddr::V4(ref a) => ( - a as *const _ as *const _, - mem::size_of::() as c_int, - ), - SocketAddr::V6(ref a) => ( - a as *const _ as *const _, - mem::size_of::() as c_int, - ), - } -} - -unsafe fn ptrs_to_socket_addr(ptr: *const SOCKADDR, len: c_int) -> Option { - if (len as usize) < mem::size_of::() { - return None; - } - match (*ptr).sa_family as i32 { - AF_INET if len as usize >= mem::size_of::() => { - let b = &*(ptr as *const SOCKADDR_IN); - let ip = ntoh(*b.sin_addr.S_un.S_addr()); - let ip = Ipv4Addr::new( - (ip >> 24) as u8, - (ip >> 16) as u8, - (ip >> 8) as u8, - (ip >> 0) as u8, - ); - Some(SocketAddr::V4(SocketAddrV4::new(ip, ntoh(b.sin_port)))) - } - AF_INET6 if len as usize >= mem::size_of::() => { - let b = &*(ptr as *const SOCKADDR_IN6_LH); - let arr = b.sin6_addr.u.Byte(); - let ip = Ipv6Addr::new( - ((arr[0] as u16) << 8) | (arr[1] as u16), - ((arr[2] as u16) << 8) | (arr[3] as u16), - ((arr[4] as u16) << 8) | (arr[5] as u16), - ((arr[6] as u16) << 8) | (arr[7] as u16), - ((arr[8] as u16) << 8) | (arr[9] as u16), - ((arr[10] as u16) << 8) | (arr[11] as u16), - ((arr[12] as u16) << 8) | (arr[13] as u16), - ((arr[14] as u16) << 8) | (arr[15] as u16), - ); - let addr = SocketAddrV6::new( - ip, - ntoh(b.sin6_port), - ntoh(b.sin6_flowinfo), - ntoh(*b.u.sin6_scope_id()), - ); - Some(SocketAddr::V6(addr)) - } - _ => None, - } -} - -unsafe fn slice2buf(slice: &[u8]) -> WSABUF { - WSABUF { - len: cmp::min(slice.len(), ::max_value() as usize) as u_long, - buf: slice.as_ptr() as *mut _, - } -} - -unsafe fn result(socket: SOCKET, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { - let mut transferred = 0; - let mut flags = 0; - let r = WSAGetOverlappedResult(socket, overlapped, &mut transferred, FALSE, &mut flags); - if r == 0 { - Err(io::Error::last_os_error()) - } else { - Ok((transferred as usize, flags)) - } -} - -impl TcpStreamExt for TcpStream { - unsafe fn read_overlapped( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - let mut buf = slice2buf(buf); - let mut flags = 0; - let mut bytes_read: DWORD = 0; - let r = WSARecv( - self.as_raw_socket() as SOCKET, - &mut buf, - 1, - &mut bytes_read, - &mut flags, - overlapped, - None, - ); - cvt(r, bytes_read) - } - - unsafe fn write_overlapped( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - let mut buf = slice2buf(buf); - let mut bytes_written = 0; - - // Note here that we capture the number of bytes written. The - // documentation on MSDN, however, states: - // - // > Use NULL for this parameter if the lpOverlapped parameter is not - // > NULL to avoid potentially erroneous results. This parameter can be - // > NULL only if the lpOverlapped parameter is not NULL. - // - // If we're not passing a null overlapped pointer here, then why are we - // then capturing the number of bytes! Well so it turns out that this is - // clearly faster to learn the bytes here rather than later calling - // `WSAGetOverlappedResult`, and in practice almost all implementations - // use this anyway [1]. - // - // As a result we use this to and report back the result. - // - // [1]: https://github.com/carllerche/mio/pull/520#issuecomment-273983823 - let r = WSASend( - self.as_raw_socket() as SOCKET, - &mut buf, - 1, - &mut bytes_written, - 0, - overlapped, - None, - ); - cvt(r, bytes_written) - } - - unsafe fn connect_overlapped( - &self, - addr: &SocketAddr, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - connect_overlapped(self.as_raw_socket() as SOCKET, addr, buf, overlapped) - } - - fn connect_complete(&self) -> io::Result<()> { - const SO_UPDATE_CONNECT_CONTEXT: c_int = 0x7010; - let result = unsafe { - setsockopt( - self.as_raw_socket() as SOCKET, - SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - 0 as *const _, - 0, - ) - }; - if result == 0 { - Ok(()) - } else { - Err(io::Error::last_os_error()) - } - } - - unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { - result(self.as_raw_socket() as SOCKET, overlapped) - } -} - -unsafe fn connect_overlapped( - socket: SOCKET, - addr: &SocketAddr, - buf: &[u8], - overlapped: *mut OVERLAPPED, -) -> io::Result> { - static CONNECTEX: WsaExtension = WsaExtension { - guid: GUID { - Data1: 0x25a207b9, - Data2: 0xddf3, - Data3: 0x4660, - Data4: [0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e], - }, - val: AtomicUsize::new(0), - }; - type ConnectEx = unsafe extern "system" fn( - SOCKET, - *const SOCKADDR, - c_int, - PVOID, - DWORD, - LPDWORD, - LPOVERLAPPED, - ) -> BOOL; - - let ptr = CONNECTEX.get(socket)?; - assert!(ptr != 0); - let connect_ex = mem::transmute::<_, ConnectEx>(ptr); - - let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); - let mut bytes_sent: DWORD = 0; - let r = connect_ex( - socket, - addr_buf, - addr_len, - buf.as_ptr() as *mut _, - buf.len() as u32, - &mut bytes_sent, - overlapped, - ); - if r == TRUE { - Ok(Some(bytes_sent as usize)) - } else { - last_err() - } -} - -impl UdpSocketExt for UdpSocket { - unsafe fn recv_from_overlapped( - &self, - buf: &mut [u8], - addr: *mut SocketAddrBuf, - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - let mut buf = slice2buf(buf); - let mut flags = 0; - let mut received_bytes: DWORD = 0; - let r = WSARecvFrom( - self.as_raw_socket() as SOCKET, - &mut buf, - 1, - &mut received_bytes, - &mut flags, - &mut (*addr).buf as *mut _ as *mut _, - &mut (*addr).len, - overlapped, - None, - ); - cvt(r, received_bytes) - } - - unsafe fn recv_overlapped( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - let mut buf = slice2buf(buf); - let mut flags = 0; - let mut received_bytes: DWORD = 0; - let r = WSARecv( - self.as_raw_socket() as SOCKET, - &mut buf, - 1, - &mut received_bytes, - &mut flags, - overlapped, - None, - ); - cvt(r, received_bytes) - } - - unsafe fn send_to_overlapped( - &self, - buf: &[u8], - addr: &SocketAddr, - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); - let mut buf = slice2buf(buf); - let mut sent_bytes = 0; - let r = WSASendTo( - self.as_raw_socket() as SOCKET, - &mut buf, - 1, - &mut sent_bytes, - 0, - addr_buf as *const _, - addr_len, - overlapped, - None, - ); - cvt(r, sent_bytes) - } - - unsafe fn send_overlapped( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - let mut buf = slice2buf(buf); - let mut sent_bytes = 0; - let r = WSASend( - self.as_raw_socket() as SOCKET, - &mut buf, - 1, - &mut sent_bytes, - 0, - overlapped, - None, - ); - cvt(r, sent_bytes) - } - - unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { - result(self.as_raw_socket() as SOCKET, overlapped) - } -} - -impl TcpListenerExt for TcpListener { - unsafe fn accept_overlapped( - &self, - socket: &TcpStream, - addrs: &mut AcceptAddrsBuf, - overlapped: *mut OVERLAPPED, - ) -> io::Result { - static ACCEPTEX: WsaExtension = WsaExtension { - guid: GUID { - Data1: 0xb5367df1, - Data2: 0xcbac, - Data3: 0x11cf, - Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92], - }, - val: AtomicUsize::new(0), - }; - type AcceptEx = unsafe extern "system" fn( - SOCKET, - SOCKET, - PVOID, - DWORD, - DWORD, - DWORD, - LPDWORD, - LPOVERLAPPED, - ) -> BOOL; - - let ptr = ACCEPTEX.get(self.as_raw_socket() as SOCKET)?; - assert!(ptr != 0); - let accept_ex = mem::transmute::<_, AcceptEx>(ptr); - - let mut bytes = 0; - let (a, b, c, d) = (*addrs).args(); - let r = accept_ex( - self.as_raw_socket() as SOCKET, - socket.as_raw_socket() as SOCKET, - a, - b, - c, - d, - &mut bytes, - overlapped, - ); - let succeeded = if r == TRUE { - true - } else { - last_err()?; - false - }; - Ok(succeeded) - } - - fn accept_complete(&self, socket: &TcpStream) -> io::Result<()> { - const SO_UPDATE_ACCEPT_CONTEXT: c_int = 0x700B; - let me = self.as_raw_socket(); - let result = unsafe { - setsockopt( - socket.as_raw_socket() as SOCKET, - SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, - &me as *const _ as *const _, - mem::size_of_val(&me) as c_int, - ) - }; - if result == 0 { - Ok(()) - } else { - Err(io::Error::last_os_error()) - } - } - - unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { - result(self.as_raw_socket() as SOCKET, overlapped) - } -} - -impl SocketAddrBuf { - /// Creates a new blank socket address buffer. - /// - /// This should be used before a call to `recv_from_overlapped` overlapped - /// to create an instance to pass down. - pub fn new() -> SocketAddrBuf { - SocketAddrBuf { - buf: unsafe { mem::zeroed() }, - len: mem::size_of::() as c_int, - } - } - - /// Parses this buffer to return a standard socket address. - /// - /// This function should be called after the buffer has been filled in with - /// a call to `recv_from_overlapped` being completed. It will interpret the - /// address filled in and return the standard socket address type. - /// - /// If an error is encountered then `None` is returned. - pub fn to_socket_addr(&self) -> Option { - unsafe { ptrs_to_socket_addr(&self.buf as *const _ as *const _, self.len) } - } -} - -static GETACCEPTEXSOCKADDRS: WsaExtension = WsaExtension { - guid: GUID { - Data1: 0xb5367df2, - Data2: 0xcbac, - Data3: 0x11cf, - Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92], - }, - val: AtomicUsize::new(0), -}; -type GetAcceptExSockaddrs = unsafe extern "system" fn( - PVOID, - DWORD, - DWORD, - DWORD, - *mut LPSOCKADDR, - LPINT, - *mut LPSOCKADDR, - LPINT, -); - -impl AcceptAddrsBuf { - /// Creates a new blank buffer ready to be passed to a call to - /// `accept_overlapped`. - pub fn new() -> AcceptAddrsBuf { - unsafe { mem::zeroed() } - } - - /// Parses the data contained in this address buffer, returning the parsed - /// result if successful. - /// - /// This function can be called after a call to `accept_overlapped` has - /// succeeded to parse out the data that was written in. - pub fn parse(&self, socket: &TcpListener) -> io::Result { - let mut ret = AcceptAddrs { - local: 0 as *mut _, - local_len: 0, - remote: 0 as *mut _, - remote_len: 0, - _data: self, - }; - let ptr = GETACCEPTEXSOCKADDRS.get(socket.as_raw_socket() as SOCKET)?; - assert!(ptr != 0); - unsafe { - let get_sockaddrs = mem::transmute::<_, GetAcceptExSockaddrs>(ptr); - let (a, b, c, d) = self.args(); - get_sockaddrs( - a, - b, - c, - d, - &mut ret.local, - &mut ret.local_len, - &mut ret.remote, - &mut ret.remote_len, - ); - Ok(ret) - } - } - - fn args(&self) -> (PVOID, DWORD, DWORD, DWORD) { - let remote_offset = unsafe { &(*(0 as *const AcceptAddrsBuf)).remote as *const _ as usize }; - ( - self as *const _ as *mut _, - 0, - remote_offset as DWORD, - (mem::size_of_val(self) - remote_offset) as DWORD, - ) - } -} - -impl<'a> AcceptAddrs<'a> { - /// Returns the local socket address contained in this buffer. - pub fn local(&self) -> Option { - unsafe { ptrs_to_socket_addr(self.local, self.local_len) } - } - - /// Returns the remote socket address contained in this buffer. - pub fn remote(&self) -> Option { - unsafe { ptrs_to_socket_addr(self.remote, self.remote_len) } - } -} - -impl WsaExtension { - fn get(&self, socket: SOCKET) -> io::Result { - let prev = self.val.load(Ordering::SeqCst); - if prev != 0 && !cfg!(debug_assertions) { - return Ok(prev); - } - let mut ret = 0 as usize; - let mut bytes = 0; - let r = unsafe { - WSAIoctl( - socket, - SIO_GET_EXTENSION_FUNCTION_POINTER, - &self.guid as *const _ as *mut _, - mem::size_of_val(&self.guid) as DWORD, - &mut ret as *mut _ as *mut _, - mem::size_of_val(&ret) as DWORD, - &mut bytes, - 0 as *mut _, - None, - ) - }; - cvt(r, 0).map(|_| { - debug_assert_eq!(bytes as usize, mem::size_of_val(&ret)); - debug_assert!(prev == 0 || prev == ret); - self.val.store(ret, Ordering::SeqCst); - ret - }) - } -} - -#[cfg(test)] -mod tests { - use std::io::prelude::*; - use std::net::{SocketAddr, TcpListener, TcpStream, UdpSocket}; - use std::thread; - - use socket2::{Domain, Socket, Type}; - - use crate::iocp::CompletionPort; - use crate::net::{AcceptAddrsBuf, TcpListenerExt}; - use crate::net::{SocketAddrBuf, TcpStreamExt, UdpSocketExt}; - use crate::Overlapped; - - fn each_ip(f: &mut dyn FnMut(SocketAddr)) { - f(t!("127.0.0.1:0".parse())); - f(t!("[::1]:0".parse())); - } - - #[test] - fn tcp_read() { - each_ip(&mut |addr| { - let l = t!(TcpListener::bind(addr)); - let addr = t!(l.local_addr()); - let t = thread::spawn(move || { - let mut a = t!(l.accept()).0; - t!(a.write_all(&[1, 2, 3])); - }); - - let cp = t!(CompletionPort::new(1)); - let s = t!(TcpStream::connect(addr)); - t!(cp.add_socket(1, &s)); - - let mut b = [0; 10]; - let a = Overlapped::zero(); - unsafe { - t!(s.read_overlapped(&mut b, a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - assert_eq!(&b[0..3], &[1, 2, 3]); - - t!(t.join()); - }) - } - - #[test] - fn tcp_write() { - each_ip(&mut |addr| { - let l = t!(TcpListener::bind(addr)); - let addr = t!(l.local_addr()); - let t = thread::spawn(move || { - let mut a = t!(l.accept()).0; - let mut b = [0; 10]; - let n = t!(a.read(&mut b)); - assert_eq!(n, 3); - assert_eq!(&b[0..3], &[1, 2, 3]); - }); - - let cp = t!(CompletionPort::new(1)); - let s = t!(TcpStream::connect(addr)); - t!(cp.add_socket(1, &s)); - - let b = [1, 2, 3]; - let a = Overlapped::zero(); - unsafe { - t!(s.write_overlapped(&b, a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - - t!(t.join()); - }) - } - - #[test] - fn tcp_connect() { - each_ip(&mut |addr_template| { - let l = t!(TcpListener::bind(addr_template)); - let addr = t!(l.local_addr()); - let t = thread::spawn(move || { - t!(l.accept()); - }); - - let cp = t!(CompletionPort::new(1)); - let domain = match addr { - SocketAddr::V4(..) => Domain::ipv4(), - SocketAddr::V6(..) => Domain::ipv6(), - }; - let socket = t!(Socket::new(domain, Type::stream(), None)); - t!(socket.bind(&addr_template.into())); - let socket = socket.into_tcp_stream(); - t!(cp.add_socket(1, &socket)); - - let a = Overlapped::zero(); - unsafe { - t!(socket.connect_overlapped(&addr, &[], a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 0); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - t!(socket.connect_complete()); - - t!(t.join()); - }) - } - - #[test] - fn udp_recv_from() { - each_ip(&mut |addr| { - let a = t!(UdpSocket::bind(addr)); - let b = t!(UdpSocket::bind(addr)); - let a_addr = t!(a.local_addr()); - let b_addr = t!(b.local_addr()); - let t = thread::spawn(move || { - t!(a.send_to(&[1, 2, 3], b_addr)); - }); - - let cp = t!(CompletionPort::new(1)); - t!(cp.add_socket(1, &b)); - - let mut buf = [0; 10]; - let a = Overlapped::zero(); - let mut addr = SocketAddrBuf::new(); - unsafe { - t!(b.recv_from_overlapped(&mut buf, &mut addr, a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - assert_eq!(&buf[..3], &[1, 2, 3]); - assert_eq!(addr.to_socket_addr(), Some(a_addr)); - - t!(t.join()); - }) - } - - #[test] - fn udp_recv() { - each_ip(&mut |addr| { - let a = t!(UdpSocket::bind(addr)); - let b = t!(UdpSocket::bind(addr)); - let a_addr = t!(a.local_addr()); - let b_addr = t!(b.local_addr()); - assert!(b.connect(a_addr).is_ok()); - assert!(a.connect(b_addr).is_ok()); - let t = thread::spawn(move || { - t!(a.send_to(&[1, 2, 3], b_addr)); - }); - - let cp = t!(CompletionPort::new(1)); - t!(cp.add_socket(1, &b)); - - let mut buf = [0; 10]; - let a = Overlapped::zero(); - unsafe { - t!(b.recv_overlapped(&mut buf, a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - assert_eq!(&buf[..3], &[1, 2, 3]); - - t!(t.join()); - }) - } - - #[test] - fn udp_send_to() { - each_ip(&mut |addr| { - let a = t!(UdpSocket::bind(addr)); - let b = t!(UdpSocket::bind(addr)); - let a_addr = t!(a.local_addr()); - let b_addr = t!(b.local_addr()); - let t = thread::spawn(move || { - let mut b = [0; 100]; - let (n, addr) = t!(a.recv_from(&mut b)); - assert_eq!(n, 3); - assert_eq!(addr, b_addr); - assert_eq!(&b[..3], &[1, 2, 3]); - }); - - let cp = t!(CompletionPort::new(1)); - t!(cp.add_socket(1, &b)); - - let a = Overlapped::zero(); - unsafe { - t!(b.send_to_overlapped(&[1, 2, 3], &a_addr, a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - - t!(t.join()); - }) - } - - #[test] - fn udp_send() { - each_ip(&mut |addr| { - let a = t!(UdpSocket::bind(addr)); - let b = t!(UdpSocket::bind(addr)); - let a_addr = t!(a.local_addr()); - let b_addr = t!(b.local_addr()); - assert!(b.connect(a_addr).is_ok()); - assert!(a.connect(b_addr).is_ok()); - let t = thread::spawn(move || { - let mut b = [0; 100]; - let (n, addr) = t!(a.recv_from(&mut b)); - assert_eq!(n, 3); - assert_eq!(addr, b_addr); - assert_eq!(&b[..3], &[1, 2, 3]); - }); - - let cp = t!(CompletionPort::new(1)); - t!(cp.add_socket(1, &b)); - - let a = Overlapped::zero(); - unsafe { - t!(b.send_overlapped(&[1, 2, 3], a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - - t!(t.join()); - }) - } - - #[test] - fn tcp_accept() { - each_ip(&mut |addr_template| { - let l = t!(TcpListener::bind(addr_template)); - let addr = t!(l.local_addr()); - let t = thread::spawn(move || { - let socket = t!(TcpStream::connect(addr)); - (socket.local_addr().unwrap(), socket.peer_addr().unwrap()) - }); - - let cp = t!(CompletionPort::new(1)); - let domain = match addr { - SocketAddr::V4(..) => Domain::ipv4(), - SocketAddr::V6(..) => Domain::ipv6(), - }; - let socket = t!(Socket::new(domain, Type::stream(), None)).into_tcp_stream(); - t!(cp.add_socket(1, &l)); - - let a = Overlapped::zero(); - let mut addrs = AcceptAddrsBuf::new(); - unsafe { - t!(l.accept_overlapped(&socket, &mut addrs, a.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 0); - assert_eq!(status.token(), 1); - assert_eq!(status.overlapped(), a.raw()); - t!(l.accept_complete(&socket)); - - let (remote, local) = t!(t.join()); - let addrs = addrs.parse(&l).unwrap(); - assert_eq!(addrs.local(), Some(local)); - assert_eq!(addrs.remote(), Some(remote)); - }) - } -} +//! Extensions and types for the standard networking primitives. +//! +//! This module contains a number of extension traits for the types in +//! `std::net` for Windows-specific functionality. + +use std::cmp; +use std::io; +use std::mem; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; +use std::net::{SocketAddr, TcpListener, TcpStream, UdpSocket}; +use std::os::windows::prelude::*; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use winapi::ctypes::*; +use winapi::shared::guiddef::*; +use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR}; +use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR}; +use winapi::shared::minwindef::*; +use winapi::shared::minwindef::{FALSE, TRUE}; +use winapi::shared::ntdef::*; +use winapi::shared::ws2def::SOL_SOCKET; +use winapi::shared::ws2def::*; +use winapi::shared::ws2ipdef::*; +use winapi::um::minwinbase::*; +use winapi::um::winsock2::*; + +/// A type to represent a buffer in which a socket address will be stored. +/// +/// This type is used with the `recv_from_overlapped` function on the +/// `UdpSocketExt` trait to provide space for the overlapped I/O operation to +/// fill in the address upon completion. +#[derive(Clone, Copy)] +pub struct SocketAddrBuf { + buf: SOCKADDR_STORAGE, + len: c_int, +} + +/// A type to represent a buffer in which an accepted socket's address will be +/// stored. +/// +/// This type is used with the `accept_overlapped` method on the +/// `TcpListenerExt` trait to provide space for the overlapped I/O operation to +/// fill in the socket addresses upon completion. +#[repr(C)] +pub struct AcceptAddrsBuf { + // For AcceptEx we've got the restriction that the addresses passed in that + // buffer need to be at least 16 bytes more than the maximum address length + // for the protocol in question, so add some extra here and there + local: SOCKADDR_STORAGE, + _pad1: [u8; 16], + remote: SOCKADDR_STORAGE, + _pad2: [u8; 16], +} + +/// The parsed return value of `AcceptAddrsBuf`. +pub struct AcceptAddrs<'a> { + local: LPSOCKADDR, + local_len: c_int, + remote: LPSOCKADDR, + remote_len: c_int, + _data: &'a AcceptAddrsBuf, +} + +struct WsaExtension { + guid: GUID, + val: AtomicUsize, +} + +/// Additional methods for the `TcpStream` type in the standard library. +pub trait TcpStreamExt { + /// Execute an overlapped read I/O operation on this TCP stream. + /// + /// This function will issue an overlapped I/O read (via `WSARecv`) on this + /// socket. The provided buffer will be filled in when the operation + /// completes and the given `OVERLAPPED` instance is used to track the + /// overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned indicating how + /// many bytes were read. If the operation returns an error indicating that + /// the I/O is currently pending, `Ok(None)` is returned. Otherwise, the + /// error associated with the operation is returned and no overlapped + /// operation is enqueued. + /// + /// The number of bytes read will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn read_overlapped( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result>; + + /// Execute an overlapped write I/O operation on this TCP stream. + /// + /// This function will issue an overlapped I/O write (via `WSASend`) on this + /// socket. The provided buffer will be written when the operation completes + /// and the given `OVERLAPPED` instance is used to track the overlapped + /// operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the + /// number of bytes that were written. If the operation returns an error + /// indicating that the I/O is currently pending, `Ok(None)` is returned. + /// Otherwise, the error associated with the operation is returned and no + /// overlapped operation is enqueued. + /// + /// The number of bytes written will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn write_overlapped( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result>; + + /// Attempt to consume the internal socket in this builder by executing an + /// overlapped connect operation. + /// + /// This function will issue a connect operation to the address specified on + /// the underlying socket, flagging it as an overlapped operation which will + /// complete asynchronously. If successful this function will return the + /// corresponding TCP stream. + /// + /// The `buf` argument provided is an initial buffer of data that should be + /// sent after the connection is initiated. It's acceptable to + /// pass an empty slice here. + /// + /// This function will also return whether the connect immediately + /// succeeded or not. If `None` is returned then the I/O operation is still + /// pending and will complete at a later date, and if `Some(bytes)` is + /// returned then that many bytes were transferred. + /// + /// Note that to succeed this requires that the underlying socket has + /// previously been bound via a call to `bind` to a local address. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the + /// `overlapped` and `buf` pointers to be valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for + /// this I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that this pointer is + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + unsafe fn connect_overlapped( + &self, + addr: &SocketAddr, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result>; + + /// Once a `connect_overlapped` has finished, this function needs to be + /// called to finish the connect operation. + /// + /// Currently this just calls `setsockopt` with `SO_UPDATE_CONNECT_CONTEXT` + /// to ensure that further functions like `getpeername` and `getsockname` + /// work correctly. + fn connect_complete(&self) -> io::Result<()>; + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred, along with the results of the `lpFlags` parameter of + /// the relevant operation, if applicable. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `OVERLAPPED` instance. + /// + /// # Panics + /// + /// This function will panic + unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)>; +} + +/// Additional methods for the `UdpSocket` type in the standard library. +pub trait UdpSocketExt { + /// Execute an overlapped receive I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O read (via `WSARecvFrom`) on + /// this socket. The provided buffer will be filled in when the operation + /// completes, the source from where the data came from will be written to + /// `addr`, and the given `OVERLAPPED` instance is used to track the + /// overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the + /// number of bytes that were read. If the operation returns an error + /// indicating that the I/O is currently pending, `Ok(None)` is returned. + /// Otherwise, the error associated with the operation is returned and no + /// overlapped operation is enqueued. + /// + /// The number of bytes read will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf`, + /// `addr`, and `overlapped` pointers are valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for this + /// I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn recv_from_overlapped( + &self, + buf: &mut [u8], + addr: *mut SocketAddrBuf, + overlapped: *mut OVERLAPPED, + ) -> io::Result>; + + /// Execute an overlapped receive I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O read (via `WSARecv`) on + /// this socket. The provided buffer will be filled in when the operation + /// completes, the source from where the data came from will be written to + /// `addr`, and the given `OVERLAPPED` instance is used to track the + /// overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the + /// number of bytes that were read. If the operation returns an error + /// indicating that the I/O is currently pending, `Ok(None)` is returned. + /// Otherwise, the error associated with the operation is returned and no + /// overlapped operation is enqueued. + /// + /// The number of bytes read will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf`, + /// and `overlapped` pointers are valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for this + /// I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn recv_overlapped( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result>; + + /// Execute an overlapped send I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O write (via `WSASendTo`) on + /// this socket to the address specified by `addr`. The provided buffer will + /// be written when the operation completes and the given `OVERLAPPED` + /// instance is used to track the overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte + /// were written. If the operation returns an error indicating that the I/O + /// is currently pending, `Ok(None)` is returned. Otherwise, the error + /// associated with the operation is returned and no overlapped operation + /// is enqueued. + /// + /// The number of bytes written will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn send_to_overlapped( + &self, + buf: &[u8], + addr: &SocketAddr, + overlapped: *mut OVERLAPPED, + ) -> io::Result>; + + /// Execute an overlapped send I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O write (via `WSASend`) on + /// this socket to the address it was previously connected to. The provided + /// buffer will be written when the operation completes and the given `OVERLAPPED` + /// instance is used to track the overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte + /// were written. If the operation returns an error indicating that the I/O + /// is currently pending, `Ok(None)` is returned. Otherwise, the error + /// associated with the operation is returned and no overlapped operation + /// is enqueued. + /// + /// The number of bytes written will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn send_overlapped( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result>; + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred, along with the results of the `lpFlags` parameter of + /// the relevant operation, if applicable. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `OVERLAPPED` instance. + /// + /// # Panics + /// + /// This function will panic + unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)>; +} + +/// Additional methods for the `TcpListener` type in the standard library. +pub trait TcpListenerExt { + /// Perform an accept operation on this listener, accepting a connection in + /// an overlapped fashion. + /// + /// This function will issue an I/O request to accept an incoming connection + /// with the specified overlapped instance. The `socket` provided must be a + /// configured but not bound or connected socket, and if successful this + /// will consume the internal socket of the builder to return a TCP stream. + /// + /// The `addrs` buffer provided will be filled in with the local and remote + /// addresses of the connection upon completion. + /// + /// If the accept succeeds immediately, `Ok(true)` is returned. If + /// the connect indicates that the I/O is currently pending, `Ok(false)` is + /// returned. Otherwise, the error associated with the operation is + /// returned and no overlapped operation is enqueued. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the + /// `addrs` and `overlapped` pointers are valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for this + /// I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that the pointers are + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + unsafe fn accept_overlapped( + &self, + socket: &TcpStream, + addrs: &mut AcceptAddrsBuf, + overlapped: *mut OVERLAPPED, + ) -> io::Result; + + /// Once an `accept_overlapped` has finished, this function needs to be + /// called to finish the accept operation. + /// + /// Currently this just calls `setsockopt` with `SO_UPDATE_ACCEPT_CONTEXT` + /// to ensure that further functions like `getpeername` and `getsockname` + /// work correctly. + fn accept_complete(&self, socket: &TcpStream) -> io::Result<()>; + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred, along with the results of the `lpFlags` parameter of + /// the relevant operation, if applicable. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `OVERLAPPED` instance. + /// + /// # Panics + /// + /// This function will panic + unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)>; +} + +#[doc(hidden)] +trait NetInt { + fn from_be(i: Self) -> Self; + fn to_be(&self) -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl NetInt for $t { + fn from_be(i: Self) -> Self { <$t>::from_be(i) } + fn to_be(&self) -> Self { <$t>::to_be(*self) } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +// fn hton(i: I) -> I { i.to_be() } +fn ntoh(i: I) -> I { + I::from_be(i) +} + +fn last_err() -> io::Result> { + let err = unsafe { WSAGetLastError() }; + if err == WSA_IO_PENDING as i32 { + Ok(None) + } else { + Err(io::Error::from_raw_os_error(err)) + } +} + +fn cvt(i: c_int, size: DWORD) -> io::Result> { + if i == SOCKET_ERROR { + last_err() + } else { + Ok(Some(size as usize)) + } +} + +/// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level +/// SocketAddr* types into their system representation. The benefit of this specific +/// type over using `SOCKADDR_STORAGE` is that this type is exactly as large as it +/// needs to be and not a lot larger. And it can be initialized cleaner from Rust. +#[repr(C)] +pub(crate) union SocketAddrCRepr { + v4: SOCKADDR_IN, + v6: SOCKADDR_IN6_LH, +} + +impl SocketAddrCRepr { + pub(crate) fn as_ptr(&self) -> *const SOCKADDR { + self as *const _ as *const SOCKADDR + } +} + +fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { + match *addr { + SocketAddr::V4(ref a) => { + let sin_addr = unsafe { + let mut s_un = mem::zeroed::(); + *s_un.S_addr_mut() = u32::from_ne_bytes(a.ip().octets()); + IN_ADDR { S_un: s_un } + }; + + let sockaddr_in = SOCKADDR_IN { + sin_family: AF_INET as ADDRESS_FAMILY, + sin_port: a.port().to_be(), + sin_addr, + sin_zero: [0; 8], + }; + + let sockaddr = SocketAddrCRepr { v4: sockaddr_in }; + (sockaddr, mem::size_of::() as c_int) + } + SocketAddr::V6(ref a) => { + let sin6_addr = unsafe { + let mut u = mem::zeroed::(); + *u.Byte_mut() = a.ip().octets(); + IN6_ADDR { u } + }; + let u = unsafe { + let mut u = mem::zeroed::(); + *u.sin6_scope_id_mut() = a.scope_id(); + u + }; + + let sockaddr_in6 = SOCKADDR_IN6_LH { + sin6_family: AF_INET6 as ADDRESS_FAMILY, + sin6_port: a.port().to_be(), + sin6_addr, + sin6_flowinfo: a.flowinfo(), + u, + }; + + let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; + (sockaddr, mem::size_of::() as c_int) + } + } +} + +unsafe fn ptrs_to_socket_addr(ptr: *const SOCKADDR, len: c_int) -> Option { + if (len as usize) < mem::size_of::() { + return None; + } + match (*ptr).sa_family as i32 { + AF_INET if len as usize >= mem::size_of::() => { + let b = &*(ptr as *const SOCKADDR_IN); + let ip = ntoh(*b.sin_addr.S_un.S_addr()); + let ip = Ipv4Addr::new( + (ip >> 24) as u8, + (ip >> 16) as u8, + (ip >> 8) as u8, + (ip >> 0) as u8, + ); + Some(SocketAddr::V4(SocketAddrV4::new(ip, ntoh(b.sin_port)))) + } + AF_INET6 if len as usize >= mem::size_of::() => { + let b = &*(ptr as *const SOCKADDR_IN6_LH); + let arr = b.sin6_addr.u.Byte(); + let ip = Ipv6Addr::new( + ((arr[0] as u16) << 8) | (arr[1] as u16), + ((arr[2] as u16) << 8) | (arr[3] as u16), + ((arr[4] as u16) << 8) | (arr[5] as u16), + ((arr[6] as u16) << 8) | (arr[7] as u16), + ((arr[8] as u16) << 8) | (arr[9] as u16), + ((arr[10] as u16) << 8) | (arr[11] as u16), + ((arr[12] as u16) << 8) | (arr[13] as u16), + ((arr[14] as u16) << 8) | (arr[15] as u16), + ); + let addr = SocketAddrV6::new( + ip, + ntoh(b.sin6_port), + ntoh(b.sin6_flowinfo), + ntoh(*b.u.sin6_scope_id()), + ); + Some(SocketAddr::V6(addr)) + } + _ => None, + } +} + +unsafe fn slice2buf(slice: &[u8]) -> WSABUF { + WSABUF { + len: cmp::min(slice.len(), ::max_value() as usize) as u_long, + buf: slice.as_ptr() as *mut _, + } +} + +unsafe fn result(socket: SOCKET, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { + let mut transferred = 0; + let mut flags = 0; + let r = WSAGetOverlappedResult(socket, overlapped, &mut transferred, FALSE, &mut flags); + if r == 0 { + Err(io::Error::last_os_error()) + } else { + Ok((transferred as usize, flags)) + } +} + +impl TcpStreamExt for TcpStream { + unsafe fn read_overlapped( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + let mut buf = slice2buf(buf); + let mut flags = 0; + let mut bytes_read: DWORD = 0; + let r = WSARecv( + self.as_raw_socket() as SOCKET, + &mut buf, + 1, + &mut bytes_read, + &mut flags, + overlapped, + None, + ); + cvt(r, bytes_read) + } + + unsafe fn write_overlapped( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + let mut buf = slice2buf(buf); + let mut bytes_written = 0; + + // Note here that we capture the number of bytes written. The + // documentation on MSDN, however, states: + // + // > Use NULL for this parameter if the lpOverlapped parameter is not + // > NULL to avoid potentially erroneous results. This parameter can be + // > NULL only if the lpOverlapped parameter is not NULL. + // + // If we're not passing a null overlapped pointer here, then why are we + // then capturing the number of bytes! Well so it turns out that this is + // clearly faster to learn the bytes here rather than later calling + // `WSAGetOverlappedResult`, and in practice almost all implementations + // use this anyway [1]. + // + // As a result we use this to and report back the result. + // + // [1]: https://github.com/carllerche/mio/pull/520#issuecomment-273983823 + let r = WSASend( + self.as_raw_socket() as SOCKET, + &mut buf, + 1, + &mut bytes_written, + 0, + overlapped, + None, + ); + cvt(r, bytes_written) + } + + unsafe fn connect_overlapped( + &self, + addr: &SocketAddr, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + connect_overlapped(self.as_raw_socket() as SOCKET, addr, buf, overlapped) + } + + fn connect_complete(&self) -> io::Result<()> { + const SO_UPDATE_CONNECT_CONTEXT: c_int = 0x7010; + let result = unsafe { + setsockopt( + self.as_raw_socket() as SOCKET, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + 0 as *const _, + 0, + ) + }; + if result == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { + result(self.as_raw_socket() as SOCKET, overlapped) + } +} + +unsafe fn connect_overlapped( + socket: SOCKET, + addr: &SocketAddr, + buf: &[u8], + overlapped: *mut OVERLAPPED, +) -> io::Result> { + static CONNECTEX: WsaExtension = WsaExtension { + guid: GUID { + Data1: 0x25a207b9, + Data2: 0xddf3, + Data3: 0x4660, + Data4: [0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e], + }, + val: AtomicUsize::new(0), + }; + type ConnectEx = unsafe extern "system" fn( + SOCKET, + *const SOCKADDR, + c_int, + PVOID, + DWORD, + LPDWORD, + LPOVERLAPPED, + ) -> BOOL; + + let ptr = CONNECTEX.get(socket)?; + assert!(ptr != 0); + let connect_ex = mem::transmute::<_, ConnectEx>(ptr); + + let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); + let mut bytes_sent: DWORD = 0; + let r = connect_ex( + socket, + addr_buf.as_ptr(), + addr_len, + buf.as_ptr() as *mut _, + buf.len() as u32, + &mut bytes_sent, + overlapped, + ); + if r == TRUE { + Ok(Some(bytes_sent as usize)) + } else { + last_err() + } +} + +impl UdpSocketExt for UdpSocket { + unsafe fn recv_from_overlapped( + &self, + buf: &mut [u8], + addr: *mut SocketAddrBuf, + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + let mut buf = slice2buf(buf); + let mut flags = 0; + let mut received_bytes: DWORD = 0; + let r = WSARecvFrom( + self.as_raw_socket() as SOCKET, + &mut buf, + 1, + &mut received_bytes, + &mut flags, + &mut (*addr).buf as *mut _ as *mut _, + &mut (*addr).len, + overlapped, + None, + ); + cvt(r, received_bytes) + } + + unsafe fn recv_overlapped( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + let mut buf = slice2buf(buf); + let mut flags = 0; + let mut received_bytes: DWORD = 0; + let r = WSARecv( + self.as_raw_socket() as SOCKET, + &mut buf, + 1, + &mut received_bytes, + &mut flags, + overlapped, + None, + ); + cvt(r, received_bytes) + } + + unsafe fn send_to_overlapped( + &self, + buf: &[u8], + addr: &SocketAddr, + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); + let mut buf = slice2buf(buf); + let mut sent_bytes = 0; + let r = WSASendTo( + self.as_raw_socket() as SOCKET, + &mut buf, + 1, + &mut sent_bytes, + 0, + addr_buf.as_ptr() as *const _, + addr_len, + overlapped, + None, + ); + cvt(r, sent_bytes) + } + + unsafe fn send_overlapped( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + let mut buf = slice2buf(buf); + let mut sent_bytes = 0; + let r = WSASend( + self.as_raw_socket() as SOCKET, + &mut buf, + 1, + &mut sent_bytes, + 0, + overlapped, + None, + ); + cvt(r, sent_bytes) + } + + unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { + result(self.as_raw_socket() as SOCKET, overlapped) + } +} + +impl TcpListenerExt for TcpListener { + unsafe fn accept_overlapped( + &self, + socket: &TcpStream, + addrs: &mut AcceptAddrsBuf, + overlapped: *mut OVERLAPPED, + ) -> io::Result { + static ACCEPTEX: WsaExtension = WsaExtension { + guid: GUID { + Data1: 0xb5367df1, + Data2: 0xcbac, + Data3: 0x11cf, + Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92], + }, + val: AtomicUsize::new(0), + }; + type AcceptEx = unsafe extern "system" fn( + SOCKET, + SOCKET, + PVOID, + DWORD, + DWORD, + DWORD, + LPDWORD, + LPOVERLAPPED, + ) -> BOOL; + + let ptr = ACCEPTEX.get(self.as_raw_socket() as SOCKET)?; + assert!(ptr != 0); + let accept_ex = mem::transmute::<_, AcceptEx>(ptr); + + let mut bytes = 0; + let (a, b, c, d) = (*addrs).args(); + let r = accept_ex( + self.as_raw_socket() as SOCKET, + socket.as_raw_socket() as SOCKET, + a, + b, + c, + d, + &mut bytes, + overlapped, + ); + let succeeded = if r == TRUE { + true + } else { + last_err()?; + false + }; + Ok(succeeded) + } + + fn accept_complete(&self, socket: &TcpStream) -> io::Result<()> { + const SO_UPDATE_ACCEPT_CONTEXT: c_int = 0x700B; + let me = self.as_raw_socket(); + let result = unsafe { + setsockopt( + socket.as_raw_socket() as SOCKET, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + &me as *const _ as *const _, + mem::size_of_val(&me) as c_int, + ) + }; + if result == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<(usize, u32)> { + result(self.as_raw_socket() as SOCKET, overlapped) + } +} + +impl SocketAddrBuf { + /// Creates a new blank socket address buffer. + /// + /// This should be used before a call to `recv_from_overlapped` overlapped + /// to create an instance to pass down. + pub fn new() -> SocketAddrBuf { + SocketAddrBuf { + buf: unsafe { mem::zeroed() }, + len: mem::size_of::() as c_int, + } + } + + /// Parses this buffer to return a standard socket address. + /// + /// This function should be called after the buffer has been filled in with + /// a call to `recv_from_overlapped` being completed. It will interpret the + /// address filled in and return the standard socket address type. + /// + /// If an error is encountered then `None` is returned. + pub fn to_socket_addr(&self) -> Option { + unsafe { ptrs_to_socket_addr(&self.buf as *const _ as *const _, self.len) } + } +} + +static GETACCEPTEXSOCKADDRS: WsaExtension = WsaExtension { + guid: GUID { + Data1: 0xb5367df2, + Data2: 0xcbac, + Data3: 0x11cf, + Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92], + }, + val: AtomicUsize::new(0), +}; +type GetAcceptExSockaddrs = unsafe extern "system" fn( + PVOID, + DWORD, + DWORD, + DWORD, + *mut LPSOCKADDR, + LPINT, + *mut LPSOCKADDR, + LPINT, +); + +impl AcceptAddrsBuf { + /// Creates a new blank buffer ready to be passed to a call to + /// `accept_overlapped`. + pub fn new() -> AcceptAddrsBuf { + unsafe { mem::zeroed() } + } + + /// Parses the data contained in this address buffer, returning the parsed + /// result if successful. + /// + /// This function can be called after a call to `accept_overlapped` has + /// succeeded to parse out the data that was written in. + pub fn parse(&self, socket: &TcpListener) -> io::Result { + let mut ret = AcceptAddrs { + local: 0 as *mut _, + local_len: 0, + remote: 0 as *mut _, + remote_len: 0, + _data: self, + }; + let ptr = GETACCEPTEXSOCKADDRS.get(socket.as_raw_socket() as SOCKET)?; + assert!(ptr != 0); + unsafe { + let get_sockaddrs = mem::transmute::<_, GetAcceptExSockaddrs>(ptr); + let (a, b, c, d) = self.args(); + get_sockaddrs( + a, + b, + c, + d, + &mut ret.local, + &mut ret.local_len, + &mut ret.remote, + &mut ret.remote_len, + ); + Ok(ret) + } + } + + fn args(&self) -> (PVOID, DWORD, DWORD, DWORD) { + let remote_offset = unsafe { &(*(0 as *const AcceptAddrsBuf)).remote as *const _ as usize }; + ( + self as *const _ as *mut _, + 0, + remote_offset as DWORD, + (mem::size_of_val(self) - remote_offset) as DWORD, + ) + } +} + +impl<'a> AcceptAddrs<'a> { + /// Returns the local socket address contained in this buffer. + pub fn local(&self) -> Option { + unsafe { ptrs_to_socket_addr(self.local, self.local_len) } + } + + /// Returns the remote socket address contained in this buffer. + pub fn remote(&self) -> Option { + unsafe { ptrs_to_socket_addr(self.remote, self.remote_len) } + } +} + +impl WsaExtension { + fn get(&self, socket: SOCKET) -> io::Result { + let prev = self.val.load(Ordering::SeqCst); + if prev != 0 && !cfg!(debug_assertions) { + return Ok(prev); + } + let mut ret = 0 as usize; + let mut bytes = 0; + let r = unsafe { + WSAIoctl( + socket, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &self.guid as *const _ as *mut _, + mem::size_of_val(&self.guid) as DWORD, + &mut ret as *mut _ as *mut _, + mem::size_of_val(&ret) as DWORD, + &mut bytes, + 0 as *mut _, + None, + ) + }; + cvt(r, 0).map(|_| { + debug_assert_eq!(bytes as usize, mem::size_of_val(&ret)); + debug_assert!(prev == 0 || prev == ret); + self.val.store(ret, Ordering::SeqCst); + ret + }) + } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use std::net::{ + IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV6, TcpListener, TcpStream, UdpSocket, + }; + use std::slice; + use std::thread; + + use socket2::{Domain, Socket, Type}; + + use crate::iocp::CompletionPort; + use crate::net::{AcceptAddrsBuf, TcpListenerExt}; + use crate::net::{SocketAddrBuf, TcpStreamExt, UdpSocketExt}; + use crate::Overlapped; + + fn each_ip(f: &mut dyn FnMut(SocketAddr)) { + f(t!("127.0.0.1:0".parse())); + f(t!("[::1]:0".parse())); + } + + #[test] + fn tcp_read() { + each_ip(&mut |addr| { + let l = t!(TcpListener::bind(addr)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + let mut a = t!(l.accept()).0; + t!(a.write_all(&[1, 2, 3])); + }); + + let cp = t!(CompletionPort::new(1)); + let s = t!(TcpStream::connect(addr)); + t!(cp.add_socket(1, &s)); + + let mut b = [0; 10]; + let a = Overlapped::zero(); + unsafe { + t!(s.read_overlapped(&mut b, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + assert_eq!(&b[0..3], &[1, 2, 3]); + + t!(t.join()); + }) + } + + #[test] + fn tcp_write() { + each_ip(&mut |addr| { + let l = t!(TcpListener::bind(addr)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + let mut a = t!(l.accept()).0; + let mut b = [0; 10]; + let n = t!(a.read(&mut b)); + assert_eq!(n, 3); + assert_eq!(&b[0..3], &[1, 2, 3]); + }); + + let cp = t!(CompletionPort::new(1)); + let s = t!(TcpStream::connect(addr)); + t!(cp.add_socket(1, &s)); + + let b = [1, 2, 3]; + let a = Overlapped::zero(); + unsafe { + t!(s.write_overlapped(&b, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + + t!(t.join()); + }) + } + + #[test] + fn tcp_connect() { + each_ip(&mut |addr_template| { + let l = t!(TcpListener::bind(addr_template)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + t!(l.accept()); + }); + + let cp = t!(CompletionPort::new(1)); + let domain = match addr { + SocketAddr::V4(..) => Domain::ipv4(), + SocketAddr::V6(..) => Domain::ipv6(), + }; + let socket = t!(Socket::new(domain, Type::stream(), None)); + t!(socket.bind(&addr_template.into())); + let socket = socket.into_tcp_stream(); + t!(cp.add_socket(1, &socket)); + + let a = Overlapped::zero(); + unsafe { + t!(socket.connect_overlapped(&addr, &[], a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 0); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + t!(socket.connect_complete()); + + t!(t.join()); + }) + } + + #[test] + fn udp_recv_from() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + let t = thread::spawn(move || { + t!(a.send_to(&[1, 2, 3], b_addr)); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let mut buf = [0; 10]; + let a = Overlapped::zero(); + let mut addr = SocketAddrBuf::new(); + unsafe { + t!(b.recv_from_overlapped(&mut buf, &mut addr, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + assert_eq!(&buf[..3], &[1, 2, 3]); + assert_eq!(addr.to_socket_addr(), Some(a_addr)); + + t!(t.join()); + }) + } + + #[test] + fn udp_recv() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + assert!(b.connect(a_addr).is_ok()); + assert!(a.connect(b_addr).is_ok()); + let t = thread::spawn(move || { + t!(a.send_to(&[1, 2, 3], b_addr)); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let mut buf = [0; 10]; + let a = Overlapped::zero(); + unsafe { + t!(b.recv_overlapped(&mut buf, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + assert_eq!(&buf[..3], &[1, 2, 3]); + + t!(t.join()); + }) + } + + #[test] + fn udp_send_to() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + let t = thread::spawn(move || { + let mut b = [0; 100]; + let (n, addr) = t!(a.recv_from(&mut b)); + assert_eq!(n, 3); + assert_eq!(addr, b_addr); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let a = Overlapped::zero(); + unsafe { + t!(b.send_to_overlapped(&[1, 2, 3], &a_addr, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + + t!(t.join()); + }) + } + + #[test] + fn udp_send() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + assert!(b.connect(a_addr).is_ok()); + assert!(a.connect(b_addr).is_ok()); + let t = thread::spawn(move || { + let mut b = [0; 100]; + let (n, addr) = t!(a.recv_from(&mut b)); + assert_eq!(n, 3); + assert_eq!(addr, b_addr); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let a = Overlapped::zero(); + unsafe { + t!(b.send_overlapped(&[1, 2, 3], a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + + t!(t.join()); + }) + } + + #[test] + fn tcp_accept() { + each_ip(&mut |addr_template| { + let l = t!(TcpListener::bind(addr_template)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + let socket = t!(TcpStream::connect(addr)); + (socket.local_addr().unwrap(), socket.peer_addr().unwrap()) + }); + + let cp = t!(CompletionPort::new(1)); + let domain = match addr { + SocketAddr::V4(..) => Domain::ipv4(), + SocketAddr::V6(..) => Domain::ipv6(), + }; + let socket = t!(Socket::new(domain, Type::stream(), None)).into_tcp_stream(); + t!(cp.add_socket(1, &l)); + + let a = Overlapped::zero(); + let mut addrs = AcceptAddrsBuf::new(); + unsafe { + t!(l.accept_overlapped(&socket, &mut addrs, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 0); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + t!(l.accept_complete(&socket)); + + let (remote, local) = t!(t.join()); + let addrs = addrs.parse(&l).unwrap(); + assert_eq!(addrs.local(), Some(local)); + assert_eq!(addrs.remote(), Some(remote)); + }) + } + + #[test] + fn sockaddr_convert_4() { + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(3, 4, 5, 6)), 0xabcd); + let (raw_addr, addr_len) = super::socket_addr_to_ptrs(&addr); + assert_eq!(addr_len, 16); + let addr_bytes = + unsafe { slice::from_raw_parts(raw_addr.as_ptr() as *const u8, addr_len as usize) }; + assert_eq!( + addr_bytes, + &[2, 0, 0xab, 0xcd, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0] + ); + } + + #[test] + fn sockaddr_convert_v6() { + let port = 0xabcd; + let flowinfo = 0x12345678; + let scope_id = 0x87654321; + let addr = SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::new( + 0x0102, 0x0304, 0x0506, 0x0708, 0x090a, 0x0b0c, 0x0d0e, 0x0f10, + ), + port, + flowinfo, + scope_id, + )); + let (raw_addr, addr_len) = super::socket_addr_to_ptrs(&addr); + assert_eq!(addr_len, 28); + let addr_bytes = + unsafe { slice::from_raw_parts(raw_addr.as_ptr() as *const u8, addr_len as usize) }; + assert_eq!( + addr_bytes, + &[ + 23, 0, // AF_INET6 + 0xab, 0xcd, // Port + 0x78, 0x56, 0x34, 0x12, // flowinfo + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, // IP + 0x21, 0x43, 0x65, 0x87, // scope_id + ] + ); + } +} diff --git a/vendor/miow/src/overlapped.rs b/vendor/miow/src/overlapped.rs index 69bc7163b3..abe2d37cbb 100644 --- a/vendor/miow/src/overlapped.rs +++ b/vendor/miow/src/overlapped.rs @@ -1,92 +1,92 @@ -use std::fmt; -use std::io; -use std::mem; -use std::ptr; - -use winapi::shared::ntdef::{HANDLE, NULL}; -use winapi::um::minwinbase::*; -use winapi::um::synchapi::*; - -/// A wrapper around `OVERLAPPED` to provide "rustic" accessors and -/// initializers. -pub struct Overlapped(OVERLAPPED); - -impl fmt::Debug for Overlapped { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "OVERLAPPED") - } -} - -unsafe impl Send for Overlapped {} -unsafe impl Sync for Overlapped {} - -impl Overlapped { - /// Creates a new zeroed out instance of an overlapped I/O tracking state. - /// - /// This is suitable for passing to methods which will then later get - /// notified via an I/O Completion Port. - pub fn zero() -> Overlapped { - Overlapped(unsafe { mem::zeroed() }) - } - - /// Creates a new `Overlapped` with an initialized non-null `hEvent`. The caller is - /// responsible for calling `CloseHandle` on the `hEvent` field of the returned - /// `Overlapped`. The event is created with `bManualReset` set to `FALSE`, meaning after a - /// single thread waits on the event, it will be reset. - pub fn initialize_with_autoreset_event() -> io::Result { - let event = unsafe { CreateEventW(ptr::null_mut(), 0i32, 0i32, ptr::null()) }; - if event == NULL { - return Err(io::Error::last_os_error()); - } - let mut overlapped = Self::zero(); - overlapped.set_event(event); - Ok(overlapped) - } - - /// Creates a new `Overlapped` function pointer from the underlying - /// `OVERLAPPED`, wrapping in the "rusty" wrapper for working with - /// accessors. - /// - /// # Unsafety - /// - /// This function doesn't validate `ptr` nor the lifetime of the returned - /// pointer at all, it's recommended to use this method with extreme - /// caution. - pub unsafe fn from_raw<'a>(ptr: *mut OVERLAPPED) -> &'a mut Overlapped { - &mut *(ptr as *mut Overlapped) - } - - /// Gain access to the raw underlying data - pub fn raw(&self) -> *mut OVERLAPPED { - &self.0 as *const _ as *mut _ - } - - /// Sets the offset inside this overlapped structure. - /// - /// Note that for I/O operations in general this only has meaning for I/O - /// handles that are on a seeking device that supports the concept of an - /// offset. - pub fn set_offset(&mut self, offset: u64) { - let s = unsafe { self.0.u.s_mut() }; - s.Offset = offset as u32; - s.OffsetHigh = (offset >> 32) as u32; - } - - /// Reads the offset inside this overlapped structure. - pub fn offset(&self) -> u64 { - let s = unsafe { self.0.u.s() }; - (s.Offset as u64) | ((s.OffsetHigh as u64) << 32) - } - - /// Sets the `hEvent` field of this structure. - /// - /// The event specified can be null. - pub fn set_event(&mut self, event: HANDLE) { - self.0.hEvent = event; - } - - /// Reads the `hEvent` field of this structure, may return null. - pub fn event(&self) -> HANDLE { - self.0.hEvent - } -} +use std::fmt; +use std::io; +use std::mem; +use std::ptr; + +use winapi::shared::ntdef::{HANDLE, NULL}; +use winapi::um::minwinbase::*; +use winapi::um::synchapi::*; + +/// A wrapper around `OVERLAPPED` to provide "rustic" accessors and +/// initializers. +pub struct Overlapped(OVERLAPPED); + +impl fmt::Debug for Overlapped { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OVERLAPPED") + } +} + +unsafe impl Send for Overlapped {} +unsafe impl Sync for Overlapped {} + +impl Overlapped { + /// Creates a new zeroed out instance of an overlapped I/O tracking state. + /// + /// This is suitable for passing to methods which will then later get + /// notified via an I/O Completion Port. + pub fn zero() -> Overlapped { + Overlapped(unsafe { mem::zeroed() }) + } + + /// Creates a new `Overlapped` with an initialized non-null `hEvent`. The caller is + /// responsible for calling `CloseHandle` on the `hEvent` field of the returned + /// `Overlapped`. The event is created with `bManualReset` set to `FALSE`, meaning after a + /// single thread waits on the event, it will be reset. + pub fn initialize_with_autoreset_event() -> io::Result { + let event = unsafe { CreateEventW(ptr::null_mut(), 0i32, 0i32, ptr::null()) }; + if event == NULL { + return Err(io::Error::last_os_error()); + } + let mut overlapped = Self::zero(); + overlapped.set_event(event); + Ok(overlapped) + } + + /// Creates a new `Overlapped` function pointer from the underlying + /// `OVERLAPPED`, wrapping in the "rusty" wrapper for working with + /// accessors. + /// + /// # Unsafety + /// + /// This function doesn't validate `ptr` nor the lifetime of the returned + /// pointer at all, it's recommended to use this method with extreme + /// caution. + pub unsafe fn from_raw<'a>(ptr: *mut OVERLAPPED) -> &'a mut Overlapped { + &mut *(ptr as *mut Overlapped) + } + + /// Gain access to the raw underlying data + pub fn raw(&self) -> *mut OVERLAPPED { + &self.0 as *const _ as *mut _ + } + + /// Sets the offset inside this overlapped structure. + /// + /// Note that for I/O operations in general this only has meaning for I/O + /// handles that are on a seeking device that supports the concept of an + /// offset. + pub fn set_offset(&mut self, offset: u64) { + let s = unsafe { self.0.u.s_mut() }; + s.Offset = offset as u32; + s.OffsetHigh = (offset >> 32) as u32; + } + + /// Reads the offset inside this overlapped structure. + pub fn offset(&self) -> u64 { + let s = unsafe { self.0.u.s() }; + (s.Offset as u64) | ((s.OffsetHigh as u64) << 32) + } + + /// Sets the `hEvent` field of this structure. + /// + /// The event specified can be null. + pub fn set_event(&mut self, event: HANDLE) { + self.0.hEvent = event; + } + + /// Reads the `hEvent` field of this structure, may return null. + pub fn event(&self) -> HANDLE { + self.0.hEvent + } +} diff --git a/vendor/miow/src/pipe.rs b/vendor/miow/src/pipe.rs index af0f601b16..6192dd250e 100644 --- a/vendor/miow/src/pipe.rs +++ b/vendor/miow/src/pipe.rs @@ -1,784 +1,784 @@ -//! Interprocess Communication pipes -//! -//! A pipe is a section of shared memory that processes use for communication. -//! The process that creates a pipe is the _pipe server_. A process that connects -//! to a pipe is a _pipe client_. One process writes information to the pipe, then -//! the other process reads the information from the pipe. This overview -//! describes how to create, manage, and use pipes. -//! -//! There are two types of pipes: [anonymous pipes](#fn.anonymous.html) and -//! [named pipes](#fn.named.html). Anonymous pipes require less overhead than -//! named pipes, but offer limited services. -//! -//! # Anonymous pipes -//! -//! An anonymous pipe is an unnamed, one-way pipe that typically transfers data -//! between a parent process and a child process. Anonymous pipes are always -//! local; they cannot be used for communication over a network. -//! -//! # Named pipes -//! -//! A *named pipe* is a named, one-way or duplex pipe for communication between -//! the pipe server and one or more pipe clients. All instances of a named pipe -//! share the same pipe name, but each instance has its own buffers and handles, -//! and provides a separate conduit for client/server communication. The use of -//! instances enables multiple pipe clients to use the same named pipe -//! simultaneously. -//! -//! Any process can access named pipes, subject to security checks, making named -//! pipes an easy form of communication between related or unrelated processes. -//! -//! Any process can act as both a server and a client, making peer-to-peer -//! communication possible. As used here, the term pipe server refers to a -//! process that creates a named pipe, and the term pipe client refers to a -//! process that connects to an instance of a named pipe. -//! -//! Named pipes can be used to provide communication between processes on the -//! same computer or between processes on different computers across a network. -//! If the server service is running, all named pipes are accessible remotely. If -//! you intend to use a named pipe locally only, deny access to NT -//! AUTHORITY\\NETWORK or switch to local RPC. -//! -//! # References -//! -//! - [win32 pipe docs](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/ipc/pipes.md) - -use std::cell::RefCell; -use std::ffi::OsStr; -use std::fs::{File, OpenOptions}; -use std::io; -use std::io::prelude::*; -use std::os::windows::ffi::*; -use std::os::windows::io::*; -use std::time::Duration; - -use crate::handle::Handle; -use crate::overlapped::Overlapped; -use winapi::shared::minwindef::*; -use winapi::shared::ntdef::HANDLE; -use winapi::shared::winerror::*; -use winapi::um::fileapi::*; -use winapi::um::handleapi::*; -use winapi::um::ioapiset::*; -use winapi::um::minwinbase::*; -use winapi::um::namedpipeapi::*; -use winapi::um::winbase::*; - -/// Readable half of an anonymous pipe. -#[derive(Debug)] -pub struct AnonRead(Handle); - -/// Writable half of an anonymous pipe. -#[derive(Debug)] -pub struct AnonWrite(Handle); - -/// A named pipe that can accept connections. -#[derive(Debug)] -pub struct NamedPipe(Handle); - -/// A builder structure for creating a new named pipe. -#[derive(Debug)] -pub struct NamedPipeBuilder { - name: Vec, - dwOpenMode: DWORD, - dwPipeMode: DWORD, - nMaxInstances: DWORD, - nOutBufferSize: DWORD, - nInBufferSize: DWORD, - nDefaultTimeOut: DWORD, -} - -/// Creates a new anonymous in-memory pipe, returning the read/write ends of the -/// pipe. -/// -/// The buffer size for this pipe may also be specified, but the system will -/// normally use this as a suggestion and it's not guaranteed that the buffer -/// will be precisely this size. -pub fn anonymous(buffer_size: u32) -> io::Result<(AnonRead, AnonWrite)> { - let mut read = 0 as HANDLE; - let mut write = 0 as HANDLE; - crate::cvt(unsafe { CreatePipe(&mut read, &mut write, 0 as *mut _, buffer_size) })?; - Ok((AnonRead(Handle::new(read)), AnonWrite(Handle::new(write)))) -} - -impl Read for AnonRead { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } -} -impl<'a> Read for &'a AnonRead { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } -} - -impl AsRawHandle for AnonRead { - fn as_raw_handle(&self) -> HANDLE { - self.0.raw() - } -} -impl FromRawHandle for AnonRead { - unsafe fn from_raw_handle(handle: HANDLE) -> AnonRead { - AnonRead(Handle::new(handle)) - } -} -impl IntoRawHandle for AnonRead { - fn into_raw_handle(self) -> HANDLE { - self.0.into_raw() - } -} - -impl Write for AnonWrite { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} -impl<'a> Write for &'a AnonWrite { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl AsRawHandle for AnonWrite { - fn as_raw_handle(&self) -> HANDLE { - self.0.raw() - } -} -impl FromRawHandle for AnonWrite { - unsafe fn from_raw_handle(handle: HANDLE) -> AnonWrite { - AnonWrite(Handle::new(handle)) - } -} -impl IntoRawHandle for AnonWrite { - fn into_raw_handle(self) -> HANDLE { - self.0.into_raw() - } -} - -/// A convenience function to connect to a named pipe. -/// -/// This function will block the calling process until it can connect to the -/// pipe server specified by `addr`. This will use `NamedPipe::wait` internally -/// to block until it can connect. -pub fn connect>(addr: A) -> io::Result { - _connect(addr.as_ref()) -} - -fn _connect(addr: &OsStr) -> io::Result { - let mut r = OpenOptions::new(); - let mut w = OpenOptions::new(); - let mut rw = OpenOptions::new(); - r.read(true); - w.write(true); - rw.read(true).write(true); - loop { - let res = rw - .open(addr) - .or_else(|_| r.open(addr)) - .or_else(|_| w.open(addr)); - match res { - Ok(f) => return Ok(f), - Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => {} - Err(e) => return Err(e), - } - - NamedPipe::wait(addr, Some(Duration::new(20, 0)))?; - } -} - -impl NamedPipe { - /// Creates a new initial named pipe. - /// - /// This function is equivalent to: - /// - /// ``` - /// use miow::pipe::NamedPipeBuilder; - /// - /// # let addr = "foo"; - /// NamedPipeBuilder::new(addr) - /// .first(true) - /// .inbound(true) - /// .outbound(true) - /// .out_buffer_size(65536) - /// .in_buffer_size(65536) - /// .create(); - /// ``` - pub fn new>(addr: A) -> io::Result { - NamedPipeBuilder::new(addr).create() - } - - /// Waits until either a time-out interval elapses or an instance of the - /// specified named pipe is available for connection. - /// - /// If this function succeeds the process can create a `File` to connect to - /// the named pipe. - pub fn wait>(addr: A, timeout: Option) -> io::Result<()> { - NamedPipe::_wait(addr.as_ref(), timeout) - } - - fn _wait(addr: &OsStr, timeout: Option) -> io::Result<()> { - let addr = addr.encode_wide().chain(Some(0)).collect::>(); - let timeout = crate::dur2ms(timeout); - crate::cvt(unsafe { WaitNamedPipeW(addr.as_ptr(), timeout) }).map(|_| ()) - } - - /// Connects this named pipe to a client, blocking until one becomes - /// available. - /// - /// This function will call the `ConnectNamedPipe` function to await for a - /// client to connect. This can be called immediately after the pipe is - /// created, or after it has been disconnected from a previous client. - pub fn connect(&self) -> io::Result<()> { - match crate::cvt(unsafe { ConnectNamedPipe(self.0.raw(), 0 as *mut _) }) { - Ok(_) => Ok(()), - Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) => Ok(()), - Err(e) => Err(e), - } - } - - /// Issue a connection request with the specified overlapped operation. - /// - /// This function will issue a request to connect a client to this server, - /// returning immediately after starting the overlapped operation. - /// - /// If this function immediately succeeds then `Ok(true)` is returned. If - /// the overlapped operation is enqueued and pending, then `Ok(false)` is - /// returned. Otherwise an error is returned indicating what went wrong. - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the - /// `overlapped` pointer is valid until the end of the I/O operation. The - /// kernel also requires that `overlapped` is unique for this I/O operation - /// and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that this pointer is - /// valid until the I/O operation is completed, typically via completion - /// ports and waiting to receive the completion notification on the port. - pub unsafe fn connect_overlapped(&self, overlapped: *mut OVERLAPPED) -> io::Result { - match crate::cvt(ConnectNamedPipe(self.0.raw(), overlapped)) { - Ok(_) => Ok(true), - Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) => Ok(true), - Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) => Ok(false), - Err(ref e) if e.raw_os_error() == Some(ERROR_NO_DATA as i32) => Ok(true), - Err(e) => Err(e), - } - } - - /// Disconnects this named pipe from any connected client. - pub fn disconnect(&self) -> io::Result<()> { - crate::cvt(unsafe { DisconnectNamedPipe(self.0.raw()) }).map(|_| ()) - } - - /// Issues an overlapped read operation to occur on this pipe. - /// - /// This function will issue an asynchronous read to occur in an overlapped - /// fashion, returning immediately. The `buf` provided will be filled in - /// with data and the request is tracked by the `overlapped` function - /// provided. - /// - /// If the operation succeeds immediately, `Ok(Some(n))` is returned where - /// `n` is the number of bytes read. If an asynchronous operation is - /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred - /// it is returned. - /// - /// When this operation completes (or if it completes immediately), another - /// mechanism must be used to learn how many bytes were transferred (such as - /// looking at the filed in the IOCP status message). - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf` and - /// `overlapped` pointers to be valid until the end of the I/O operation. - /// The kernel also requires that `overlapped` is unique for this I/O - /// operation and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that the pointers are - /// valid until the I/O operation is completed, typically via completion - /// ports and waiting to receive the completion notification on the port. - pub unsafe fn read_overlapped( - &self, - buf: &mut [u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - self.0.read_overlapped(buf, overlapped) - } - - /// Issues an overlapped write operation to occur on this pipe. - /// - /// This function will issue an asynchronous write to occur in an overlapped - /// fashion, returning immediately. The `buf` provided will be filled in - /// with data and the request is tracked by the `overlapped` function - /// provided. - /// - /// If the operation succeeds immediately, `Ok(Some(n))` is returned where - /// `n` is the number of bytes written. If an asynchronous operation is - /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred - /// it is returned. - /// - /// When this operation completes (or if it completes immediately), another - /// mechanism must be used to learn how many bytes were transferred (such as - /// looking at the filed in the IOCP status message). - /// - /// # Unsafety - /// - /// This function is unsafe because the kernel requires that the `buf` and - /// `overlapped` pointers to be valid until the end of the I/O operation. - /// The kernel also requires that `overlapped` is unique for this I/O - /// operation and is not in use for any other I/O. - /// - /// To safely use this function callers must ensure that the pointers are - /// valid until the I/O operation is completed, typically via completion - /// ports and waiting to receive the completion notification on the port. - pub unsafe fn write_overlapped( - &self, - buf: &[u8], - overlapped: *mut OVERLAPPED, - ) -> io::Result> { - self.0.write_overlapped(buf, overlapped) - } - - /// Calls the `GetOverlappedResult` function to get the result of an - /// overlapped operation for this handle. - /// - /// This function takes the `OVERLAPPED` argument which must have been used - /// to initiate an overlapped I/O operation, and returns either the - /// successful number of bytes transferred during the operation or an error - /// if one occurred. - /// - /// # Unsafety - /// - /// This function is unsafe as `overlapped` must have previously been used - /// to execute an operation for this handle, and it must also be a valid - /// pointer to an `Overlapped` instance. - /// - /// # Panics - /// - /// This function will panic - pub unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result { - let mut transferred = 0; - let r = GetOverlappedResult(self.0.raw(), overlapped, &mut transferred, FALSE); - if r == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(transferred as usize) - } - } -} - -thread_local! { - static NAMED_PIPE_OVERLAPPED: RefCell> = RefCell::new(None); -} - -/// Call a function with a threadlocal `Overlapped`. The function `f` should be -/// sure that the event is reset, either manually or by a thread being released. -fn with_threadlocal_overlapped(f: F) -> io::Result -where - F: FnOnce(&Overlapped) -> io::Result, -{ - NAMED_PIPE_OVERLAPPED.with(|overlapped| { - let mut mborrow = overlapped.borrow_mut(); - if let None = *mborrow { - let op = Overlapped::initialize_with_autoreset_event()?; - *mborrow = Some(op); - } - f(mborrow.as_ref().unwrap()) - }) -} - -impl Read for NamedPipe { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. - with_threadlocal_overlapped(|overlapped| unsafe { - self.0 - .read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) - }) - } -} -impl<'a> Read for &'a NamedPipe { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. - with_threadlocal_overlapped(|overlapped| unsafe { - self.0 - .read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) - }) - } -} - -impl Write for NamedPipe { - fn write(&mut self, buf: &[u8]) -> io::Result { - // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. - with_threadlocal_overlapped(|overlapped| unsafe { - self.0 - .write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) - }) - } - fn flush(&mut self) -> io::Result<()> { - <&NamedPipe as Write>::flush(&mut &*self) - } -} -impl<'a> Write for &'a NamedPipe { - fn write(&mut self, buf: &[u8]) -> io::Result { - // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. - with_threadlocal_overlapped(|overlapped| unsafe { - self.0 - .write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) - }) - } - fn flush(&mut self) -> io::Result<()> { - crate::cvt(unsafe { FlushFileBuffers(self.0.raw()) }).map(|_| ()) - } -} - -impl AsRawHandle for NamedPipe { - fn as_raw_handle(&self) -> HANDLE { - self.0.raw() - } -} -impl FromRawHandle for NamedPipe { - unsafe fn from_raw_handle(handle: HANDLE) -> NamedPipe { - NamedPipe(Handle::new(handle)) - } -} -impl IntoRawHandle for NamedPipe { - fn into_raw_handle(self) -> HANDLE { - self.0.into_raw() - } -} - -fn flag(slot: &mut DWORD, on: bool, val: DWORD) { - if on { - *slot |= val; - } else { - *slot &= !val; - } -} - -impl NamedPipeBuilder { - /// Creates a new named pipe builder with the default settings. - pub fn new>(addr: A) -> NamedPipeBuilder { - NamedPipeBuilder { - name: addr.as_ref().encode_wide().chain(Some(0)).collect(), - dwOpenMode: PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, - dwPipeMode: PIPE_TYPE_BYTE, - nMaxInstances: PIPE_UNLIMITED_INSTANCES, - nOutBufferSize: 65536, - nInBufferSize: 65536, - nDefaultTimeOut: 0, - } - } - - /// Indicates whether data is allowed to flow from the client to the server. - pub fn inbound(&mut self, allowed: bool) -> &mut Self { - flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_INBOUND); - self - } - - /// Indicates whether data is allowed to flow from the server to the client. - pub fn outbound(&mut self, allowed: bool) -> &mut Self { - flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_OUTBOUND); - self - } - - /// Indicates that this pipe must be the first instance. - /// - /// If set to true, then creation will fail if there's already an instance - /// elsewhere. - pub fn first(&mut self, first: bool) -> &mut Self { - flag(&mut self.dwOpenMode, first, FILE_FLAG_FIRST_PIPE_INSTANCE); - self - } - - /// Indicates whether this server can accept remote clients or not. - pub fn accept_remote(&mut self, accept: bool) -> &mut Self { - flag(&mut self.dwPipeMode, !accept, PIPE_REJECT_REMOTE_CLIENTS); - self - } - - /// Specifies the maximum number of instances of the server pipe that are - /// allowed. - /// - /// The first instance of a pipe can specify this value. A value of 255 - /// indicates that there is no limit to the number of instances. - pub fn max_instances(&mut self, instances: u8) -> &mut Self { - self.nMaxInstances = instances as DWORD; - self - } - - /// Specifies the number of bytes to reserver for the output buffer - pub fn out_buffer_size(&mut self, buffer: u32) -> &mut Self { - self.nOutBufferSize = buffer as DWORD; - self - } - - /// Specifies the number of bytes to reserver for the input buffer - pub fn in_buffer_size(&mut self, buffer: u32) -> &mut Self { - self.nInBufferSize = buffer as DWORD; - self - } - - /// Using the options in this builder, attempt to create a new named pipe. - /// - /// This function will call the `CreateNamedPipe` function and return the - /// result. - pub fn create(&mut self) -> io::Result { - unsafe { self.with_security_attributes(::std::ptr::null_mut()) } - } - - /// Using the options in the builder and the provided security attributes, attempt to create a - /// new named pipe. This function has to be called with a valid pointer to a - /// `SECURITY_ATTRIBUTES` struct that will stay valid for the lifetime of this function or a - /// null pointer. - /// - /// This function will call the `CreateNamedPipe` function and return the - /// result. - pub unsafe fn with_security_attributes( - &mut self, - attrs: *mut SECURITY_ATTRIBUTES, - ) -> io::Result { - let h = CreateNamedPipeW( - self.name.as_ptr(), - self.dwOpenMode, - self.dwPipeMode, - self.nMaxInstances, - self.nOutBufferSize, - self.nInBufferSize, - self.nDefaultTimeOut, - attrs, - ); - - if h == INVALID_HANDLE_VALUE { - Err(io::Error::last_os_error()) - } else { - Ok(NamedPipe(Handle::new(h))) - } - } -} - -#[cfg(test)] -mod tests { - use std::fs::{File, OpenOptions}; - use std::io::prelude::*; - use std::sync::mpsc::channel; - use std::thread; - use std::time::Duration; - - use rand::{thread_rng, Rng}; - - use super::{anonymous, NamedPipe, NamedPipeBuilder}; - use crate::iocp::CompletionPort; - use crate::Overlapped; - - fn name() -> String { - let name = thread_rng().gen_ascii_chars().take(30).collect::(); - format!(r"\\.\pipe\{}", name) - } - - #[test] - fn anon() { - let (mut read, mut write) = t!(anonymous(256)); - assert_eq!(t!(write.write(&[1, 2, 3])), 3); - let mut b = [0; 10]; - assert_eq!(t!(read.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]); - } - - #[test] - fn named_not_first() { - let name = name(); - let _a = t!(NamedPipe::new(&name)); - assert!(NamedPipe::new(&name).is_err()); - - t!(NamedPipeBuilder::new(&name).first(false).create()); - } - - #[test] - fn named_connect() { - let name = name(); - let a = t!(NamedPipe::new(&name)); - - let t = thread::spawn(move || { - t!(File::open(name)); - }); - - t!(a.connect()); - t!(a.disconnect()); - t!(t.join()); - } - - #[test] - fn named_wait() { - let name = name(); - let a = t!(NamedPipe::new(&name)); - - let (tx, rx) = channel(); - let t = thread::spawn(move || { - t!(NamedPipe::wait(&name, None)); - t!(File::open(&name)); - assert!(NamedPipe::wait(&name, Some(Duration::from_millis(1))).is_err()); - t!(tx.send(())); - }); - - t!(a.connect()); - t!(rx.recv()); - t!(a.disconnect()); - t!(t.join()); - } - - #[test] - fn named_connect_overlapped() { - let name = name(); - let a = t!(NamedPipe::new(&name)); - - let t = thread::spawn(move || { - t!(File::open(name)); - }); - - let cp = t!(CompletionPort::new(1)); - t!(cp.add_handle(2, &a)); - - let over = Overlapped::zero(); - unsafe { - t!(a.connect_overlapped(over.raw())); - } - - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 0); - assert_eq!(status.token(), 2); - assert_eq!(status.overlapped(), over.raw()); - t!(t.join()); - } - - #[test] - fn named_read_write() { - let name = name(); - let mut a = t!(NamedPipe::new(&name)); - - let t = thread::spawn(move || { - let mut f = t!(OpenOptions::new().read(true).write(true).open(name)); - t!(f.write_all(&[1, 2, 3])); - let mut b = [0; 10]; - assert_eq!(t!(f.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]); - }); - - t!(a.connect()); - let mut b = [0; 10]; - assert_eq!(t!(a.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]); - t!(a.write_all(&[1, 2, 3])); - t!(a.flush()); - t!(a.disconnect()); - t!(t.join()); - } - - #[test] - fn named_read_write_multi() { - for _ in 0..5 { - named_read_write() - } - } - - #[test] - fn named_read_write_multi_same_thread() { - let name1 = name(); - let mut a1 = t!(NamedPipe::new(&name1)); - let name2 = name(); - let mut a2 = t!(NamedPipe::new(&name2)); - - let t = thread::spawn(move || { - let mut f = t!(OpenOptions::new().read(true).write(true).open(name1)); - t!(f.write_all(&[1, 2, 3])); - let mut b = [0; 10]; - assert_eq!(t!(f.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]); - - let mut f = t!(OpenOptions::new().read(true).write(true).open(name2)); - t!(f.write_all(&[1, 2, 3])); - let mut b = [0; 10]; - assert_eq!(t!(f.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]); - }); - - t!(a1.connect()); - let mut b = [0; 10]; - assert_eq!(t!(a1.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]); - t!(a1.write_all(&[1, 2, 3])); - t!(a1.flush()); - t!(a1.disconnect()); - - t!(a2.connect()); - let mut b = [0; 10]; - assert_eq!(t!(a2.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]); - t!(a2.write_all(&[1, 2, 3])); - t!(a2.flush()); - t!(a2.disconnect()); - - t!(t.join()); - } - - #[test] - fn named_read_overlapped() { - let name = name(); - let a = t!(NamedPipe::new(&name)); - - let t = thread::spawn(move || { - let mut f = t!(File::create(name)); - t!(f.write_all(&[1, 2, 3])); - }); - - let cp = t!(CompletionPort::new(1)); - t!(cp.add_handle(3, &a)); - t!(a.connect()); - - let mut b = [0; 10]; - let over = Overlapped::zero(); - unsafe { - t!(a.read_overlapped(&mut b, over.raw())); - } - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 3); - assert_eq!(status.overlapped(), over.raw()); - assert_eq!(&b[..3], &[1, 2, 3]); - - t!(t.join()); - } - - #[test] - fn named_write_overlapped() { - let name = name(); - let a = t!(NamedPipe::new(&name)); - - let t = thread::spawn(move || { - let mut f = t!(super::connect(name)); - let mut b = [0; 10]; - assert_eq!(t!(f.read(&mut b)), 3); - assert_eq!(&b[..3], &[1, 2, 3]) - }); - - let cp = t!(CompletionPort::new(1)); - t!(cp.add_handle(3, &a)); - t!(a.connect()); - - let over = Overlapped::zero(); - unsafe { - t!(a.write_overlapped(&[1, 2, 3], over.raw())); - } - - let status = t!(cp.get(None)); - assert_eq!(status.bytes_transferred(), 3); - assert_eq!(status.token(), 3); - assert_eq!(status.overlapped(), over.raw()); - - t!(t.join()); - } -} +//! Interprocess Communication pipes +//! +//! A pipe is a section of shared memory that processes use for communication. +//! The process that creates a pipe is the _pipe server_. A process that connects +//! to a pipe is a _pipe client_. One process writes information to the pipe, then +//! the other process reads the information from the pipe. This overview +//! describes how to create, manage, and use pipes. +//! +//! There are two types of pipes: [anonymous pipes](#fn.anonymous.html) and +//! [named pipes](#fn.named.html). Anonymous pipes require less overhead than +//! named pipes, but offer limited services. +//! +//! # Anonymous pipes +//! +//! An anonymous pipe is an unnamed, one-way pipe that typically transfers data +//! between a parent process and a child process. Anonymous pipes are always +//! local; they cannot be used for communication over a network. +//! +//! # Named pipes +//! +//! A *named pipe* is a named, one-way or duplex pipe for communication between +//! the pipe server and one or more pipe clients. All instances of a named pipe +//! share the same pipe name, but each instance has its own buffers and handles, +//! and provides a separate conduit for client/server communication. The use of +//! instances enables multiple pipe clients to use the same named pipe +//! simultaneously. +//! +//! Any process can access named pipes, subject to security checks, making named +//! pipes an easy form of communication between related or unrelated processes. +//! +//! Any process can act as both a server and a client, making peer-to-peer +//! communication possible. As used here, the term pipe server refers to a +//! process that creates a named pipe, and the term pipe client refers to a +//! process that connects to an instance of a named pipe. +//! +//! Named pipes can be used to provide communication between processes on the +//! same computer or between processes on different computers across a network. +//! If the server service is running, all named pipes are accessible remotely. If +//! you intend to use a named pipe locally only, deny access to NT +//! AUTHORITY\\NETWORK or switch to local RPC. +//! +//! # References +//! +//! - [win32 pipe docs](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/ipc/pipes.md) + +use std::cell::RefCell; +use std::ffi::OsStr; +use std::fs::{File, OpenOptions}; +use std::io; +use std::io::prelude::*; +use std::os::windows::ffi::*; +use std::os::windows::io::*; +use std::time::Duration; + +use crate::handle::Handle; +use crate::overlapped::Overlapped; +use winapi::shared::minwindef::*; +use winapi::shared::ntdef::HANDLE; +use winapi::shared::winerror::*; +use winapi::um::fileapi::*; +use winapi::um::handleapi::*; +use winapi::um::ioapiset::*; +use winapi::um::minwinbase::*; +use winapi::um::namedpipeapi::*; +use winapi::um::winbase::*; + +/// Readable half of an anonymous pipe. +#[derive(Debug)] +pub struct AnonRead(Handle); + +/// Writable half of an anonymous pipe. +#[derive(Debug)] +pub struct AnonWrite(Handle); + +/// A named pipe that can accept connections. +#[derive(Debug)] +pub struct NamedPipe(Handle); + +/// A builder structure for creating a new named pipe. +#[derive(Debug)] +pub struct NamedPipeBuilder { + name: Vec, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, +} + +/// Creates a new anonymous in-memory pipe, returning the read/write ends of the +/// pipe. +/// +/// The buffer size for this pipe may also be specified, but the system will +/// normally use this as a suggestion and it's not guaranteed that the buffer +/// will be precisely this size. +pub fn anonymous(buffer_size: u32) -> io::Result<(AnonRead, AnonWrite)> { + let mut read = 0 as HANDLE; + let mut write = 0 as HANDLE; + crate::cvt(unsafe { CreatePipe(&mut read, &mut write, 0 as *mut _, buffer_size) })?; + Ok((AnonRead(Handle::new(read)), AnonWrite(Handle::new(write)))) +} + +impl Read for AnonRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } +} +impl<'a> Read for &'a AnonRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } +} + +impl AsRawHandle for AnonRead { + fn as_raw_handle(&self) -> HANDLE { + self.0.raw() + } +} +impl FromRawHandle for AnonRead { + unsafe fn from_raw_handle(handle: HANDLE) -> AnonRead { + AnonRead(Handle::new(handle)) + } +} +impl IntoRawHandle for AnonRead { + fn into_raw_handle(self) -> HANDLE { + self.0.into_raw() + } +} + +impl Write for AnonWrite { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} +impl<'a> Write for &'a AnonWrite { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl AsRawHandle for AnonWrite { + fn as_raw_handle(&self) -> HANDLE { + self.0.raw() + } +} +impl FromRawHandle for AnonWrite { + unsafe fn from_raw_handle(handle: HANDLE) -> AnonWrite { + AnonWrite(Handle::new(handle)) + } +} +impl IntoRawHandle for AnonWrite { + fn into_raw_handle(self) -> HANDLE { + self.0.into_raw() + } +} + +/// A convenience function to connect to a named pipe. +/// +/// This function will block the calling process until it can connect to the +/// pipe server specified by `addr`. This will use `NamedPipe::wait` internally +/// to block until it can connect. +pub fn connect>(addr: A) -> io::Result { + _connect(addr.as_ref()) +} + +fn _connect(addr: &OsStr) -> io::Result { + let mut r = OpenOptions::new(); + let mut w = OpenOptions::new(); + let mut rw = OpenOptions::new(); + r.read(true); + w.write(true); + rw.read(true).write(true); + loop { + let res = rw + .open(addr) + .or_else(|_| r.open(addr)) + .or_else(|_| w.open(addr)); + match res { + Ok(f) => return Ok(f), + Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => {} + Err(e) => return Err(e), + } + + NamedPipe::wait(addr, Some(Duration::new(20, 0)))?; + } +} + +impl NamedPipe { + /// Creates a new initial named pipe. + /// + /// This function is equivalent to: + /// + /// ``` + /// use miow::pipe::NamedPipeBuilder; + /// + /// # let addr = "foo"; + /// NamedPipeBuilder::new(addr) + /// .first(true) + /// .inbound(true) + /// .outbound(true) + /// .out_buffer_size(65536) + /// .in_buffer_size(65536) + /// .create(); + /// ``` + pub fn new>(addr: A) -> io::Result { + NamedPipeBuilder::new(addr).create() + } + + /// Waits until either a time-out interval elapses or an instance of the + /// specified named pipe is available for connection. + /// + /// If this function succeeds the process can create a `File` to connect to + /// the named pipe. + pub fn wait>(addr: A, timeout: Option) -> io::Result<()> { + NamedPipe::_wait(addr.as_ref(), timeout) + } + + fn _wait(addr: &OsStr, timeout: Option) -> io::Result<()> { + let addr = addr.encode_wide().chain(Some(0)).collect::>(); + let timeout = crate::dur2ms(timeout); + crate::cvt(unsafe { WaitNamedPipeW(addr.as_ptr(), timeout) }).map(|_| ()) + } + + /// Connects this named pipe to a client, blocking until one becomes + /// available. + /// + /// This function will call the `ConnectNamedPipe` function to await for a + /// client to connect. This can be called immediately after the pipe is + /// created, or after it has been disconnected from a previous client. + pub fn connect(&self) -> io::Result<()> { + match crate::cvt(unsafe { ConnectNamedPipe(self.0.raw(), 0 as *mut _) }) { + Ok(_) => Ok(()), + Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) => Ok(()), + Err(e) => Err(e), + } + } + + /// Issue a connection request with the specified overlapped operation. + /// + /// This function will issue a request to connect a client to this server, + /// returning immediately after starting the overlapped operation. + /// + /// If this function immediately succeeds then `Ok(true)` is returned. If + /// the overlapped operation is enqueued and pending, then `Ok(false)` is + /// returned. Otherwise an error is returned indicating what went wrong. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the + /// `overlapped` pointer is valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that this pointer is + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + pub unsafe fn connect_overlapped(&self, overlapped: *mut OVERLAPPED) -> io::Result { + match crate::cvt(ConnectNamedPipe(self.0.raw(), overlapped)) { + Ok(_) => Ok(true), + Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) => Ok(true), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) => Ok(false), + Err(ref e) if e.raw_os_error() == Some(ERROR_NO_DATA as i32) => Ok(true), + Err(e) => Err(e), + } + } + + /// Disconnects this named pipe from any connected client. + pub fn disconnect(&self) -> io::Result<()> { + crate::cvt(unsafe { DisconnectNamedPipe(self.0.raw()) }).map(|_| ()) + } + + /// Issues an overlapped read operation to occur on this pipe. + /// + /// This function will issue an asynchronous read to occur in an overlapped + /// fashion, returning immediately. The `buf` provided will be filled in + /// with data and the request is tracked by the `overlapped` function + /// provided. + /// + /// If the operation succeeds immediately, `Ok(Some(n))` is returned where + /// `n` is the number of bytes read. If an asynchronous operation is + /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred + /// it is returned. + /// + /// When this operation completes (or if it completes immediately), another + /// mechanism must be used to learn how many bytes were transferred (such as + /// looking at the filed in the IOCP status message). + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers to be valid until the end of the I/O operation. + /// The kernel also requires that `overlapped` is unique for this I/O + /// operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that the pointers are + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + pub unsafe fn read_overlapped( + &self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + self.0.read_overlapped(buf, overlapped) + } + + /// Issues an overlapped write operation to occur on this pipe. + /// + /// This function will issue an asynchronous write to occur in an overlapped + /// fashion, returning immediately. The `buf` provided will be filled in + /// with data and the request is tracked by the `overlapped` function + /// provided. + /// + /// If the operation succeeds immediately, `Ok(Some(n))` is returned where + /// `n` is the number of bytes written. If an asynchronous operation is + /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred + /// it is returned. + /// + /// When this operation completes (or if it completes immediately), another + /// mechanism must be used to learn how many bytes were transferred (such as + /// looking at the filed in the IOCP status message). + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers to be valid until the end of the I/O operation. + /// The kernel also requires that `overlapped` is unique for this I/O + /// operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that the pointers are + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + pub unsafe fn write_overlapped( + &self, + buf: &[u8], + overlapped: *mut OVERLAPPED, + ) -> io::Result> { + self.0.write_overlapped(buf, overlapped) + } + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `Overlapped` instance. + /// + /// # Panics + /// + /// This function will panic + pub unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result { + let mut transferred = 0; + let r = GetOverlappedResult(self.0.raw(), overlapped, &mut transferred, FALSE); + if r == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(transferred as usize) + } + } +} + +thread_local! { + static NAMED_PIPE_OVERLAPPED: RefCell> = RefCell::new(None); +} + +/// Call a function with a threadlocal `Overlapped`. The function `f` should be +/// sure that the event is reset, either manually or by a thread being released. +fn with_threadlocal_overlapped(f: F) -> io::Result +where + F: FnOnce(&Overlapped) -> io::Result, +{ + NAMED_PIPE_OVERLAPPED.with(|overlapped| { + let mut mborrow = overlapped.borrow_mut(); + if let None = *mborrow { + let op = Overlapped::initialize_with_autoreset_event()?; + *mborrow = Some(op); + } + f(mborrow.as_ref().unwrap()) + }) +} + +impl Read for NamedPipe { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0 + .read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } +} +impl<'a> Read for &'a NamedPipe { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0 + .read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } +} + +impl Write for NamedPipe { + fn write(&mut self, buf: &[u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0 + .write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } + fn flush(&mut self) -> io::Result<()> { + <&NamedPipe as Write>::flush(&mut &*self) + } +} +impl<'a> Write for &'a NamedPipe { + fn write(&mut self, buf: &[u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0 + .write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } + fn flush(&mut self) -> io::Result<()> { + crate::cvt(unsafe { FlushFileBuffers(self.0.raw()) }).map(|_| ()) + } +} + +impl AsRawHandle for NamedPipe { + fn as_raw_handle(&self) -> HANDLE { + self.0.raw() + } +} +impl FromRawHandle for NamedPipe { + unsafe fn from_raw_handle(handle: HANDLE) -> NamedPipe { + NamedPipe(Handle::new(handle)) + } +} +impl IntoRawHandle for NamedPipe { + fn into_raw_handle(self) -> HANDLE { + self.0.into_raw() + } +} + +fn flag(slot: &mut DWORD, on: bool, val: DWORD) { + if on { + *slot |= val; + } else { + *slot &= !val; + } +} + +impl NamedPipeBuilder { + /// Creates a new named pipe builder with the default settings. + pub fn new>(addr: A) -> NamedPipeBuilder { + NamedPipeBuilder { + name: addr.as_ref().encode_wide().chain(Some(0)).collect(), + dwOpenMode: PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, + dwPipeMode: PIPE_TYPE_BYTE, + nMaxInstances: PIPE_UNLIMITED_INSTANCES, + nOutBufferSize: 65536, + nInBufferSize: 65536, + nDefaultTimeOut: 0, + } + } + + /// Indicates whether data is allowed to flow from the client to the server. + pub fn inbound(&mut self, allowed: bool) -> &mut Self { + flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_INBOUND); + self + } + + /// Indicates whether data is allowed to flow from the server to the client. + pub fn outbound(&mut self, allowed: bool) -> &mut Self { + flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_OUTBOUND); + self + } + + /// Indicates that this pipe must be the first instance. + /// + /// If set to true, then creation will fail if there's already an instance + /// elsewhere. + pub fn first(&mut self, first: bool) -> &mut Self { + flag(&mut self.dwOpenMode, first, FILE_FLAG_FIRST_PIPE_INSTANCE); + self + } + + /// Indicates whether this server can accept remote clients or not. + pub fn accept_remote(&mut self, accept: bool) -> &mut Self { + flag(&mut self.dwPipeMode, !accept, PIPE_REJECT_REMOTE_CLIENTS); + self + } + + /// Specifies the maximum number of instances of the server pipe that are + /// allowed. + /// + /// The first instance of a pipe can specify this value. A value of 255 + /// indicates that there is no limit to the number of instances. + pub fn max_instances(&mut self, instances: u8) -> &mut Self { + self.nMaxInstances = instances as DWORD; + self + } + + /// Specifies the number of bytes to reserver for the output buffer + pub fn out_buffer_size(&mut self, buffer: u32) -> &mut Self { + self.nOutBufferSize = buffer as DWORD; + self + } + + /// Specifies the number of bytes to reserver for the input buffer + pub fn in_buffer_size(&mut self, buffer: u32) -> &mut Self { + self.nInBufferSize = buffer as DWORD; + self + } + + /// Using the options in this builder, attempt to create a new named pipe. + /// + /// This function will call the `CreateNamedPipe` function and return the + /// result. + pub fn create(&mut self) -> io::Result { + unsafe { self.with_security_attributes(::std::ptr::null_mut()) } + } + + /// Using the options in the builder and the provided security attributes, attempt to create a + /// new named pipe. This function has to be called with a valid pointer to a + /// `SECURITY_ATTRIBUTES` struct that will stay valid for the lifetime of this function or a + /// null pointer. + /// + /// This function will call the `CreateNamedPipe` function and return the + /// result. + pub unsafe fn with_security_attributes( + &mut self, + attrs: *mut SECURITY_ATTRIBUTES, + ) -> io::Result { + let h = CreateNamedPipeW( + self.name.as_ptr(), + self.dwOpenMode, + self.dwPipeMode, + self.nMaxInstances, + self.nOutBufferSize, + self.nInBufferSize, + self.nDefaultTimeOut, + attrs, + ); + + if h == INVALID_HANDLE_VALUE { + Err(io::Error::last_os_error()) + } else { + Ok(NamedPipe(Handle::new(h))) + } + } +} + +#[cfg(test)] +mod tests { + use std::fs::{File, OpenOptions}; + use std::io::prelude::*; + use std::sync::mpsc::channel; + use std::thread; + use std::time::Duration; + + use rand::{thread_rng, Rng}; + + use super::{anonymous, NamedPipe, NamedPipeBuilder}; + use crate::iocp::CompletionPort; + use crate::Overlapped; + + fn name() -> String { + let name = thread_rng().gen_ascii_chars().take(30).collect::(); + format!(r"\\.\pipe\{}", name) + } + + #[test] + fn anon() { + let (mut read, mut write) = t!(anonymous(256)); + assert_eq!(t!(write.write(&[1, 2, 3])), 3); + let mut b = [0; 10]; + assert_eq!(t!(read.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + } + + #[test] + fn named_not_first() { + let name = name(); + let _a = t!(NamedPipe::new(&name)); + assert!(NamedPipe::new(&name).is_err()); + + t!(NamedPipeBuilder::new(&name).first(false).create()); + } + + #[test] + fn named_connect() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + t!(File::open(name)); + }); + + t!(a.connect()); + t!(a.disconnect()); + t!(t.join()); + } + + #[test] + fn named_wait() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let (tx, rx) = channel(); + let t = thread::spawn(move || { + t!(NamedPipe::wait(&name, None)); + t!(File::open(&name)); + assert!(NamedPipe::wait(&name, Some(Duration::from_millis(1))).is_err()); + t!(tx.send(())); + }); + + t!(a.connect()); + t!(rx.recv()); + t!(a.disconnect()); + t!(t.join()); + } + + #[test] + fn named_connect_overlapped() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + t!(File::open(name)); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_handle(2, &a)); + + let over = Overlapped::zero(); + unsafe { + t!(a.connect_overlapped(over.raw())); + } + + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 0); + assert_eq!(status.token(), 2); + assert_eq!(status.overlapped(), over.raw()); + t!(t.join()); + } + + #[test] + fn named_read_write() { + let name = name(); + let mut a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + let mut f = t!(OpenOptions::new().read(true).write(true).open(name)); + t!(f.write_all(&[1, 2, 3])); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + t!(a.connect()); + let mut b = [0; 10]; + assert_eq!(t!(a.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + t!(a.write_all(&[1, 2, 3])); + t!(a.flush()); + t!(a.disconnect()); + t!(t.join()); + } + + #[test] + fn named_read_write_multi() { + for _ in 0..5 { + named_read_write() + } + } + + #[test] + fn named_read_write_multi_same_thread() { + let name1 = name(); + let mut a1 = t!(NamedPipe::new(&name1)); + let name2 = name(); + let mut a2 = t!(NamedPipe::new(&name2)); + + let t = thread::spawn(move || { + let mut f = t!(OpenOptions::new().read(true).write(true).open(name1)); + t!(f.write_all(&[1, 2, 3])); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + + let mut f = t!(OpenOptions::new().read(true).write(true).open(name2)); + t!(f.write_all(&[1, 2, 3])); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + t!(a1.connect()); + let mut b = [0; 10]; + assert_eq!(t!(a1.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + t!(a1.write_all(&[1, 2, 3])); + t!(a1.flush()); + t!(a1.disconnect()); + + t!(a2.connect()); + let mut b = [0; 10]; + assert_eq!(t!(a2.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + t!(a2.write_all(&[1, 2, 3])); + t!(a2.flush()); + t!(a2.disconnect()); + + t!(t.join()); + } + + #[test] + fn named_read_overlapped() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + let mut f = t!(File::create(name)); + t!(f.write_all(&[1, 2, 3])); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_handle(3, &a)); + t!(a.connect()); + + let mut b = [0; 10]; + let over = Overlapped::zero(); + unsafe { + t!(a.read_overlapped(&mut b, over.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 3); + assert_eq!(status.overlapped(), over.raw()); + assert_eq!(&b[..3], &[1, 2, 3]); + + t!(t.join()); + } + + #[test] + fn named_write_overlapped() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + let mut f = t!(super::connect(name)); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]) + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_handle(3, &a)); + t!(a.connect()); + + let over = Overlapped::zero(); + unsafe { + t!(a.write_overlapped(&[1, 2, 3], over.raw())); + } + + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 3); + assert_eq!(status.overlapped(), over.raw()); + + t!(t.join()); + } +} diff --git a/vendor/object-0.20.0/.cargo-checksum.json b/vendor/object-0.20.0/.cargo-checksum.json deleted file mode 100644 index b1b839b5f9..0000000000 --- a/vendor/object-0.20.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"ac9e13a321613d4b5abf534e6df887a67e6676c39fdb03ccf77db1e4c9e4c968","Cargo.toml":"1e57d9b0188970ace33c9e7667deb3686823cdb7ddbb297cb64c444752ffa2cb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0b74dfa0bcee5c420c6b7f67b4b2658f9ab8388c97b8e733975f2cecbdd668a6","README.md":"0125f149d521851c72fb4115ca85c1fee9c6a4b96b8e4dc79f919bc62f2ff498","examples/nm.rs":"b2e58a42b4d2c3730097b10d67788c5265bc9c0e27054ee28c60a8ecf91cbb71","examples/objcopy.rs":"6badbcd79b291894d18f217ca341d5a9131ab5ebd2320b2974a186a724525463","examples/objdump.rs":"bcd73657c86dc3a8e31de858c16603692401ddc3c5c058df8f143481018aaff0","src/common.rs":"90419289ac0d19caae8a24baa7cab26efcfe86de047dd5dc4534021cea386e39","src/elf.rs":"ce842bf73da95a3a534764161ad25e6685ea68c0909016b6dbdcc13eab23d834","src/endian.rs":"ceaad1b651627ad9e6218a168f87353ae651f5d76c9f61bc8099dff25007405e","src/lib.rs":"e737a604caea3b52bbd0811be42cb52cf52e8496ba2ca12cf7998b6c2a3084c8","src/macho.rs":"fd1c199c450f0c91d3405ef18a397fbd39ed2145c51177681c68c27dc6f92914","src/pe.rs":"8a281d134532e34d7992c3e7d047f72d5aa73b0533c0d20b91944d2045d62357","src/pod.rs":"c291b1fe11b59197fa10ef2f2cbe8d64ede58fc10121c0fff9b326dfce9a104a","src/read/any.rs":"836f34d4465c9eade56ed92b3187821a64b3a9309a685c172ade2968a4fc2c78","src/read/coff/file.rs":"b23fe39bedd78b3b03b2e590e0858c5a554f635fe83230028a270017fdd0888f","src/read/coff/mod.rs":"731ce2ab4d1393eeb527a2caa1d58c4b94bbab84bb8477d3819da1db90c6a502","src/read/coff/relocation.rs":"ca751f163fa0ed96d39331850b0e7301b2ab36038824426df2962d3767ff6c48","src/read/coff/section.rs":"9753fd0f874366365b88973e9c1cb2b3f7bf69a104671d726bbe5bc8b1f21f34","src/read/coff/symbol.rs":"5b151b6fbaf71165b13b8acc5701de229db28f60244dddca84356b8ef38a5887","src/read/elf/compression.rs":"097ff8bdc78d01a1532b11c1c0cae3b35905128c7d98b471de188d46da3ff970","src/read/elf/file.rs":"524ff5fd2f15cbffd01cfda4ce6ba392602d4ab96b1d8cd129634a7067503a69","src/read/elf/mod.rs":"339ae67d89b250e3e520cacf49c19902673b0953896de5a783ccea3652c598d9","src/read/elf/note.rs":"5aa4100de10cfe9c315fe306fe87ee7725334ce828b1b69412660d58d35db02a","src/read/elf/relocation.rs":"871ce3df59dd4940030cbbe2cb57bb77b546f3c7ab41a07c60e5838fed6efee7","src/read/elf/section.rs":"16e701e8469d2abab84db3b5965f84757615854d9f86127d18a75d283384b297","src/read/elf/segment.rs":"1e7ffe5d62b28f75773f7b22f5344444e5959301caf355354d5f962a24a32267","src/read/elf/symbol.rs":"39136fd38b6a21074a6dd8ff29ffd696298c805f0d92069eb7eb80bc197b5aba","src/read/macho/file.rs":"6ea8fd281f255376b502ac623d20a9b0b330629115ca068a9d636f9d02a978e1","src/read/macho/load_command.rs":"d6b3469140101c0d6f83f6cc5cd446c0bdd2ec2834ae2b42d2d8ca54106c0aea","src/read/macho/mod.rs":"bf5128078d75515c763f1605554557d91c3dd0fda8cc5eafc012d2c6fb2642be","src/read/macho/relocation.rs":"6cd7782f1def85e13f96c3548c00c199384028edda1de1a8d93e0aa12ce55e6a","src/read/macho/section.rs":"cb34a74020caa05e0be73f0896b96e1d58e3b0c59bddb79a8e03bc7798f6e074","src/read/macho/segment.rs":"2af4e635ee3194d78ba3dd2412c0fe74b8719eb43b46d9e2cf39b1674dafb336","src/read/macho/symbol.rs":"e799f63e43304500f20f2a7e7efbc4c769f5e3a062bb8198bf790fb44b912363","src/read/mod.rs":"8d3c6210d5ff47f87424e83c3c5991a6d923be117b875d8da6965a04f3f4f323","src/read/pe/file.rs":"d49b9bd37b8e019acd2d226c216b78954c667035682ec8eb17099ee3c1428bac","src/read/pe/mod.rs":"1a2cd741d15329e64d7089b314782db8ee39db26d45962c7e9de9aefe6d83aaf","src/read/pe/section.rs":"9333f5f74102b0ab66e2d61526fd066a65dc4c1e1add1b1dac5e9cf1df85db9e","src/read/traits.rs":"360b463c2473034c757a642a50383a27301c09a03ed7e195abb7f74f6d321099","src/read/util.rs":"a98f0720c2c393cc316184c93c2f76b6027ed3d8b2f692313c3f391b64002d6e","src/read/wasm.rs":"5598cd40adc95c89c49ee9c7d341d28feb191af6c9b553dcefdba6efbd89db43","src/write/coff.rs":"e52dcf1c5166b0419b18304ac8a7b03438b73accc715b13922c8c8ff42c14a75","src/write/elf.rs":"032cf315cc0b302a32c6de42b0bd31be174692edd697cac6634832acb77b87c4","src/write/macho.rs":"e119322a8b8e1a6c1e421a2506913854fc78b8f1d65c59b8123cdb79241145ae","src/write/mod.rs":"bb5ea4307771336b56574bec5761b82216d0ddd3c2eb220e7593fa8b9a8bc133","src/write/string.rs":"920d71223a5a146ef516b6d5fb6d22bc86a7e456da369ae8a4d1ca6b63d59892","src/write/util.rs":"f8e1015ba87f7aa6cc1634abb79c6108c3b76905683252e32b689e0796087e03","tests/integration.rs":"d491a0ae0d50c3194cd7b81720262f55ccb234251346f188284ce29729823dc2","tests/parse_self.rs":"02aebb0548a98739a0705ba07785ffe0897bd04e450c5c914313b93b4dfd6b00","tests/round_trip/bss.rs":"37c47d123346278daec5e2b6b17a5f0052802050a7856959f3c69cec11a29cd9","tests/round_trip/common.rs":"6a26da5ac9be87188dc7bd7e9ef4752d3a5c48316c22ccb8b9b3d006c24a986f","tests/round_trip/elf.rs":"d0a62bb80e00ae0d7c5ccd57d429a475289480cb2d272ffe8f9e30abbacaa9e7","tests/round_trip/mod.rs":"46adaca72a3bab87057a4a78a8095d1649cc20f7878307e815647f8dd0af298c","tests/round_trip/tls.rs":"6de25d3ec2f03cab418697d5c1699665422b2c3fbe544ba9a09ca84b635e99bf"},"package":"1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"} \ No newline at end of file diff --git a/vendor/object-0.20.0/Cargo.lock b/vendor/object-0.20.0/Cargo.lock deleted file mode 100644 index 5129377c34..0000000000 --- a/vendor/object-0.20.0/Cargo.lock +++ /dev/null @@ -1,170 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cc" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "compiler_builtins" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crc32fast" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "indexmap" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.51" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memmap" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz-sys" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide_c_api" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "object" -version = "0.20.0" -dependencies = [ - "compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-alloc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.57.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-std-workspace-alloc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-std-workspace-core" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasmparser" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" -"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" -"checksum compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" -"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356" -"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" -"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" -"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" -"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" -"checksum rustc-std-workspace-alloc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" -"checksum rustc-std-workspace-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" -"checksum wasmparser 0.57.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/object-0.20.0/README.md b/vendor/object-0.20.0/README.md deleted file mode 100644 index df0b436732..0000000000 --- a/vendor/object-0.20.0/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# `object` - -The `object` crate provides a unified interface to working with object files -across platforms. It supports reading object files and executable files, -and writing object files. diff --git a/vendor/object-0.20.0/src/lib.rs b/vendor/object-0.20.0/src/lib.rs deleted file mode 100644 index 7651fa1c31..0000000000 --- a/vendor/object-0.20.0/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! # `object` -//! -//! The `object` crate provides a unified interface to working with object files -//! across platforms. It supports reading object files and executable files, -//! and writing object files. -//! -//! See the [`File` struct](./read/struct.File.html) for details. - -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] -#![no_std] - -#[cfg(feature = "cargo-all")] -compile_error!("'--all-features' is not supported; use '--features all' instead"); - -#[allow(unused_imports)] -#[macro_use] -extern crate alloc; - -#[cfg(feature = "std")] -#[allow(unused_imports)] -#[macro_use] -extern crate std; - -mod common; -pub use common::*; - -#[macro_use] -pub mod endian; -pub use endian::*; - -#[macro_use] -pub mod pod; -pub use pod::*; - -#[cfg(feature = "read_core")] -pub mod read; -#[cfg(feature = "read_core")] -pub use read::*; - -#[cfg(feature = "write_core")] -pub mod write; - -#[cfg(feature = "elf")] -pub mod elf; -#[cfg(feature = "macho")] -pub mod macho; -#[cfg(any(feature = "coff", feature = "pe"))] -pub mod pe; diff --git a/vendor/object-0.20.0/src/read/coff/symbol.rs b/vendor/object-0.20.0/src/read/coff/symbol.rs deleted file mode 100644 index 3152e02825..0000000000 --- a/vendor/object-0.20.0/src/read/coff/symbol.rs +++ /dev/null @@ -1,250 +0,0 @@ -use alloc::fmt; -use core::convert::TryInto; -use core::str; - -use crate::endian::{LittleEndian as LE, U32Bytes}; -use crate::pe; -use crate::pod::{Bytes, Pod}; -use crate::read::util::StringTable; -use crate::read::{ - ReadError, Result, SectionIndex, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, - SymbolSection, -}; - -/// A table of symbol entries in a COFF or PE file. -/// -/// Also includes the string table used for the symbol names. -#[derive(Debug)] -pub struct SymbolTable<'data> { - symbols: &'data [pe::ImageSymbolBytes], - strings: StringTable<'data>, -} - -impl<'data> SymbolTable<'data> { - /// Read the symbol table. - pub fn parse(header: &pe::ImageFileHeader, mut data: Bytes<'data>) -> Result { - // The symbol table may not be present. - let symbol_offset = header.pointer_to_symbol_table.get(LE) as usize; - let (symbols, strings) = if symbol_offset != 0 { - data.skip(symbol_offset) - .read_error("Invalid COFF symbol table offset")?; - let symbols = data - .read_slice(header.number_of_symbols.get(LE) as usize) - .read_error("Invalid COFF symbol table size")?; - - // Note: don't update data when reading length; the length includes itself. - let length = data - .read_at::>(0) - .read_error("Missing COFF string table")? - .get(LE); - let strings = data - .read_bytes(length as usize) - .read_error("Invalid COFF string table length")?; - - (symbols, strings) - } else { - (&[][..], Bytes(&[])) - }; - - Ok(SymbolTable { - symbols, - strings: StringTable::new(strings), - }) - } - - /// Return the string table used for the symbol names. - #[inline] - pub fn strings(&self) -> StringTable<'data> { - self.strings - } - - /// Return true if the symbol table is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.symbols.is_empty() - } - - /// The number of symbols. - #[inline] - pub fn len(&self) -> usize { - self.symbols.len() - } - - /// Return the symbol table entry at the given index. - #[inline] - pub fn symbol(&self, index: usize) -> Option<&'data pe::ImageSymbol> { - self.get::(index) - } - - /// Return the symbol table entry or auxilliary record at the given index. - pub fn get(&self, index: usize) -> Option<&'data T> { - let bytes = self.symbols.get(index)?; - Bytes(&bytes.0[..]).read().ok() - } -} - -impl pe::ImageSymbol { - /// Parse a COFF symbol name. - /// - /// `strings` must be the string table used for symbols names. - pub fn name<'data>(&'data self, strings: StringTable<'data>) -> Result<&'data [u8]> { - if self.name[0] == 0 { - // If the name starts with 0 then the last 4 bytes are a string table offset. - let offset = u32::from_le_bytes(self.name[4..8].try_into().unwrap()); - strings - .get(offset) - .read_error("Invalid COFF symbol name offset") - } else { - // The name is inline and padded with nulls. - Ok(match self.name.iter().position(|&x| x == 0) { - Some(end) => &self.name[..end], - None => &self.name[..], - }) - } - } -} - -/// An iterator over the symbols of a `CoffFile`. -pub struct CoffSymbolIterator<'data, 'file> -where - 'data: 'file, -{ - pub(crate) symbols: &'file SymbolTable<'data>, - pub(crate) index: usize, -} - -impl<'data, 'file> fmt::Debug for CoffSymbolIterator<'data, 'file> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CoffSymbolIterator").finish() - } -} - -impl<'data, 'file> Iterator for CoffSymbolIterator<'data, 'file> { - type Item = (SymbolIndex, Symbol<'data>); - - fn next(&mut self) -> Option { - let index = self.index; - let symbol = self.symbols.get::(index)?; - self.index += 1 + symbol.number_of_aux_symbols as usize; - Some(( - SymbolIndex(index), - parse_symbol(self.symbols, index, symbol), - )) - } -} - -pub(crate) fn parse_symbol<'data>( - symbols: &SymbolTable<'data>, - index: usize, - symbol: &'data pe::ImageSymbol, -) -> Symbol<'data> { - let value = symbol.value.get(LE); - let section_number = symbol.section_number.get(LE); - - let name = if symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { - // The file name is in the following auxiliary symbol. - if symbol.number_of_aux_symbols > 0 { - symbols.symbols.get(index + 1).map(|s| { - // The name is padded with nulls. - match s.0.iter().position(|&x| x == 0) { - Some(end) => &s.0[..end], - None => &s.0[..], - } - }) - } else { - None - } - } else { - symbol.name(symbols.strings()).ok() - }; - let name = name.and_then(|s| str::from_utf8(s).ok()); - - let derived_kind = if symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION { - SymbolKind::Text - } else { - SymbolKind::Data - }; - let mut flags = SymbolFlags::None; - // FIXME: symbol.value is a section offset for non-absolute symbols, not an address - let (kind, address, size) = match symbol.storage_class { - pe::IMAGE_SYM_CLASS_STATIC => { - if value == 0 && symbol.number_of_aux_symbols > 0 { - let mut size = 0; - if let Some(aux) = symbols.get::(index + 1) { - size = u64::from(aux.length.get(LE)); - // TODO: use high_number for bigobj - let number = aux.number.get(LE) as usize; - flags = SymbolFlags::CoffSection { - selection: aux.selection, - associative_section: SectionIndex(number), - }; - } - (SymbolKind::Section, 0, size) - } else { - (derived_kind, u64::from(value), 0) - } - } - pe::IMAGE_SYM_CLASS_EXTERNAL => { - if section_number == pe::IMAGE_SYM_UNDEFINED { - // Common data: symbol.value is the size. - (derived_kind, 0, u64::from(value)) - } else if symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION - && symbol.number_of_aux_symbols > 0 - { - let mut size = 0; - if let Some(aux) = symbols.get::(index + 1) { - size = u64::from(aux.total_size.get(LE)); - } - (derived_kind, u64::from(value), size) - } else { - (derived_kind, u64::from(value), 0) - } - } - pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => (derived_kind, u64::from(value), 0), - pe::IMAGE_SYM_CLASS_SECTION => (SymbolKind::Section, 0, 0), - pe::IMAGE_SYM_CLASS_FILE => (SymbolKind::File, 0, 0), - pe::IMAGE_SYM_CLASS_LABEL => (SymbolKind::Label, u64::from(value), 0), - _ => { - // No address because symbol.value could mean anything. - (SymbolKind::Unknown, 0, 0) - } - }; - let section = match section_number { - pe::IMAGE_SYM_UNDEFINED => { - if symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL && value != 0 { - SymbolSection::Common - } else { - SymbolSection::Undefined - } - } - pe::IMAGE_SYM_ABSOLUTE => SymbolSection::Absolute, - pe::IMAGE_SYM_DEBUG => { - if symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { - SymbolSection::None - } else { - SymbolSection::Unknown - } - } - index if index > 0 => SymbolSection::Section(SectionIndex(index as usize - 1)), - _ => SymbolSection::Unknown, - }; - let weak = symbol.storage_class == pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL; - let scope = match symbol.storage_class { - _ if section == SymbolSection::Undefined => SymbolScope::Unknown, - pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => { - // TODO: determine if symbol is exported - SymbolScope::Linkage - } - _ => SymbolScope::Compilation, - }; - Symbol { - name, - address, - size, - kind, - section, - weak, - scope, - flags, - } -} diff --git a/vendor/object-0.20.0/src/read/macho/symbol.rs b/vendor/object-0.20.0/src/read/macho/symbol.rs deleted file mode 100644 index e2d3c33d85..0000000000 --- a/vendor/object-0.20.0/src/read/macho/symbol.rs +++ /dev/null @@ -1,235 +0,0 @@ -use core::fmt::Debug; -use core::{fmt, slice, str}; - -use crate::endian::{self, Endianness}; -use crate::macho; -use crate::pod::Pod; -use crate::read::util::StringTable; -use crate::read::{ - ReadError, Result, SectionIndex, SectionKind, Symbol, SymbolFlags, SymbolIndex, SymbolKind, - SymbolScope, SymbolSection, -}; - -use super::{MachHeader, MachOFile}; - -/// A table of symbol entries in a Mach-O file. -/// -/// Also includes the string table used for the symbol names. -#[derive(Debug, Clone, Copy)] -pub struct SymbolTable<'data, Mach: MachHeader> { - symbols: &'data [Mach::Nlist], - strings: StringTable<'data>, -} - -impl<'data, Mach: MachHeader> Default for SymbolTable<'data, Mach> { - fn default() -> Self { - SymbolTable { - symbols: &[], - strings: Default::default(), - } - } -} - -impl<'data, Mach: MachHeader> SymbolTable<'data, Mach> { - #[inline] - pub(super) fn new(symbols: &'data [Mach::Nlist], strings: StringTable<'data>) -> Self { - SymbolTable { symbols, strings } - } - - /// Return the string table used for the symbol names. - #[inline] - pub fn strings(&self) -> StringTable<'data> { - self.strings - } - - /// Iterate over the symbols. - #[inline] - pub fn iter(&self) -> slice::Iter<'data, Mach::Nlist> { - self.symbols.iter() - } - - /// Return true if the symbol table is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.symbols.is_empty() - } - - /// Return the symbol at the given index. - pub fn symbol(&self, index: usize) -> Result<&'data Mach::Nlist> { - self.symbols - .get(index) - .read_error("Invalid Mach-O symbol index") - } -} - -/// An iterator over the symbols of a `MachOFile32`. -pub type MachOSymbolIterator32<'data, 'file, Endian = Endianness> = - MachOSymbolIterator<'data, 'file, macho::MachHeader32>; -/// An iterator over the symbols of a `MachOFile64`. -pub type MachOSymbolIterator64<'data, 'file, Endian = Endianness> = - MachOSymbolIterator<'data, 'file, macho::MachHeader64>; - -/// An iterator over the symbols of a `MachOFile`. -pub struct MachOSymbolIterator<'data, 'file, Mach: MachHeader> { - pub(super) file: &'file MachOFile<'data, Mach>, - pub(super) symbols: SymbolTable<'data, Mach>, - pub(super) index: usize, -} - -impl<'data, 'file, Mach: MachHeader> fmt::Debug for MachOSymbolIterator<'data, 'file, Mach> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MachOSymbolIterator").finish() - } -} - -impl<'data, 'file, Mach: MachHeader> Iterator for MachOSymbolIterator<'data, 'file, Mach> { - type Item = (SymbolIndex, Symbol<'data>); - - fn next(&mut self) -> Option { - loop { - let index = self.index; - let nlist = self.symbols.symbols.get(index)?; - self.index += 1; - if let Some(symbol) = parse_symbol(self.file, nlist, self.symbols.strings) { - return Some((SymbolIndex(index), symbol)); - } - } - } -} - -pub(super) fn parse_symbol<'data, Mach: MachHeader>( - file: &MachOFile<'data, Mach>, - nlist: &Mach::Nlist, - strings: StringTable<'data>, -) -> Option> { - let endian = file.endian; - let name = nlist - .name(endian, strings) - .ok() - .and_then(|s| str::from_utf8(s).ok()); - let n_type = nlist.n_type(); - let n_desc = nlist.n_desc(endian); - if n_type & macho::N_STAB != 0 { - return None; - } - let section = match n_type & macho::N_TYPE { - macho::N_UNDF => SymbolSection::Undefined, - macho::N_ABS => SymbolSection::Absolute, - macho::N_SECT => { - let n_sect = nlist.n_sect(); - if n_sect != 0 { - SymbolSection::Section(SectionIndex(n_sect as usize)) - } else { - SymbolSection::Unknown - } - } - _ => SymbolSection::Unknown, - }; - let kind = section - .index() - .and_then(|index| file.section_internal(index).ok()) - .map(|section| match section.kind { - SectionKind::Text => SymbolKind::Text, - SectionKind::Data - | SectionKind::ReadOnlyData - | SectionKind::ReadOnlyString - | SectionKind::UninitializedData - | SectionKind::Common => SymbolKind::Data, - SectionKind::Tls | SectionKind::UninitializedTls | SectionKind::TlsVariables => { - SymbolKind::Tls - } - _ => SymbolKind::Unknown, - }) - .unwrap_or(SymbolKind::Unknown); - let weak = n_desc & (macho::N_WEAK_REF | macho::N_WEAK_DEF) != 0; - let scope = if section == SymbolSection::Undefined { - SymbolScope::Unknown - } else if n_type & macho::N_EXT == 0 { - SymbolScope::Compilation - } else if n_type & macho::N_PEXT != 0 { - SymbolScope::Linkage - } else { - SymbolScope::Dynamic - }; - let flags = SymbolFlags::MachO { n_desc }; - Some(Symbol { - name, - address: nlist.n_value(endian).into(), - // Only calculated for symbol maps - size: 0, - kind, - section, - weak, - scope, - flags, - }) -} - -/// A trait for generic access to `Nlist32` and `Nlist64`. -#[allow(missing_docs)] -pub trait Nlist: Debug + Pod { - type Word: Into; - type Endian: endian::Endian; - - fn n_strx(&self, endian: Self::Endian) -> u32; - fn n_type(&self) -> u8; - fn n_sect(&self) -> u8; - fn n_desc(&self, endian: Self::Endian) -> u16; - fn n_value(&self, endian: Self::Endian) -> Self::Word; - - fn name<'data>( - &self, - endian: Self::Endian, - strings: StringTable<'data>, - ) -> Result<&'data [u8]> { - strings - .get(self.n_strx(endian)) - .read_error("Invalid Mach-O symbol name offset") - } - - fn is_undefined(&self) -> bool { - self.n_type() & macho::N_TYPE == macho::N_UNDF - } -} - -impl Nlist for macho::Nlist32 { - type Word = u32; - type Endian = Endian; - - fn n_strx(&self, endian: Self::Endian) -> u32 { - self.n_strx.get(endian) - } - fn n_type(&self) -> u8 { - self.n_type - } - fn n_sect(&self) -> u8 { - self.n_sect - } - fn n_desc(&self, endian: Self::Endian) -> u16 { - self.n_desc.get(endian) - } - fn n_value(&self, endian: Self::Endian) -> Self::Word { - self.n_value.get(endian) - } -} - -impl Nlist for macho::Nlist64 { - type Word = u64; - type Endian = Endian; - - fn n_strx(&self, endian: Self::Endian) -> u32 { - self.n_strx.get(endian) - } - fn n_type(&self) -> u8 { - self.n_type - } - fn n_sect(&self) -> u8 { - self.n_sect - } - fn n_desc(&self, endian: Self::Endian) -> u16 { - self.n_desc.get(endian) - } - fn n_value(&self, endian: Self::Endian) -> Self::Word { - self.n_value.get(endian) - } -} diff --git a/vendor/object/.cargo-checksum.json b/vendor/object/.cargo-checksum.json new file mode 100644 index 0000000000..592f1bf581 --- /dev/null +++ b/vendor/object/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"603c5210dd959cf6ebd1cf3f9f4c115dafb2918e8d16c734eba1e375e9229365","Cargo.toml":"13af9055d96778670a80d939840f95389e90522049a196dcf2f87fed1db2936d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0b74dfa0bcee5c420c6b7f67b4b2658f9ab8388c97b8e733975f2cecbdd668a6","README.md":"8d2a8e636daba9e9b80c316c5eddacf9dc0abfda23eb321c406654b8443b9926","examples/ar.rs":"e7944efd03ad1bb70344bbf9d10e4ed44aa5ccdcfa70af2b1e76c130f6d5db93","examples/nm.rs":"25c40b89ac96298b6a99282bd9d459fcbb194e25a8fcdffd283248802e7aa8d7","examples/objcopy.rs":"64093c98fb5236a83cbd3046f171bbc3ecc6e1edf57e5416f39feac000e071e1","examples/objdump.rs":"2681e0008b35582e88b0eb04e9fee340fee475ccedcf4a729775cfdbb5b81270","examples/objectmap.rs":"0affc3afecea8e5418c3a839fa2697c914c4978d646dbb5841892dbac4df4a1c","src/archive.rs":"7ca11076759d4b87b42657f866b0d2b1dd07d2536b19645da0a5da5dd713b77d","src/common.rs":"d457c3747260d579ad6776820848de454850d384b5e3dbba31eb3309ec42fd55","src/elf.rs":"16a75ec17035f8b72ffb496765acbe175e52032df03e81d641575480bb63dfd6","src/endian.rs":"ceaad1b651627ad9e6218a168f87353ae651f5d76c9f61bc8099dff25007405e","src/lib.rs":"73aa5890f0c5c63bbf82704877cb98f9344162f2edd1b47afb963ff76d5efc9d","src/macho.rs":"fd1c199c450f0c91d3405ef18a397fbd39ed2145c51177681c68c27dc6f92914","src/pe.rs":"e21f22c28d06befb71292c449e5274ca620f4dbdf6cf331959d93791c1873c82","src/pod.rs":"47c2a4cd75df89cae932e318260586da4216510a2e3fa40fa9885894d9f973a2","src/read/any.rs":"7fbf06d083b15e69ebf83ec89880cf1bc0aead7cb803f90e47b55398bf56b827","src/read/archive.rs":"9c2d7d6f2aea2a2733a86f170264963e4dc2645622e0502c71a5fd41015e055e","src/read/coff/comdat.rs":"baa64820b25e17a50708afc616fb3a3eb308b183a93222d0d55be8aff26b6026","src/read/coff/file.rs":"994f05798bc81dc8ea82ede0629f16147492e096bdb51ab7113738ad57018552","src/read/coff/mod.rs":"5eed1c0ca7cf044b3173223b06afacc4961a0515ef2478fffa35641f4ee364ee","src/read/coff/relocation.rs":"ca751f163fa0ed96d39331850b0e7301b2ab36038824426df2962d3767ff6c48","src/read/coff/section.rs":"351a160ed6c11cf297b3b3316d3b87b3a6f31782763715d70eeae17555e8e6a1","src/read/coff/symbol.rs":"70e6db6b66941d5dabad72aa8bbcfe345cf50a204978f6281bfc486ab9007e4a","src/read/elf/comdat.rs":"2d8f7ecd4545351e89b3d1d98fadccf26e0a350cdfc42c6d4f5ea29e8ce3d72c","src/read/elf/compression.rs":"097ff8bdc78d01a1532b11c1c0cae3b35905128c7d98b471de188d46da3ff970","src/read/elf/file.rs":"b0bc065b150819d0e130cdfb42a792493e6d173f2723bd1c71de3399bdcff50d","src/read/elf/mod.rs":"365e0aaae1b33600c9f8a2b944a780d650266f83cb03d4546268fb40ef2b3604","src/read/elf/note.rs":"5aa4100de10cfe9c315fe306fe87ee7725334ce828b1b69412660d58d35db02a","src/read/elf/relocation.rs":"cf82b981f8faafee9a1129926a16757a23b80d00862c0389a4a837b4cc417f0a","src/read/elf/section.rs":"bec4b919ac6d0e15478d0a0c588388e4d78be394c590f71e1a1d75ab26aa97b5","src/read/elf/segment.rs":"1e7ffe5d62b28f75773f7b22f5344444e5959301caf355354d5f962a24a32267","src/read/elf/symbol.rs":"b5346bc2c46750eacf7fc5f44f9985b86b9e79da7324a66f19e6493477eccd35","src/read/macho/file.rs":"e299932d923391807c57de0ec41a1412391b0d0816570a1ca40234c8c265ef6a","src/read/macho/load_command.rs":"d6b3469140101c0d6f83f6cc5cd446c0bdd2ec2834ae2b42d2d8ca54106c0aea","src/read/macho/mod.rs":"bf5128078d75515c763f1605554557d91c3dd0fda8cc5eafc012d2c6fb2642be","src/read/macho/relocation.rs":"6cd7782f1def85e13f96c3548c00c199384028edda1de1a8d93e0aa12ce55e6a","src/read/macho/section.rs":"cb34a74020caa05e0be73f0896b96e1d58e3b0c59bddb79a8e03bc7798f6e074","src/read/macho/segment.rs":"2af4e635ee3194d78ba3dd2412c0fe74b8719eb43b46d9e2cf39b1674dafb336","src/read/macho/symbol.rs":"c8dcbf38506069039a2791a6c0b25ef95690c70a22ec4f6703e2c21e4c56dd3f","src/read/mod.rs":"036cebc7809874990d0f74e0bff2dceb9ec430f77bd16b0b7114cfd7c8c55be9","src/read/pe/file.rs":"2bb2932bd09c51703958a093845beb18ec6d2cd8e0bfa0a994711be2d71333c9","src/read/pe/mod.rs":"1a2cd741d15329e64d7089b314782db8ee39db26d45962c7e9de9aefe6d83aaf","src/read/pe/section.rs":"0f03cace202198dceb1e47f9d03c3a9b491f72fa3bd3d5f27a7dcd29991151d1","src/read/traits.rs":"d988b028fb6b8a108ce66ce49b2cfc36e653b5ba3f8a4a78b3ea7f76fe8166dd","src/read/util.rs":"a98f0720c2c393cc316184c93c2f76b6027ed3d8b2f692313c3f391b64002d6e","src/read/wasm.rs":"d483a0b408d9262f549610007d72f1bd282b08842e75a393394824fbd775d91d","src/write/coff.rs":"40f20a60090c9ca188b67dafb9a440f914d69063e6d81567468945a00125bfa8","src/write/elf.rs":"f94be9c3065d7ddc5ab6e98efdbca3848e17c494e8a5afb804453d122cd06ce6","src/write/macho.rs":"1ea6c84fe506ede639578b751299779ba51a84ee625751b9fa7e3e19ea20273b","src/write/mod.rs":"a68240e3db6e20f967d54f958e8cc335daee2a063aa2e51dc1ab7f224e831e5c","src/write/string.rs":"920d71223a5a146ef516b6d5fb6d22bc86a7e456da369ae8a4d1ca6b63d59892","src/write/util.rs":"c7f75a08c67a431edf14a4ef25b504196b9f4aef7145213aade1f5a290612c0c","tests/integration.rs":"d491a0ae0d50c3194cd7b81720262f55ccb234251346f188284ce29729823dc2","tests/parse_self.rs":"02aebb0548a98739a0705ba07785ffe0897bd04e450c5c914313b93b4dfd6b00","tests/round_trip/bss.rs":"021b909a03b86f1960291e7855bd7ca34c8eb6dc142f7b79f57b449042f18c3e","tests/round_trip/comdat.rs":"da73e513788f714ac98cc5dfe7bee22493959ac7ae91af539f1c912f59d63db6","tests/round_trip/common.rs":"311314045a32c1d7852b828f49fd841285d23c3faa92c53cd5eb11a0b003673f","tests/round_trip/elf.rs":"28b66be3c264dd80a6c122372036e88bc58a87c91ac1e57dbe8d8f4505ac0054","tests/round_trip/mod.rs":"0e73aa4ab258a313d17b4988f2f2c30f7716142c0a54219d5d4de3c1e1965753","tests/round_trip/tls.rs":"e73a8a4c0f064884b507bf75e7b9e20aaf557bf2cbfcd23ed577dc6c39d9f300"},"package":"8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"} \ No newline at end of file diff --git a/vendor/object/Cargo.lock b/vendor/object/Cargo.lock new file mode 100644 index 0000000000..217d5d01e4 --- /dev/null +++ b/vendor/object/Cargo.lock @@ -0,0 +1,144 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "compiler_builtins" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" + +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "flate2" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + +[[package]] +name = "hashbrown" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" +dependencies = [ + "autocfg", +] + +[[package]] +name = "indexmap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "libc" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.22.0" +dependencies = [ + "compiler_builtins", + "crc32fast", + "flate2", + "indexmap", + "memmap", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "wasmparser", +] + +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" + +[[package]] +name = "wasmparser" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/object-0.20.0/Cargo.toml b/vendor/object/Cargo.toml similarity index 87% rename from vendor/object-0.20.0/Cargo.toml rename to vendor/object/Cargo.toml index b53c3722b8..417c8208e9 100644 --- a/vendor/object-0.20.0/Cargo.toml +++ b/vendor/object/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "object" -version = "0.20.0" +version = "0.22.0" authors = ["Nick Fitzgerald ", "Philip Craig "] exclude = ["/.coveralls.yml", "/.travis.yml"] description = "A unified interface for reading and writing object file formats." @@ -33,7 +33,15 @@ required-features = ["read", "write"] [[example]] name = "objdump" -required-features = ["read"] +required-features = ["read_core"] + +[[example]] +name = "ar" +required-features = ["read_core", "archive"] + +[[example]] +name = "objectmap" +required-features = ["read_core"] [dependencies.alloc] version = "1.0.0" optional = true @@ -68,6 +76,7 @@ version = "0.7" [features] all = ["read", "write", "std", "compression", "default"] +archive = [] cargo-all = [] coff = [] compression = ["flate2", "std"] @@ -75,7 +84,7 @@ default = ["read", "compression"] elf = [] macho = [] pe = ["coff"] -read = ["read_core", "coff", "elf", "macho", "pe", "wasm", "unaligned"] +read = ["read_core", "archive", "coff", "elf", "macho", "pe", "wasm", "unaligned"] read_core = [] rustc-dep-of-std = ["core", "compiler_builtins", "alloc"] std = [] diff --git a/vendor/object/LICENSE-APACHE b/vendor/object/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/vendor/object/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/object-0.20.0/LICENSE-MIT b/vendor/object/LICENSE-MIT similarity index 100% rename from vendor/object-0.20.0/LICENSE-MIT rename to vendor/object/LICENSE-MIT diff --git a/vendor/object/README.md b/vendor/object/README.md new file mode 100644 index 0000000000..f09af4ac24 --- /dev/null +++ b/vendor/object/README.md @@ -0,0 +1,31 @@ +# `object` + +The `object` crate provides a unified interface to working with object files +across platforms. It supports reading object files and executable files, +and writing object files. + +For reading files, it provides multiple levels of support: + +* raw struct definitions suitable for zero copy access +* low level APIs for accessing the raw structs +* a higher level unified API for accessing common features of object files, such + as sections and symbols + +Supported file formats: ELF, Mach-O, Windows PE/COFF, and Unix archive. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +See [CONTRIBUTING.md](./CONTRIBUTING.md) for hacking. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/vendor/object/examples/ar.rs b/vendor/object/examples/ar.rs new file mode 100644 index 0000000000..8781ff2115 --- /dev/null +++ b/vendor/object/examples/ar.rs @@ -0,0 +1,47 @@ +use std::{env, fs, process}; + +fn main() { + let mut args = env::args().skip(1); + if args.len() < 2 { + eprintln!( + "Usage: {} [...]", + env::args().next().unwrap() + ); + process::exit(1); + } + + let op = args.next().unwrap(); + let file_path = args.next().unwrap(); + + let file = match fs::File::open(&file_path) { + Ok(file) => file, + Err(err) => { + println!("Failed to open file '{}': {}", file_path, err,); + return; + } + }; + let file = match unsafe { memmap::Mmap::map(&file) } { + Ok(mmap) => mmap, + Err(err) => { + println!("Failed to map file '{}': {}", file_path, err,); + return; + } + }; + let archive = match object::read::archive::ArchiveFile::parse(&*file) { + Ok(file) => file, + Err(err) => { + println!("Failed to parse file '{}': {}", file_path, err); + return; + } + }; + match op.chars().next().unwrap() { + 't' => { + println!("kind: {:?}", archive.kind()); + for member in archive.members() { + let member = member.unwrap(); + println!("{}", String::from_utf8_lossy(member.name())); + } + } + op => println!("Invalid operation: {}", op), + } +} diff --git a/vendor/object-0.20.0/examples/nm.rs b/vendor/object/examples/nm.rs similarity index 90% rename from vendor/object-0.20.0/examples/nm.rs rename to vendor/object/examples/nm.rs index 67a1d31b98..6c35737dea 100644 --- a/vendor/object-0.20.0/examples/nm.rs +++ b/vendor/object/examples/nm.rs @@ -1,4 +1,7 @@ -use object::{Object, ObjectSection, SectionIndex, SectionKind, Symbol, SymbolKind, SymbolSection}; +use object::{ + Object, ObjectSection, ObjectSymbol, SectionIndex, SectionKind, Symbol, SymbolKind, + SymbolSection, +}; use std::collections::HashMap; use std::{env, fs, process}; @@ -40,19 +43,19 @@ fn main() { let section_kinds = file.sections().map(|s| (s.index(), s.kind())).collect(); println!("Debugging symbols:"); - for (_, symbol) in file.symbols() { + for symbol in file.symbols() { print_symbol(&symbol, §ion_kinds); } println!(); println!("Dynamic symbols:"); - for (_, symbol) in file.dynamic_symbols() { + for symbol in file.dynamic_symbols() { print_symbol(&symbol, §ion_kinds); } } } -fn print_symbol(symbol: &Symbol<'_>, section_kinds: &HashMap) { +fn print_symbol(symbol: &Symbol<'_, '_>, section_kinds: &HashMap) { if let SymbolKind::Section | SymbolKind::File = symbol.kind() { return; } diff --git a/vendor/object-0.20.0/examples/objcopy.rs b/vendor/object/examples/objcopy.rs similarity index 79% rename from vendor/object-0.20.0/examples/objcopy.rs rename to vendor/object/examples/objcopy.rs index 4258f78a6e..8d2c11401b 100644 --- a/vendor/object-0.20.0/examples/objcopy.rs +++ b/vendor/object/examples/objcopy.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use std::{env, fs, process}; use object::{ - write, Object, ObjectSection, RelocationTarget, SectionKind, SymbolFlags, SymbolKind, - SymbolSection, + write, Object, ObjectComdat, ObjectSection, ObjectSymbol, RelocationTarget, SectionKind, + SymbolFlags, SymbolKind, SymbolSection, }; fn main() { @@ -73,7 +73,7 @@ fn main() { } let mut out_symbols = HashMap::new(); - for (symbol_index, in_symbol) in in_object.symbols() { + for in_symbol in in_object.symbols() { if in_symbol.kind() == SymbolKind::Null { continue; } @@ -83,10 +83,18 @@ fn main() { SymbolSection::Undefined => (write::SymbolSection::Undefined, in_symbol.address()), SymbolSection::Absolute => (write::SymbolSection::Absolute, in_symbol.address()), SymbolSection::Common => (write::SymbolSection::Common, in_symbol.address()), - SymbolSection::Section(index) => ( - write::SymbolSection::Section(*out_sections.get(&index).unwrap()), - in_symbol.address() - in_object.section_by_index(index).unwrap().address(), - ), + SymbolSection::Section(index) => { + if let Some(out_section) = out_sections.get(&index) { + ( + write::SymbolSection::Section(*out_section), + in_symbol.address() - in_object.section_by_index(index).unwrap().address(), + ) + } else { + // Ignore symbols for sections that we have skipped. + assert_eq!(in_symbol.kind(), SymbolKind::Section); + continue; + } + } }; let flags = match in_symbol.flags() { SymbolFlags::None => SymbolFlags::None, @@ -96,7 +104,8 @@ fn main() { selection, associative_section, } => { - let associative_section = *out_sections.get(&associative_section).unwrap(); + let associative_section = + associative_section.map(|index| *out_sections.get(&index).unwrap()); SymbolFlags::CoffSection { selection, associative_section, @@ -114,7 +123,7 @@ fn main() { flags, }; let symbol_id = out_object.add_symbol(out_symbol); - out_symbols.insert(symbol_index, symbol_id); + out_symbols.insert(in_symbol.index(), symbol_id); } for in_section in in_object.sections() { @@ -143,6 +152,18 @@ fn main() { } } + for in_comdat in in_object.comdats() { + let mut sections = Vec::new(); + for in_section in in_comdat.sections() { + sections.push(*out_sections.get(&in_section).unwrap()); + } + out_object.add_comdat(write::Comdat { + kind: in_comdat.kind(), + symbol: *out_symbols.get(&in_comdat.symbol()).unwrap(), + sections, + }); + } + let out_data = out_object.write().unwrap(); if let Err(err) = fs::write(&out_file_path, out_data) { eprintln!("Failed to write file '{}': {}", out_file_path, err); diff --git a/vendor/object-0.20.0/examples/objdump.rs b/vendor/object/examples/objdump.rs similarity index 86% rename from vendor/object-0.20.0/examples/objdump.rs rename to vendor/object/examples/objdump.rs index bb5246c741..4bcfe43bf8 100644 --- a/vendor/object-0.20.0/examples/objdump.rs +++ b/vendor/object/examples/objdump.rs @@ -1,4 +1,4 @@ -use object::{Object, ObjectSection}; +use object::{Object, ObjectComdat, ObjectSection, ObjectSymbol}; use std::{env, fs, process}; fn main() { @@ -64,8 +64,16 @@ fn main() { println!("{}: {:?}", section.index().0, section); } - for (index, symbol) in file.symbols() { - println!("{}: {:?}", index.0, symbol); + for comdat in file.comdats() { + print!("{:?} Sections:", comdat); + for section in comdat.sections() { + print!(" {}", section.0); + } + println!(); + } + + for symbol in file.symbols() { + println!("{}: {:?}", symbol.index().0, symbol); } for section in file.sections() { diff --git a/vendor/object/examples/objectmap.rs b/vendor/object/examples/objectmap.rs new file mode 100644 index 0000000000..743fac9a85 --- /dev/null +++ b/vendor/object/examples/objectmap.rs @@ -0,0 +1,67 @@ +use object::Object; +use std::{env, fs, process}; + +fn main() { + let mut args = env::args().skip(1); + if args.len() == 0 { + eprintln!( + "Usage: {} [address] ...", + env::args().next().unwrap() + ); + process::exit(1); + } + + let file_path = args.next().unwrap(); + let file = match fs::File::open(&file_path) { + Ok(file) => file, + Err(err) => { + println!("Failed to open file '{}': {}", file_path, err,); + process::exit(1); + } + }; + let file = match unsafe { memmap::Mmap::map(&file) } { + Ok(mmap) => mmap, + Err(err) => { + println!("Failed to map file '{}': {}", file_path, err,); + process::exit(1); + } + }; + let file = match object::File::parse(&*file) { + Ok(file) => file, + Err(err) => { + println!("Failed to parse file '{}': {}", file_path, err); + process::exit(1); + } + }; + + let map = file.object_map(); + + if args.len() == 0 { + for symbol in map.symbols() { + print_symbol(symbol, &map); + } + } else { + for arg in args { + let mut arg = &arg[..]; + if arg.starts_with("0x") { + arg = &arg[2..]; + } + let address = u64::from_str_radix(arg, 16).expect("Failed to parse address"); + if let Some(symbol) = map.get(address) { + print_symbol(symbol, &map); + } else { + println!("{:} not found", address); + } + } + } +} + +fn print_symbol(symbol: &object::ObjectMapEntry<'_>, map: &object::ObjectMap<'_>) { + println!( + "{:x} {:x} {} {}", + symbol.address(), + symbol.size(), + String::from_utf8_lossy(symbol.name()), + String::from_utf8_lossy(symbol.object(map)), + ); +} diff --git a/vendor/object/src/archive.rs b/vendor/object/src/archive.rs new file mode 100644 index 0000000000..d4b419beba --- /dev/null +++ b/vendor/object/src/archive.rs @@ -0,0 +1,39 @@ +//! Archive definitions. +//! +//! These definitions are independent of read/write support, although we do implement +//! some traits useful for those. + +use crate::pod::Pod; + +/// File identification bytes stored at the beginning of the file. +pub const MAGIC: [u8; 8] = *b"!\n"; + +/// File identification bytes stored at the beginning of a thin archive. +/// +/// A thin archive only contains a symbol table and file names. +pub const THIN_MAGIC: [u8; 8] = *b"!\n"; + +/// The terminator for each archive member header. +pub const TERMINATOR: [u8; 2] = *b"`\n"; + +/// The header at the start of an archive member. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Header { + /// The file name. + pub name: [u8; 16], + /// File modification timestamp in decimal. + pub date: [u8; 12], + /// User ID in decimal. + pub uid: [u8; 6], + /// Group ID in decimal. + pub gid: [u8; 6], + /// File mode in octal. + pub mode: [u8; 8], + /// File size in decimal. + pub size: [u8; 10], + /// Must be equal to `TERMINATOR`. + pub terminator: [u8; 2], +} + +unsafe_impl_pod!(Header); diff --git a/vendor/object-0.20.0/src/common.rs b/vendor/object/src/common.rs similarity index 85% rename from vendor/object-0.20.0/src/common.rs rename to vendor/object/src/common.rs index cb47e28711..4b2724ec6e 100644 --- a/vendor/object-0.20.0/src/common.rs +++ b/vendor/object/src/common.rs @@ -7,6 +7,7 @@ pub enum Architecture { Arm, I386, Mips, + S390x, Wasm32, X86_64, } @@ -22,6 +23,7 @@ impl Architecture { Architecture::Arm => Some(AddressSize::U32), Architecture::I386 => Some(AddressSize::U32), Architecture::Mips => Some(AddressSize::U32), + Architecture::S390x => Some(AddressSize::U64), Architecture::Wasm32 => Some(AddressSize::U32), Architecture::X86_64 => Some(AddressSize::U64), } @@ -135,7 +137,7 @@ pub enum SectionKind { Note, /// Metadata such as symbols or relocations. /// - /// Example ELF sections: `.symtab`, `.strtab` + /// Example ELF sections: `.symtab`, `.strtab`, `.group` Metadata, } @@ -148,6 +150,40 @@ impl SectionKind { } } +/// The selection kind for a COMDAT section group. +/// +/// This determines the way in which the linker resolves multiple definitions of the COMDAT +/// sections. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ComdatKind { + /// The selection kind is unknown. + Unknown, + /// Multiple definitions are allowed. + /// + /// An arbitrary definition is selected, and the rest are removed. + /// + /// This is the only supported selection kind for ELF. + Any, + /// Multiple definitions are not allowed. + /// + /// This is used to group sections without allowing duplicates. + NoDuplicates, + /// Multiple definitions must have the same size. + /// + /// An arbitrary definition is selected, and the rest are removed. + SameSize, + /// Multiple definitions must match exactly. + /// + /// An arbitrary definition is selected, and the rest are removed. + ExactMatch, + /// Multiple definitions are allowed, and the largest is selected. + /// + /// An arbitrary definition with the largest size is selected, and the rest are removed. + Largest, + /// Multiple definitions are allowed, and the newest is selected. + Newest, +} + /// The kind of a symbol. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SymbolKind { @@ -257,6 +293,11 @@ pub enum RelocationEncoding { /// /// The `RelocationKind` must be PC relative. X86Branch, + + /// s390x PC-relative offset shifted right by one bit. + /// + /// The `RelocationKind` must be PC relative. + S390xDbl, } /// File flags that are specific to each file format. @@ -325,6 +366,6 @@ pub enum SymbolFlags
{ /// `Selection` field in the auxiliary symbol for the section. selection: u8, /// `Number` field in the auxiliary symbol for the section. - associative_section: Section, + associative_section: Option
, }, } diff --git a/vendor/object-0.20.0/src/elf.rs b/vendor/object/src/elf.rs similarity index 99% rename from vendor/object-0.20.0/src/elf.rs rename to vendor/object/src/elf.rs index 0f6db17334..d8ff6c9668 100644 --- a/vendor/object-0.20.0/src/elf.rs +++ b/vendor/object/src/elf.rs @@ -890,9 +890,9 @@ impl Sym64 { #[repr(C)] pub struct Syminfo32 { /// Direct bindings, symbol bound to. - si_boundto: U16, + pub si_boundto: U16, /// Per symbol flags. - si_flags: U16, + pub si_flags: U16, } /// Additional information about a `Sym64`. @@ -900,9 +900,9 @@ pub struct Syminfo32 { #[repr(C)] pub struct Syminfo64 { /// Direct bindings, symbol bound to. - si_boundto: U16, + pub si_boundto: U16, /// Per symbol flags. - si_flags: U16, + pub si_flags: U16, } // Values for `Syminfo*::si_boundto`. @@ -1392,9 +1392,9 @@ pub const NT_VERSION: u32 = 1; #[repr(C)] pub struct Dyn32 { /// Dynamic entry type. - d_tag: I32, + pub d_tag: I32, /// Value (integer or address). - d_val: U32, + pub d_val: U32, } /// Dynamic section entry. @@ -1402,9 +1402,9 @@ pub struct Dyn32 { #[repr(C)] pub struct Dyn64 { /// Dynamic entry type. - d_tag: I64, + pub d_tag: I64, /// Value (integer or address). - d_val: U64, + pub d_val: U64, } // Values for `Dyn*::d_tag`. diff --git a/vendor/object-0.20.0/src/endian.rs b/vendor/object/src/endian.rs similarity index 100% rename from vendor/object-0.20.0/src/endian.rs rename to vendor/object/src/endian.rs diff --git a/vendor/object/src/lib.rs b/vendor/object/src/lib.rs new file mode 100644 index 0000000000..12fef8b34b --- /dev/null +++ b/vendor/object/src/lib.rs @@ -0,0 +1,71 @@ +//! # `object` +//! +//! The `object` crate provides a unified interface to working with object files +//! across platforms. It supports reading object files and executable files, +//! and writing object files. +//! +//! ## Raw struct definitions +//! +//! Raw structs are defined for: [ELF](elf), [Mach-O](macho), [PE/COFF](pe), [archive]. +//! Types and traits for zerocopy support are defined in [pod] and [endian]. +//! +//! ## Unified read API +//! +//! The [read::Object] trait defines the unified interace. This trait is implemented +//! by [read::File], which allows reading any file format, as well as implementations +//! for each file format: [ELF](read::elf::ElfFile), [Mach-O](read::macho::MachOFile), +//! [COFF](read::coff::CoffFile), [PE](read::pe::PeFile), [Wasm](read::wasm::WasmFile). +//! +//! ## Low level read API +//! +//! In addition to the unified read API, the various `read` modules define helpers that +//! operate on the raw structs. These also provide traits that abstract over the differences +//! between 32-bit and 64-bit versions of the file format. +//! +//! ## Unified write API +//! +//! [write::Object] allows building an object and then writing it out. + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![no_std] + +#[cfg(feature = "cargo-all")] +compile_error!("'--all-features' is not supported; use '--features all' instead"); + +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; + +#[cfg(feature = "std")] +#[allow(unused_imports)] +#[macro_use] +extern crate std; + +mod common; +pub use common::*; + +#[macro_use] +pub mod endian; +pub use endian::*; + +#[macro_use] +pub mod pod; +pub use pod::*; + +#[cfg(feature = "read_core")] +pub mod read; +#[cfg(feature = "read_core")] +pub use read::*; + +#[cfg(feature = "write_core")] +pub mod write; + +#[cfg(feature = "archive")] +pub mod archive; +#[cfg(feature = "elf")] +pub mod elf; +#[cfg(feature = "macho")] +pub mod macho; +#[cfg(any(feature = "coff", feature = "pe"))] +pub mod pe; diff --git a/vendor/object-0.20.0/src/macho.rs b/vendor/object/src/macho.rs similarity index 100% rename from vendor/object-0.20.0/src/macho.rs rename to vendor/object/src/macho.rs diff --git a/vendor/object-0.20.0/src/pe.rs b/vendor/object/src/pe.rs similarity index 99% rename from vendor/object-0.20.0/src/pe.rs rename to vendor/object/src/pe.rs index 170ddd9360..51b4ff5fec 100644 --- a/vendor/object-0.20.0/src/pe.rs +++ b/vendor/object/src/pe.rs @@ -936,7 +936,7 @@ pub struct ImageAuxSymbolTokenDef { pub const IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF: u16 = 1; -/// Auxilliary symbol format 1: function definitions. +/// Auxiliary symbol format 1: function definitions. // This struct has alignment 1. #[derive(Debug, Clone, Copy)] #[repr(C)] @@ -948,7 +948,7 @@ pub struct ImageAuxSymbolFunction { pub unused: [u8; 2], } -/// Auxilliary symbol format 2: .bf and .ef symbols. +/// Auxiliary symbol format 2: .bf and .ef symbols. // This struct has alignment 1. #[derive(Debug, Clone, Copy)] #[repr(C)] @@ -961,7 +961,7 @@ pub struct ImageAuxSymbolFunctionBeginEnd { pub unused3: [u8; 2], } -/// Auxilliary symbol format 3: weak externals. +/// Auxiliary symbol format 3: weak externals. /// /// Used for both `ImageSymbol` and `ImageSymbolEx` (both with padding). // This struct has alignment 1. @@ -973,7 +973,7 @@ pub struct ImageAuxSymbolWeak { pub weak_search_type: U32Bytes, } -/// Auxilliary symbol format 5: sections. +/// Auxiliary symbol format 5: sections. /// /// Used for both `ImageSymbol` and `ImageSymbolEx` (with padding). // This struct has alignment 1. @@ -1009,13 +1009,13 @@ pub struct ImageAuxSymbolCrc { // Communal selection types. // -pub const IMAGE_COMDAT_SELECT_NODUPLICATES: u16 = 1; -pub const IMAGE_COMDAT_SELECT_ANY: u16 = 2; -pub const IMAGE_COMDAT_SELECT_SAME_SIZE: u16 = 3; -pub const IMAGE_COMDAT_SELECT_EXACT_MATCH: u16 = 4; -pub const IMAGE_COMDAT_SELECT_ASSOCIATIVE: u16 = 5; -pub const IMAGE_COMDAT_SELECT_LARGEST: u16 = 6; -pub const IMAGE_COMDAT_SELECT_NEWEST: u16 = 7; +pub const IMAGE_COMDAT_SELECT_NODUPLICATES: u8 = 1; +pub const IMAGE_COMDAT_SELECT_ANY: u8 = 2; +pub const IMAGE_COMDAT_SELECT_SAME_SIZE: u8 = 3; +pub const IMAGE_COMDAT_SELECT_EXACT_MATCH: u8 = 4; +pub const IMAGE_COMDAT_SELECT_ASSOCIATIVE: u8 = 5; +pub const IMAGE_COMDAT_SELECT_LARGEST: u8 = 6; +pub const IMAGE_COMDAT_SELECT_NEWEST: u8 = 7; pub const IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY: u16 = 1; pub const IMAGE_WEAK_EXTERN_SEARCH_LIBRARY: u16 = 2; diff --git a/vendor/object-0.20.0/src/pod.rs b/vendor/object/src/pod.rs similarity index 93% rename from vendor/object-0.20.0/src/pod.rs rename to vendor/object/src/pod.rs index aa50ed8d9f..fc2e09530c 100644 --- a/vendor/object-0.20.0/src/pod.rs +++ b/vendor/object/src/pod.rs @@ -226,6 +226,21 @@ impl<'data> Bytes<'data> { } } +/// Trait for writable buffer. +pub trait WritableBuffer { + /// Returns position/offset for data to be written at. + fn len(&self) -> usize; + /// Returns true if buffer contains no data. + fn is_empty(&self) -> bool; + /// Reserves specified number of bytes in the buffer. + fn reserve(&mut self, additional: usize) -> Result<()>; + /// Resizes buffer to the specified length, fills new items + /// with the specified value. + fn resize(&mut self, new_len: usize, value: u8); + /// Extends buffer with the specified slice of bytes. + fn extend(&mut self, val: &[u8]); +} + /// A newtype for byte vectors. /// /// It provides convenience methods for `Pod` types. @@ -246,41 +261,49 @@ impl BytesMut { } #[inline] - pub fn len(&self) -> usize { - self.0.len() + pub fn write(&mut self, val: &T) { + self.0.extend_from_slice(bytes_of(val)) } #[inline] - pub fn is_empty(&self) -> bool { - self.0.is_empty() + pub fn write_at(&mut self, offset: usize, val: &T) -> Result<()> { + let src = bytes_of(val); + let dest = self.0.get_mut(offset..).ok_or(())?; + let dest = dest.get_mut(..src.len()).ok_or(())?; + dest.copy_from_slice(src); + Ok(()) } #[inline] - pub fn resize(&mut self, new_len: usize, value: u8) { - self.0.resize(new_len, value); + pub fn as_slice(&self) -> &[u8] { + self.0.as_slice() } +} +impl WritableBuffer for BytesMut { #[inline] - pub fn write(&mut self, val: &T) { - self.0.extend_from_slice(bytes_of(val)) + fn len(&self) -> usize { + self.0.len() } #[inline] - pub fn write_at(&mut self, offset: usize, val: &T) -> Result<()> { - let src = bytes_of(val); - let dest = self.0.get_mut(offset..).ok_or(())?; - let dest = dest.get_mut(..src.len()).ok_or(())?; - dest.copy_from_slice(src); + fn is_empty(&self) -> bool { + self.0.is_empty() + } + + #[inline] + fn reserve(&mut self, additional: usize) -> Result<()> { + self.0.reserve(additional); Ok(()) } #[inline] - pub fn write_bytes(&mut self, bytes: &BytesMut) { - self.0.extend_from_slice(&bytes.0) + fn resize(&mut self, new_len: usize, value: u8) { + self.0.resize(new_len, value); } #[inline] - pub fn extend(&mut self, val: &[u8]) { + fn extend(&mut self, val: &[u8]) { self.0.extend_from_slice(val) } } diff --git a/vendor/object-0.20.0/src/read/any.rs b/vendor/object/src/read/any.rs similarity index 66% rename from vendor/object-0.20.0/src/read/any.rs rename to vendor/object/src/read/any.rs index fe8ed969ac..72945eb21f 100644 --- a/vendor/object-0.20.0/src/read/any.rs +++ b/vendor/object/src/read/any.rs @@ -11,9 +11,10 @@ use crate::read::pe; #[cfg(feature = "wasm")] use crate::read::wasm; use crate::read::{ - self, Architecture, BinaryFormat, CompressedData, Error, FileFlags, Object, ObjectSection, - ObjectSegment, Relocation, Result, SectionFlags, SectionIndex, SectionKind, Symbol, - SymbolIndex, SymbolMap, + self, Architecture, BinaryFormat, ComdatKind, CompressedData, Error, FileFlags, Object, + ObjectComdat, ObjectMap, ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, + Relocation, Result, SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, + SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection, }; /// Evaluate an expression on the contents of a file format enum. @@ -243,7 +244,11 @@ where type SegmentIterator = SegmentIterator<'data, 'file>; type Section = Section<'data, 'file>; type SectionIterator = SectionIterator<'data, 'file>; + type Comdat = Comdat<'data, 'file>; + type ComdatIterator = ComdatIterator<'data, 'file>; + type Symbol = Symbol<'data, 'file>; type SymbolIterator = SymbolIterator<'data, 'file>; + type SymbolTable = SymbolTable<'data, 'file>; fn architecture(&self) -> Architecture { with_inner!(self.inner, FileInternal, |x| x.architecture()) @@ -283,8 +288,17 @@ where } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - with_inner!(self.inner, FileInternal, |x| x.symbol_by_index(index)) + fn comdats(&'file self) -> ComdatIterator<'data, 'file> { + ComdatIterator { + inner: map_inner!(self.inner, FileInternal, ComdatIteratorInternal, |x| x + .comdats()), + } + } + + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + map_inner_option!(self.inner, FileInternal, SymbolInternal, |x| x + .symbol_by_index(index)) + .map(|inner| Symbol { inner }) } fn symbols(&'file self) -> SymbolIterator<'data, 'file> { @@ -294,6 +308,12 @@ where } } + fn symbol_table(&'file self) -> Option> { + map_inner_option!(self.inner, FileInternal, SymbolTableInternal, |x| x + .symbol_table()) + .map(|inner| SymbolTable { inner }) + } + fn dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file> { SymbolIterator { inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x @@ -301,10 +321,20 @@ where } } - fn symbol_map(&self) -> SymbolMap<'data> { + fn dynamic_symbol_table(&'file self) -> Option> { + map_inner_option!(self.inner, FileInternal, SymbolTableInternal, |x| x + .dynamic_symbol_table()) + .map(|inner| SymbolTable { inner }) + } + + fn symbol_map(&self) -> SymbolMap> { with_inner!(self.inner, FileInternal, |x| x.symbol_map()) } + fn object_map(&self) -> ObjectMap<'data> { + with_inner!(self.inner, FileInternal, |x| x.object_map()) + } + fn has_debug_symbols(&self) -> bool { with_inner!(self.inner, FileInternal, |x| x.has_debug_symbols()) } @@ -544,7 +574,9 @@ impl<'data, 'file> fmt::Debug for Section<'data, 'file> { s.field("name", &self.name().unwrap_or("")) .field("address", &self.address()) .field("size", &self.size()) + .field("align", &self.align()) .field("kind", &self.kind()) + .field("flags", &self.flags()) .finish() } } @@ -614,6 +646,212 @@ impl<'data, 'file> ObjectSection<'data> for Section<'data, 'file> { } } +/// An iterator of the COMDAT section groups of a `File`. +#[derive(Debug)] +pub struct ComdatIterator<'data, 'file> +where + 'data: 'file, +{ + inner: ComdatIteratorInternal<'data, 'file>, +} + +#[derive(Debug)] +enum ComdatIteratorInternal<'data, 'file> +where + 'data: 'file, +{ + #[cfg(feature = "coff")] + Coff(coff::CoffComdatIterator<'data, 'file>), + #[cfg(feature = "elf")] + Elf32(elf::ElfComdatIterator32<'data, 'file>), + #[cfg(feature = "elf")] + Elf64(elf::ElfComdatIterator64<'data, 'file>), + #[cfg(feature = "macho")] + MachO32(macho::MachOComdatIterator32<'data, 'file>), + #[cfg(feature = "macho")] + MachO64(macho::MachOComdatIterator64<'data, 'file>), + #[cfg(feature = "pe")] + Pe32(pe::PeComdatIterator32<'data, 'file>), + #[cfg(feature = "pe")] + Pe64(pe::PeComdatIterator64<'data, 'file>), + #[cfg(feature = "wasm")] + Wasm(wasm::WasmComdatIterator<'data, 'file>), +} + +impl<'data, 'file> Iterator for ComdatIterator<'data, 'file> { + type Item = Comdat<'data, 'file>; + + fn next(&mut self) -> Option { + next_inner!(self.inner, ComdatIteratorInternal, ComdatInternal) + .map(|inner| Comdat { inner }) + } +} + +/// A COMDAT section group of a `File`. +pub struct Comdat<'data, 'file> +where + 'data: 'file, +{ + inner: ComdatInternal<'data, 'file>, +} + +enum ComdatInternal<'data, 'file> +where + 'data: 'file, +{ + #[cfg(feature = "coff")] + Coff(coff::CoffComdat<'data, 'file>), + #[cfg(feature = "elf")] + Elf32(elf::ElfComdat32<'data, 'file>), + #[cfg(feature = "elf")] + Elf64(elf::ElfComdat64<'data, 'file>), + #[cfg(feature = "macho")] + MachO32(macho::MachOComdat32<'data, 'file>), + #[cfg(feature = "macho")] + MachO64(macho::MachOComdat64<'data, 'file>), + #[cfg(feature = "pe")] + Pe32(pe::PeComdat32<'data, 'file>), + #[cfg(feature = "pe")] + Pe64(pe::PeComdat64<'data, 'file>), + #[cfg(feature = "wasm")] + Wasm(wasm::WasmComdat<'data, 'file>), +} + +impl<'data, 'file> fmt::Debug for Comdat<'data, 'file> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut s = f.debug_struct("Comdat"); + s.field("symbol", &self.symbol()) + .field("name", &self.name().unwrap_or("")) + .field("kind", &self.kind()) + .finish() + } +} + +impl<'data, 'file> read::private::Sealed for Comdat<'data, 'file> {} + +impl<'data, 'file> ObjectComdat<'data> for Comdat<'data, 'file> { + type SectionIterator = ComdatSectionIterator<'data, 'file>; + + fn kind(&self) -> ComdatKind { + with_inner!(self.inner, ComdatInternal, |x| x.kind()) + } + + fn symbol(&self) -> SymbolIndex { + with_inner!(self.inner, ComdatInternal, |x| x.symbol()) + } + + fn name(&self) -> Result<&str> { + with_inner!(self.inner, ComdatInternal, |x| x.name()) + } + + fn sections(&self) -> ComdatSectionIterator<'data, 'file> { + ComdatSectionIterator { + inner: map_inner!( + self.inner, + ComdatInternal, + ComdatSectionIteratorInternal, + |x| x.sections() + ), + } + } +} + +/// An iterator over COMDAT section entries. +#[derive(Debug)] +pub struct ComdatSectionIterator<'data, 'file> +where + 'data: 'file, +{ + inner: ComdatSectionIteratorInternal<'data, 'file>, +} + +#[derive(Debug)] +enum ComdatSectionIteratorInternal<'data, 'file> +where + 'data: 'file, +{ + #[cfg(feature = "coff")] + Coff(coff::CoffComdatSectionIterator<'data, 'file>), + #[cfg(feature = "elf")] + Elf32(elf::ElfComdatSectionIterator32<'data, 'file>), + #[cfg(feature = "elf")] + Elf64(elf::ElfComdatSectionIterator64<'data, 'file>), + #[cfg(feature = "macho")] + MachO32(macho::MachOComdatSectionIterator32<'data, 'file>), + #[cfg(feature = "macho")] + MachO64(macho::MachOComdatSectionIterator64<'data, 'file>), + #[cfg(feature = "pe")] + Pe32(pe::PeComdatSectionIterator32<'data, 'file>), + #[cfg(feature = "pe")] + Pe64(pe::PeComdatSectionIterator64<'data, 'file>), + #[cfg(feature = "wasm")] + Wasm(wasm::WasmComdatSectionIterator<'data, 'file>), +} + +impl<'data, 'file> Iterator for ComdatSectionIterator<'data, 'file> { + type Item = SectionIndex; + + fn next(&mut self) -> Option { + with_inner_mut!(self.inner, ComdatSectionIteratorInternal, |x| x.next()) + } +} + +/// A symbol table. +#[derive(Debug)] +pub struct SymbolTable<'data, 'file> +where + 'data: 'file, +{ + inner: SymbolTableInternal<'data, 'file>, +} + +#[derive(Debug)] +enum SymbolTableInternal<'data, 'file> +where + 'data: 'file, +{ + #[cfg(feature = "coff")] + Coff(coff::CoffSymbolTable<'data, 'file>), + #[cfg(feature = "elf")] + Elf32(elf::ElfSymbolTable32<'data, 'file>), + #[cfg(feature = "elf")] + Elf64(elf::ElfSymbolTable64<'data, 'file>), + #[cfg(feature = "macho")] + MachO32(macho::MachOSymbolTable32<'data, 'file>), + #[cfg(feature = "macho")] + MachO64(macho::MachOSymbolTable64<'data, 'file>), + #[cfg(feature = "pe")] + Pe32(coff::CoffSymbolTable<'data, 'file>), + #[cfg(feature = "pe")] + Pe64(coff::CoffSymbolTable<'data, 'file>), + #[cfg(feature = "wasm")] + Wasm(wasm::WasmSymbolTable<'data, 'file>), +} + +impl<'data, 'file> read::private::Sealed for SymbolTable<'data, 'file> {} + +impl<'data, 'file> ObjectSymbolTable<'data> for SymbolTable<'data, 'file> { + type Symbol = Symbol<'data, 'file>; + type SymbolIterator = SymbolIterator<'data, 'file>; + + fn symbols(&self) -> Self::SymbolIterator { + SymbolIterator { + inner: map_inner!( + self.inner, + SymbolTableInternal, + SymbolIteratorInternal, + |x| x.symbols() + ), + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + map_inner_option!(self.inner, SymbolTableInternal, SymbolInternal, |x| x + .symbol_by_index(index)) + .map(|inner| Symbol { inner }) + } +} + /// An iterator over symbol table entries. #[derive(Debug)] pub struct SymbolIterator<'data, 'file> @@ -647,10 +885,116 @@ where } impl<'data, 'file> Iterator for SymbolIterator<'data, 'file> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = Symbol<'data, 'file>; fn next(&mut self) -> Option { - with_inner_mut!(self.inner, SymbolIteratorInternal, |x| x.next()) + next_inner!(self.inner, SymbolIteratorInternal, SymbolInternal) + .map(|inner| Symbol { inner }) + } +} + +/// A symbol table entry. +pub struct Symbol<'data, 'file> +where + 'data: 'file, +{ + inner: SymbolInternal<'data, 'file>, +} + +enum SymbolInternal<'data, 'file> +where + 'data: 'file, +{ + #[cfg(feature = "coff")] + Coff(coff::CoffSymbol<'data, 'file>), + #[cfg(feature = "elf")] + Elf32(elf::ElfSymbol32<'data, 'file>), + #[cfg(feature = "elf")] + Elf64(elf::ElfSymbol64<'data, 'file>), + #[cfg(feature = "macho")] + MachO32(macho::MachOSymbol32<'data, 'file>), + #[cfg(feature = "macho")] + MachO64(macho::MachOSymbol64<'data, 'file>), + #[cfg(feature = "pe")] + Pe32(coff::CoffSymbol<'data, 'file>), + #[cfg(feature = "pe")] + Pe64(coff::CoffSymbol<'data, 'file>), + #[cfg(feature = "wasm")] + Wasm(wasm::WasmSymbol<'data, 'file>), +} + +impl<'data, 'file> fmt::Debug for Symbol<'data, 'file> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Symbol") + .field("name", &self.name().unwrap_or("")) + .field("address", &self.address()) + .field("size", &self.size()) + .field("kind", &self.kind()) + .field("section", &self.section()) + .field("scope", &self.scope()) + .field("weak", &self.is_weak()) + .field("flags", &self.flags()) + .finish() + } +} + +impl<'data, 'file> read::private::Sealed for Symbol<'data, 'file> {} + +impl<'data, 'file> ObjectSymbol<'data> for Symbol<'data, 'file> { + fn index(&self) -> SymbolIndex { + with_inner!(self.inner, SymbolInternal, |x| x.index()) + } + + fn name(&self) -> Result<&'data str> { + with_inner!(self.inner, SymbolInternal, |x| x.name()) + } + + fn address(&self) -> u64 { + with_inner!(self.inner, SymbolInternal, |x| x.address()) + } + + fn size(&self) -> u64 { + with_inner!(self.inner, SymbolInternal, |x| x.size()) + } + + fn kind(&self) -> SymbolKind { + with_inner!(self.inner, SymbolInternal, |x| x.kind()) + } + + fn section(&self) -> SymbolSection { + with_inner!(self.inner, SymbolInternal, |x| x.section()) + } + + fn is_undefined(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_undefined()) + } + + fn is_definition(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_definition()) + } + + fn is_common(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_common()) + } + + fn is_weak(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_weak()) + } + + fn scope(&self) -> SymbolScope { + with_inner!(self.inner, SymbolInternal, |x| x.scope()) + } + + fn is_global(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_global()) + } + + fn is_local(&self) -> bool { + with_inner!(self.inner, SymbolInternal, |x| x.is_local()) + } + + fn flags(&self) -> SymbolFlags { + with_inner!(self.inner, SymbolInternal, |x| x.flags()) } } diff --git a/vendor/object/src/read/archive.rs b/vendor/object/src/read/archive.rs new file mode 100644 index 0000000000..b10d2bf76f --- /dev/null +++ b/vendor/object/src/read/archive.rs @@ -0,0 +1,407 @@ +//! Support for archive files. + +use crate::read::{self, Error, ReadError}; +use crate::{archive, Bytes}; + +/// The kind of archive format. +// TODO: Gnu64 and Darwin64 (and Darwin for writing) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ArchiveKind { + /// There are no special files that indicate the archive format. + Unknown, + /// The GNU (or System V) archive format. + Gnu, + /// The BSD archive format. + Bsd, + /// The Windows COFF archive format. + Coff, +} + +/// A partially parsed archive file. +#[derive(Debug)] +pub struct ArchiveFile<'data> { + data: Bytes<'data>, + kind: ArchiveKind, + symbols: Bytes<'data>, + names: Bytes<'data>, +} + +impl<'data> ArchiveFile<'data> { + /// Parse the archive header and special members. + pub fn parse(data: &'data [u8]) -> read::Result { + let data = Bytes(data); + let mut tail = data; + + let magic = tail + .read_bytes(archive::MAGIC.len()) + .read_error("Invalid archive size")?; + if magic.0 != &archive::MAGIC[..] { + return Err(Error("Unsupported archive identifier")); + } + + let mut file = ArchiveFile { + data: tail, + kind: ArchiveKind::Unknown, + symbols: Bytes(&[]), + names: Bytes(&[]), + }; + + // The first few members may be special, so parse them. + // GNU has: + // - "/": symbol table (optional) + // - "//": names table (optional) + // COFF has: + // - "/": first linker member + // - "/": second linker member + // - "//": names table + // BSD has: + // - "__.SYMDEF" or "__.SYMDEF SORTED": symbol table (optional) + if !tail.is_empty() { + let member = ArchiveMember::parse(&mut tail, Bytes(&[]))?; + if member.name == b"/" { + // GNU symbol table (unless we later determine this is COFF). + file.kind = ArchiveKind::Gnu; + file.symbols = member.data; + file.data = tail; + + if !tail.is_empty() { + let member = ArchiveMember::parse(&mut tail, Bytes(&[]))?; + if member.name == b"/" { + // COFF linker member. + file.kind = ArchiveKind::Coff; + file.symbols = member.data; + file.data = tail; + + if !tail.is_empty() { + let member = ArchiveMember::parse(&mut tail, Bytes(&[]))?; + if member.name == b"//" { + // COFF names table. + file.names = member.data; + file.data = tail; + } + } + } else if member.name == b"//" { + // GNU names table. + file.names = member.data; + file.data = tail; + } + } + } else if member.name == b"//" { + // GNU names table. + file.kind = ArchiveKind::Gnu; + file.names = member.data; + file.data = tail; + } else if member.name == b"__.SYMDEF" || member.name == b"__.SYMDEF SORTED" { + // BSD symbol table. + file.kind = ArchiveKind::Bsd; + file.symbols = member.data; + file.data = tail; + } else { + // TODO: This could still be a BSD file. We leave this as unknown for now. + } + } + Ok(file) + } + + /// Return the archive format. + #[inline] + pub fn kind(&self) -> ArchiveKind { + self.kind + } + + /// Iterate over the members of the archive. + /// + /// This does not return special members. + #[inline] + pub fn members(&self) -> ArchiveMemberIterator<'data> { + ArchiveMemberIterator { + data: self.data, + names: self.names, + } + } +} + +/// An iterator over the members of an archive. +#[derive(Debug)] +pub struct ArchiveMemberIterator<'data> { + data: Bytes<'data>, + names: Bytes<'data>, +} + +impl<'data> Iterator for ArchiveMemberIterator<'data> { + type Item = read::Result>; + + fn next(&mut self) -> Option { + if self.data.is_empty() { + return None; + } + let member = ArchiveMember::parse(&mut self.data, self.names); + if member.is_err() { + self.data = Bytes(&[]); + } + Some(member) + } +} + +/// A partially parsed archive member. +#[derive(Debug)] +pub struct ArchiveMember<'data> { + header: &'data archive::Header, + name: &'data [u8], + data: Bytes<'data>, +} + +impl<'data> ArchiveMember<'data> { + /// Parse the archive member header, name, and file data. + /// + /// This reads the extended name (if any) and adjusts the file size. + fn parse(data: &mut Bytes<'data>, names: Bytes<'data>) -> read::Result { + let header = data + .read::() + .read_error("Invalid archive member header")?; + if header.terminator != archive::TERMINATOR { + return Err(Error("Invalid archive terminator")); + } + + let size = + parse_usize_digits(&header.size, 10).read_error("Invalid archive member size")?; + let mut file_data = data + .read_bytes(size) + .read_error("Archive member size is too large")?; + // Entries are padded to an even number of bytes. + if (size & 1) != 0 { + data.skip(1).ok(); + } + + let name = if header.name[0] == b'/' && (header.name[1] as char).is_digit(10) { + // Read file name from the names table. + parse_sysv_extended_name(&header.name[1..], names) + .read_error("Invalid archive extended name offset")? + } else if &header.name[..3] == b"#1/" && (header.name[3] as char).is_digit(10) { + // Read file name from the start of the file data. + parse_bsd_extended_name(&header.name[3..], &mut file_data) + .read_error("Invalid archive extended name length")? + } else if header.name[0] == b'/' { + let name_len = + (header.name.iter().position(|&x| x == b' ')).unwrap_or_else(|| header.name.len()); + &header.name[..name_len] + } else { + let name_len = (header.name.iter().position(|&x| x == b'/')) + .or_else(|| header.name.iter().position(|&x| x == b' ')) + .unwrap_or_else(|| header.name.len()); + &header.name[..name_len] + }; + + Ok(ArchiveMember { + header, + name, + data: file_data, + }) + } + + /// Return the raw header. + #[inline] + pub fn header(&self) -> &'data archive::Header { + self.header + } + + /// Return the parsed file name. + /// + /// This may be an extended file name. + #[inline] + pub fn name(&self) -> &'data [u8] { + self.name + } + + /// Parse the file modification timestamp from the header. + #[inline] + pub fn date(&self) -> Option { + parse_usize_digits(&self.header.date, 10) + } + + /// Parse the user ID from the header. + #[inline] + pub fn uid(&self) -> Option { + parse_usize_digits(&self.header.uid, 10) + } + + /// Parse the group ID from the header. + #[inline] + pub fn gid(&self) -> Option { + parse_usize_digits(&self.header.gid, 10) + } + + /// Parse the file mode from the header. + #[inline] + pub fn mode(&self) -> Option { + parse_usize_digits(&self.header.mode, 8) + } + + /// Return the file data. + #[inline] + pub fn data(&self) -> &'data [u8] { + self.data.0 + } +} + +// Ignores bytes starting from the first space. +fn parse_usize_digits(digits: &[u8], radix: u32) -> Option { + let len = digits + .iter() + .position(|&x| x == b' ') + .unwrap_or_else(|| digits.len()); + let digits = &digits[..len]; + if digits.is_empty() { + return None; + } + let mut result: usize = 0; + for &c in digits { + let x = (c as char).to_digit(radix)?; + result = result + .checked_mul(radix as usize)? + .checked_add(x as usize)?; + } + Some(result) +} + +fn parse_sysv_extended_name<'data>( + digits: &[u8], + mut names: Bytes<'data>, +) -> Result<&'data [u8], ()> { + let offset = parse_usize_digits(digits, 10).ok_or(())?; + names.skip(offset)?; + let name = match names.0.iter().position(|&x| x == b'/' || x == 0) { + Some(len) => names.read_bytes(len)?, + None => names, + }; + Ok(name.0) +} + +/// Modifies `data` to start after the extended name. +fn parse_bsd_extended_name<'data>( + digits: &[u8], + data: &mut Bytes<'data>, +) -> Result<&'data [u8], ()> { + let len = parse_usize_digits(digits, 10).ok_or(())?; + let mut name_data = data.read_bytes(len)?; + let name = match name_data.0.iter().position(|&x| x == 0) { + Some(len) => name_data.read_bytes(len)?, + None => name_data, + }; + Ok(name.0) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn kind() { + let data = b"!\n"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Unknown); + + let data = b"\ + !\n\ + / 4 `\n\ + 0000"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Gnu); + + let data = b"\ + !\n\ + // 4 `\n\ + 0000"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Gnu); + + let data = b"\ + !\n\ + / 4 `\n\ + 0000\ + // 4 `\n\ + 0000"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Gnu); + + let data = b"\ + !\n\ + __.SYMDEF 4 `\n\ + 0000"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Bsd); + + let data = b"\ + !\n\ + #1/9 13 `\n\ + __.SYMDEF0000"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Bsd); + + let data = b"\ + !\n\ + #1/16 20 `\n\ + __.SYMDEF SORTED0000"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Bsd); + + let data = b"\ + !\n\ + / 4 `\n\ + 0000\ + / 4 `\n\ + 0000\ + // 4 `\n\ + 0000"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Coff); + } + + #[test] + fn gnu_names() { + let data = b"\ + !\n\ + // 18 `\n\ + 0123456789abcdef/\n\ + 0123456789abcde/0 0 0 644 3 `\n\ + odd\n\ + /0 0 0 0 644 4 `\n\ + even"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Gnu); + let mut members = archive.members(); + + let member = members.next().unwrap().unwrap(); + assert_eq!(member.name(), b"0123456789abcde"); + assert_eq!(member.data(), b"odd"); + + let member = members.next().unwrap().unwrap(); + assert_eq!(member.name(), b"0123456789abcdef"); + assert_eq!(member.data(), b"even"); + + assert!(members.next().is_none()); + } + + #[test] + fn bsd_names() { + let data = b"\ + !\n\ + 0123456789abcde 0 0 0 644 3 `\n\ + odd\n\ + #1/16 0 0 0 644 20 `\n\ + 0123456789abcdefeven"; + let archive = ArchiveFile::parse(data).unwrap(); + assert_eq!(archive.kind(), ArchiveKind::Unknown); + let mut members = archive.members(); + + let member = members.next().unwrap().unwrap(); + assert_eq!(member.name(), b"0123456789abcde"); + assert_eq!(member.data(), b"odd"); + + let member = members.next().unwrap().unwrap(); + assert_eq!(member.name(), b"0123456789abcdef"); + assert_eq!(member.data(), b"even"); + + assert!(members.next().is_none()); + } +} diff --git a/vendor/object/src/read/coff/comdat.rs b/vendor/object/src/read/coff/comdat.rs new file mode 100644 index 0000000000..46dad0a090 --- /dev/null +++ b/vendor/object/src/read/coff/comdat.rs @@ -0,0 +1,200 @@ +use core::str; + +use crate::endian::LittleEndian as LE; +use crate::pe; +use crate::read::{self, ComdatKind, ObjectComdat, ReadError, Result, SectionIndex, SymbolIndex}; + +use super::CoffFile; + +/// An iterator over the COMDAT section groups of a `CoffFile`. +#[derive(Debug)] +pub struct CoffComdatIterator<'data, 'file> +where + 'data: 'file, +{ + pub(super) file: &'file CoffFile<'data>, + pub(super) index: usize, +} + +impl<'data, 'file> Iterator for CoffComdatIterator<'data, 'file> { + type Item = CoffComdat<'data, 'file>; + + fn next(&mut self) -> Option { + loop { + let index = self.index; + let symbol = self + .file + .common + .symbols + .get::(index) + .ok()?; + self.index += 1 + symbol.number_of_aux_symbols as usize; + if let Some(comdat) = CoffComdat::parse(self.file, symbol, index) { + return Some(comdat); + } + } + } +} + +/// A COMDAT section group of a `CoffFile`. +#[derive(Debug)] +pub struct CoffComdat<'data, 'file> +where + 'data: 'file, +{ + file: &'file CoffFile<'data>, + symbol_index: SymbolIndex, + symbol: &'data pe::ImageSymbol, + selection: u8, +} + +impl<'data, 'file> CoffComdat<'data, 'file> { + fn parse( + file: &'file CoffFile<'data>, + section_symbol: &'data pe::ImageSymbol, + index: usize, + ) -> Option> { + // Must be a section symbol. + if section_symbol.value.get(LE) != 0 + || section_symbol.base_type() != pe::IMAGE_SYM_TYPE_NULL + || section_symbol.storage_class != pe::IMAGE_SYM_CLASS_STATIC + || section_symbol.number_of_aux_symbols == 0 + { + return None; + } + + // Auxiliary record must have a non-associative selection. + let aux = file + .common + .symbols + .get::(index + 1) + .ok()?; + let selection = aux.selection; + if selection == 0 || selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { + return None; + } + + // Find the COMDAT symbol. + let mut symbol_index = index; + let mut symbol = section_symbol; + let section_number = section_symbol.section_number.get(LE); + loop { + symbol_index += 1 + symbol.number_of_aux_symbols as usize; + symbol = file + .common + .symbols + .get::(symbol_index) + .ok()?; + if section_number == symbol.section_number.get(LE) { + break; + } + } + + Some(CoffComdat { + file, + symbol_index: SymbolIndex(symbol_index), + symbol, + selection, + }) + } +} + +impl<'data, 'file> read::private::Sealed for CoffComdat<'data, 'file> {} + +impl<'data, 'file> ObjectComdat<'data> for CoffComdat<'data, 'file> { + type SectionIterator = CoffComdatSectionIterator<'data, 'file>; + + #[inline] + fn kind(&self) -> ComdatKind { + match self.selection { + pe::IMAGE_COMDAT_SELECT_NODUPLICATES => ComdatKind::NoDuplicates, + pe::IMAGE_COMDAT_SELECT_ANY => ComdatKind::Any, + pe::IMAGE_COMDAT_SELECT_SAME_SIZE => ComdatKind::SameSize, + pe::IMAGE_COMDAT_SELECT_EXACT_MATCH => ComdatKind::ExactMatch, + pe::IMAGE_COMDAT_SELECT_LARGEST => ComdatKind::Largest, + pe::IMAGE_COMDAT_SELECT_NEWEST => ComdatKind::Newest, + _ => ComdatKind::Unknown, + } + } + + #[inline] + fn symbol(&self) -> SymbolIndex { + self.symbol_index + } + + #[inline] + fn name(&self) -> Result<&str> { + // Find the name of first symbol referring to the section. + let name = self.symbol.name(self.file.common.symbols.strings())?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 COFF COMDAT name") + } + + #[inline] + fn sections(&self) -> Self::SectionIterator { + CoffComdatSectionIterator { + file: self.file, + section_number: self.symbol.section_number.get(LE), + index: 0, + } + } +} + +/// An iterator over the sections in a COMDAT section group of a `CoffFile`. +#[derive(Debug)] +pub struct CoffComdatSectionIterator<'data, 'file> +where + 'data: 'file, +{ + file: &'file CoffFile<'data>, + section_number: u16, + index: usize, +} + +impl<'data, 'file> Iterator for CoffComdatSectionIterator<'data, 'file> { + type Item = SectionIndex; + + fn next(&mut self) -> Option { + // Find associated COMDAT symbols. + // TODO: it seems gcc doesn't use associated symbols for this + loop { + let index = self.index; + let symbol = self + .file + .common + .symbols + .get::(index) + .ok()?; + self.index += 1 + symbol.number_of_aux_symbols as usize; + + // Must be a section symbol. + if symbol.value.get(LE) != 0 + || symbol.base_type() != pe::IMAGE_SYM_TYPE_NULL + || symbol.storage_class != pe::IMAGE_SYM_CLASS_STATIC + || symbol.number_of_aux_symbols == 0 + { + continue; + } + + let section_number = symbol.section_number.get(LE); + + let aux = self + .file + .common + .symbols + .get::(index + 1) + .ok()?; + if aux.selection == pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE { + // TODO: use high_number for bigobj + if aux.number.get(LE) == self.section_number { + return Some(SectionIndex(section_number as usize)); + } + } else if aux.selection != 0 { + if section_number == self.section_number { + return Some(SectionIndex(section_number as usize)); + } + } + } + } +} diff --git a/vendor/object-0.20.0/src/read/coff/file.rs b/vendor/object/src/read/coff/file.rs similarity index 70% rename from vendor/object-0.20.0/src/read/coff/file.rs rename to vendor/object/src/read/coff/file.rs index 6046e6937e..31a48d7fe2 100644 --- a/vendor/object-0.20.0/src/read/coff/file.rs +++ b/vendor/object/src/read/coff/file.rs @@ -1,24 +1,31 @@ -use alloc::vec::Vec; use core::str; use crate::read::{ - self, Architecture, FileFlags, Object, ObjectSection, ReadError, Result, SectionIndex, Symbol, - SymbolIndex, SymbolMap, + self, Architecture, FileFlags, Object, ObjectSection, ReadError, Result, SectionIndex, + SymbolIndex, }; use crate::{pe, Bytes, LittleEndian as LE}; use super::{ - parse_symbol, CoffSection, CoffSectionIterator, CoffSegment, CoffSegmentIterator, - CoffSymbolIterator, SectionTable, SymbolTable, + CoffComdat, CoffComdatIterator, CoffSection, CoffSectionIterator, CoffSegment, + CoffSegmentIterator, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SectionTable, + SymbolTable, }; +/// The common parts of `PeFile` and `CoffFile`. +#[derive(Debug)] +pub(crate) struct CoffCommon<'data> { + pub(crate) sections: SectionTable<'data>, + // TODO: ImageSymbolExBytes + pub(crate) symbols: SymbolTable<'data>, + pub(crate) image_base: u64, +} + /// A COFF object file. #[derive(Debug)] pub struct CoffFile<'data> { pub(super) header: &'data pe::ImageFileHeader, - pub(super) sections: SectionTable<'data>, - // TODO: ImageSymbolExBytes - pub(super) symbols: SymbolTable<'data>, + pub(super) common: CoffCommon<'data>, pub(super) data: Bytes<'data>, } @@ -32,8 +39,11 @@ impl<'data> CoffFile<'data> { Ok(CoffFile { header, - sections, - symbols, + common: CoffCommon { + sections, + symbols, + image_base: 0, + }, data, }) } @@ -49,7 +59,11 @@ where type SegmentIterator = CoffSegmentIterator<'data, 'file>; type Section = CoffSection<'data, 'file>; type SectionIterator = CoffSectionIterator<'data, 'file>; + type Comdat = CoffComdat<'data, 'file>; + type ComdatIterator = CoffComdatIterator<'data, 'file>; + type Symbol = CoffSymbol<'data, 'file>; type SymbolIterator = CoffSymbolIterator<'data, 'file>; + type SymbolTable = CoffSymbolTable<'data, 'file>; fn architecture(&self) -> Architecture { match self.header.machine.get(LE) { @@ -73,7 +87,7 @@ where fn segments(&'file self) -> CoffSegmentIterator<'data, 'file> { CoffSegmentIterator { file: self, - iter: self.sections.iter(), + iter: self.common.sections.iter(), } } @@ -83,7 +97,7 @@ where } fn section_by_index(&'file self, index: SectionIndex) -> Result> { - let section = self.sections.section(index.0)?; + let section = self.common.sections.section(index.0)?; Ok(CoffSection { file: self, index, @@ -94,42 +108,49 @@ where fn sections(&'file self) -> CoffSectionIterator<'data, 'file> { CoffSectionIterator { file: self, - iter: self.sections.iter().enumerate(), + iter: self.common.sections.iter().enumerate(), + } + } + + fn comdats(&'file self) -> CoffComdatIterator<'data, 'file> { + CoffComdatIterator { + file: self, + index: 0, } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let symbol = self - .symbols - .get(index.0) - .read_error("Invalid COFF symbol index")?; - Ok(parse_symbol(&self.symbols, index.0, symbol)) + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + let symbol = self.common.symbols.symbol(index.0)?; + Ok(CoffSymbol { + file: &self.common, + index, + symbol, + }) } fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, index: 0, } } + #[inline] + fn symbol_table(&'file self) -> Option> { + Some(CoffSymbolTable { file: &self.common }) + } + fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, // Hack: don't return any. - index: self.symbols.len(), + index: self.common.symbols.len(), } } - fn symbol_map(&self) -> SymbolMap<'data> { - // TODO: untested - let mut symbols: Vec<_> = self - .symbols() - .map(|(_, s)| s) - .filter(SymbolMap::filter) - .collect(); - symbols.sort_by_key(|x| x.address); - SymbolMap { symbols } + #[inline] + fn dynamic_symbol_table(&'file self) -> Option> { + None } fn has_debug_symbols(&self) -> bool { diff --git a/vendor/object-0.20.0/src/read/coff/mod.rs b/vendor/object/src/read/coff/mod.rs similarity index 89% rename from vendor/object-0.20.0/src/read/coff/mod.rs rename to vendor/object/src/read/coff/mod.rs index 33b256a3f4..d5b3caf32a 100644 --- a/vendor/object-0.20.0/src/read/coff/mod.rs +++ b/vendor/object/src/read/coff/mod.rs @@ -13,3 +13,6 @@ pub use symbol::*; mod relocation; pub use relocation::*; + +mod comdat; +pub use comdat::*; diff --git a/vendor/object-0.20.0/src/read/coff/relocation.rs b/vendor/object/src/read/coff/relocation.rs similarity index 100% rename from vendor/object-0.20.0/src/read/coff/relocation.rs rename to vendor/object/src/read/coff/relocation.rs diff --git a/vendor/object-0.20.0/src/read/coff/section.rs b/vendor/object/src/read/coff/section.rs similarity index 98% rename from vendor/object-0.20.0/src/read/coff/section.rs rename to vendor/object/src/read/coff/section.rs index 8996828717..bd1c0e3893 100644 --- a/vendor/object-0.20.0/src/read/coff/section.rs +++ b/vendor/object/src/read/coff/section.rs @@ -153,7 +153,7 @@ impl<'data, 'file> ObjectSegment<'data> for CoffSegment<'data, 'file> { #[inline] fn name(&self) -> Result> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; Ok(Some( str::from_utf8(name) .ok() @@ -178,7 +178,7 @@ impl<'data, 'file> Iterator for CoffSectionIterator<'data, 'file> { fn next(&mut self) -> Option { self.iter.next().map(|(index, section)| CoffSection { file: self.file, - index: SectionIndex(index), + index: SectionIndex(index + 1), section, }) } @@ -255,7 +255,7 @@ impl<'data, 'file> ObjectSection<'data> for CoffSection<'data, 'file> { #[inline] fn name(&self) -> Result<&str> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; str::from_utf8(name) .ok() .read_error("Non UTF-8 COFF section name") diff --git a/vendor/object/src/read/coff/symbol.rs b/vendor/object/src/read/coff/symbol.rs new file mode 100644 index 0000000000..486021322e --- /dev/null +++ b/vendor/object/src/read/coff/symbol.rs @@ -0,0 +1,451 @@ +use alloc::fmt; +use alloc::vec::Vec; +use core::convert::TryInto; +use core::str; + +use super::{CoffCommon, SectionTable}; +use crate::endian::{LittleEndian as LE, U32Bytes}; +use crate::pe; +use crate::pod::{Bytes, Pod}; +use crate::read::util::StringTable; +use crate::read::{ + self, ObjectSymbol, ObjectSymbolTable, ReadError, Result, SectionIndex, SymbolFlags, + SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection, +}; + +/// A table of symbol entries in a COFF or PE file. +/// +/// Also includes the string table used for the symbol names. +#[derive(Debug)] +pub struct SymbolTable<'data> { + symbols: &'data [pe::ImageSymbolBytes], + strings: StringTable<'data>, +} + +impl<'data> SymbolTable<'data> { + /// Read the symbol table. + pub fn parse(header: &pe::ImageFileHeader, mut data: Bytes<'data>) -> Result { + // The symbol table may not be present. + let symbol_offset = header.pointer_to_symbol_table.get(LE) as usize; + let (symbols, strings) = if symbol_offset != 0 { + data.skip(symbol_offset) + .read_error("Invalid COFF symbol table offset")?; + let symbols = data + .read_slice(header.number_of_symbols.get(LE) as usize) + .read_error("Invalid COFF symbol table size")?; + + // Note: don't update data when reading length; the length includes itself. + let length = data + .read_at::>(0) + .read_error("Missing COFF string table")? + .get(LE); + let strings = data + .read_bytes(length as usize) + .read_error("Invalid COFF string table length")?; + + (symbols, strings) + } else { + (&[][..], Bytes(&[])) + }; + + Ok(SymbolTable { + symbols, + strings: StringTable::new(strings), + }) + } + + /// Return the string table used for the symbol names. + #[inline] + pub fn strings(&self) -> StringTable<'data> { + self.strings + } + + /// Return true if the symbol table is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.symbols.is_empty() + } + + /// The number of symbols. + #[inline] + pub fn len(&self) -> usize { + self.symbols.len() + } + + /// Return the symbol table entry at the given index. + #[inline] + pub fn symbol(&self, index: usize) -> Result<&'data pe::ImageSymbol> { + self.get::(index) + } + + /// Return the symbol table entry or auxiliary record at the given index. + pub fn get(&self, index: usize) -> Result<&'data T> { + let bytes = self + .symbols + .get(index) + .read_error("Invalid COFF symbol index")?; + Bytes(&bytes.0[..]) + .read() + .read_error("Invalid COFF symbol data") + } + + /// Construct a map from addresses to a user-defined map entry. + pub fn map Option>( + &self, + f: F, + ) -> SymbolMap { + let mut symbols = Vec::with_capacity(self.symbols.len()); + let mut i = 0; + while let Ok(symbol) = self.symbol(i) { + i += 1 + symbol.number_of_aux_symbols as usize; + if !symbol.is_definition() { + continue; + } + if let Some(entry) = f(symbol) { + symbols.push(entry); + } + } + SymbolMap::new(symbols) + } +} + +impl pe::ImageSymbol { + /// Parse a COFF symbol name. + /// + /// `strings` must be the string table used for symbol names. + pub fn name<'data>(&'data self, strings: StringTable<'data>) -> Result<&'data [u8]> { + if self.name[0] == 0 { + // If the name starts with 0 then the last 4 bytes are a string table offset. + let offset = u32::from_le_bytes(self.name[4..8].try_into().unwrap()); + strings + .get(offset) + .read_error("Invalid COFF symbol name offset") + } else { + // The name is inline and padded with nulls. + Ok(match self.name.iter().position(|&x| x == 0) { + Some(end) => &self.name[..end], + None => &self.name[..], + }) + } + } + + /// Return the symbol address. + /// + /// This takes into account the image base and the section address. + pub fn address(&self, image_base: u64, sections: &SectionTable) -> Result { + let section_number = self.section_number.get(LE) as usize; + let section = sections.section(section_number)?; + let virtual_address = u64::from(section.virtual_address.get(LE)); + let value = u64::from(self.value.get(LE)); + Ok(image_base + virtual_address + value) + } + + /// Return true if the symbol is a definition of a function or data object. + pub fn is_definition(&self) -> bool { + let section_number = self.section_number.get(LE); + if section_number == pe::IMAGE_SYM_UNDEFINED { + return false; + } + match self.storage_class { + pe::IMAGE_SYM_CLASS_STATIC => { + if self.value.get(LE) == 0 && self.number_of_aux_symbols > 0 { + // This is a section symbol. + false + } else { + true + } + } + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true, + _ => false, + } + } +} + +/// A symbol table of a `CoffFile`. +#[derive(Debug, Clone, Copy)] +pub struct CoffSymbolTable<'data, 'file> +where + 'data: 'file, +{ + pub(crate) file: &'file CoffCommon<'data>, +} + +impl<'data, 'file> read::private::Sealed for CoffSymbolTable<'data, 'file> {} + +impl<'data, 'file> ObjectSymbolTable<'data> for CoffSymbolTable<'data, 'file> { + type Symbol = CoffSymbol<'data, 'file>; + type SymbolIterator = CoffSymbolIterator<'data, 'file>; + + fn symbols(&self) -> Self::SymbolIterator { + CoffSymbolIterator { + file: self.file, + index: 0, + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + let symbol = self.file.symbols.symbol(index.0)?; + Ok(CoffSymbol { + file: self.file, + index, + symbol, + }) + } +} + +/// An iterator over the symbols of a `CoffFile`. +pub struct CoffSymbolIterator<'data, 'file> +where + 'data: 'file, +{ + pub(crate) file: &'file CoffCommon<'data>, + pub(crate) index: usize, +} + +impl<'data, 'file> fmt::Debug for CoffSymbolIterator<'data, 'file> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CoffSymbolIterator").finish() + } +} + +impl<'data, 'file> Iterator for CoffSymbolIterator<'data, 'file> { + type Item = CoffSymbol<'data, 'file>; + + fn next(&mut self) -> Option { + let index = self.index; + let symbol = self.file.symbols.symbol(index).ok()?; + self.index += 1 + symbol.number_of_aux_symbols as usize; + Some(CoffSymbol { + file: self.file, + index: SymbolIndex(index), + symbol, + }) + } +} + +/// A symbol of a `CoffFile`. +#[derive(Debug, Clone, Copy)] +pub struct CoffSymbol<'data, 'file> +where + 'data: 'file, +{ + pub(crate) file: &'file CoffCommon<'data>, + pub(crate) index: SymbolIndex, + pub(crate) symbol: &'data pe::ImageSymbol, +} + +impl<'data, 'file> read::private::Sealed for CoffSymbol<'data, 'file> {} + +impl<'data, 'file> ObjectSymbol<'data> for CoffSymbol<'data, 'file> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + fn name(&self) -> read::Result<&'data str> { + let name = if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { + // The file name is in the following auxiliary symbol. + if self.symbol.number_of_aux_symbols > 0 { + let s = self + .file + .symbols + .get::(self.index.0 + 1)?; + // The name is padded with nulls. + match s.0.iter().position(|&x| x == 0) { + Some(end) => &s.0[..end], + None => &s.0[..], + } + } else { + &[][..] + } + } else { + self.symbol.name(self.file.symbols.strings())? + }; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 COFF symbol name") + } + + fn address(&self) -> u64 { + // Only return an address for storage classes that we know use an address. + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_STATIC + | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL + | pe::IMAGE_SYM_CLASS_LABEL => {} + pe::IMAGE_SYM_CLASS_EXTERNAL => { + if self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED { + // Undefined or common data, neither of which have an address. + return 0; + } + } + _ => return 0, + } + self.symbol + .address(self.file.image_base, &self.file.sections) + .unwrap_or(0) + } + + fn size(&self) -> u64 { + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_STATIC => { + // Section symbols may duplicate the size from the section table. + if self.symbol.value.get(LE) == 0 && self.symbol.number_of_aux_symbols > 0 { + if let Ok(aux) = self + .file + .symbols + .get::(self.index.0 + 1) + { + u64::from(aux.length.get(LE)) + } else { + 0 + } + } else { + 0 + } + } + pe::IMAGE_SYM_CLASS_EXTERNAL => { + if self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED { + // For undefined symbols, symbol.value is 0 and the size is 0. + // For common data, symbol.value is the size. + u64::from(self.symbol.value.get(LE)) + } else if self.symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION + && self.symbol.number_of_aux_symbols > 0 + { + // Function symbols may have a size. + if let Ok(aux) = self + .file + .symbols + .get::(self.index.0 + 1) + { + u64::from(aux.total_size.get(LE)) + } else { + 0 + } + } else { + 0 + } + } + // Most symbols don't have sizes. + _ => 0, + } + } + + fn kind(&self) -> SymbolKind { + let derived_kind = if self.symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION { + SymbolKind::Text + } else { + SymbolKind::Data + }; + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_STATIC => { + if self.symbol.value.get(LE) == 0 && self.symbol.number_of_aux_symbols > 0 { + SymbolKind::Section + } else { + derived_kind + } + } + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => derived_kind, + pe::IMAGE_SYM_CLASS_SECTION => SymbolKind::Section, + pe::IMAGE_SYM_CLASS_FILE => SymbolKind::File, + pe::IMAGE_SYM_CLASS_LABEL => SymbolKind::Label, + _ => SymbolKind::Unknown, + } + } + + fn section(&self) -> SymbolSection { + match self.symbol.section_number.get(LE) { + pe::IMAGE_SYM_UNDEFINED => { + if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL + && self.symbol.value.get(LE) == 0 + { + SymbolSection::Undefined + } else { + SymbolSection::Common + } + } + pe::IMAGE_SYM_ABSOLUTE => SymbolSection::Absolute, + pe::IMAGE_SYM_DEBUG => { + if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE { + SymbolSection::None + } else { + SymbolSection::Unknown + } + } + index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)), + _ => SymbolSection::Unknown, + } + } + + #[inline] + fn is_undefined(&self) -> bool { + self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL + && self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED + && self.symbol.value.get(LE) == 0 + } + + #[inline] + fn is_definition(&self) -> bool { + self.symbol.is_definition() + } + + #[inline] + fn is_common(&self) -> bool { + self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL + && self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED + && self.symbol.value.get(LE) != 0 + } + + #[inline] + fn is_weak(&self) -> bool { + self.symbol.storage_class == pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL + } + + #[inline] + fn scope(&self) -> SymbolScope { + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => { + // TODO: determine if symbol is exported + SymbolScope::Linkage + } + _ => SymbolScope::Compilation, + } + } + + #[inline] + fn is_global(&self) -> bool { + match self.symbol.storage_class { + pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true, + _ => false, + } + } + + #[inline] + fn is_local(&self) -> bool { + !self.is_global() + } + + fn flags(&self) -> SymbolFlags { + if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_STATIC + && self.symbol.value.get(LE) == 0 + && self.symbol.number_of_aux_symbols > 0 + { + if let Ok(aux) = self + .file + .symbols + .get::(self.index.0 + 1) + { + // TODO: use high_number for bigobj + let number = aux.number.get(LE) as usize; + return SymbolFlags::CoffSection { + selection: aux.selection, + associative_section: if number == 0 { + None + } else { + Some(SectionIndex(number)) + }, + }; + } + } + SymbolFlags::None + } +} diff --git a/vendor/object/src/read/elf/comdat.rs b/vendor/object/src/read/elf/comdat.rs new file mode 100644 index 0000000000..15459634e6 --- /dev/null +++ b/vendor/object/src/read/elf/comdat.rs @@ -0,0 +1,147 @@ +use core::fmt::Debug; +use core::{iter, slice, str}; + +use crate::elf; +use crate::endian::{Endianness, U32Bytes}; +use crate::pod::Bytes; +use crate::read::{self, ComdatKind, ObjectComdat, ReadError, SectionIndex, SymbolIndex}; + +use super::{ElfFile, FileHeader, SectionHeader, Sym}; + +/// An iterator over the COMDAT section groups of an `ElfFile32`. +pub type ElfComdatIterator32<'data, 'file, Endian = Endianness> = + ElfComdatIterator<'data, 'file, elf::FileHeader32>; +/// An iterator over the COMDAT section groups of an `ElfFile64`. +pub type ElfComdatIterator64<'data, 'file, Endian = Endianness> = + ElfComdatIterator<'data, 'file, elf::FileHeader64>; + +/// An iterator over the COMDAT section groups of an `ElfFile`. +#[derive(Debug)] +pub struct ElfComdatIterator<'data, 'file, Elf> +where + 'data: 'file, + Elf: FileHeader, +{ + pub(super) file: &'file ElfFile<'data, Elf>, + pub(super) iter: iter::Enumerate>, +} + +impl<'data, 'file, Elf: FileHeader> Iterator for ElfComdatIterator<'data, 'file, Elf> { + type Item = ElfComdat<'data, 'file, Elf>; + + fn next(&mut self) -> Option { + while let Some((index, section)) = self.iter.next() { + if let Some(comdat) = ElfComdat::parse(self.file, index, section) { + return Some(comdat); + } + } + None + } +} + +/// A COMDAT section group of an `ElfFile32`. +pub type ElfComdat32<'data, 'file, Endian = Endianness> = + ElfComdat<'data, 'file, elf::FileHeader32>; +/// A COMDAT section group of an `ElfFile64`. +pub type ElfComdat64<'data, 'file, Endian = Endianness> = + ElfComdat<'data, 'file, elf::FileHeader64>; + +/// A COMDAT section group of an `ElfFile`. +#[derive(Debug)] +pub struct ElfComdat<'data, 'file, Elf> +where + 'data: 'file, + Elf: FileHeader, +{ + file: &'file ElfFile<'data, Elf>, + index: SectionIndex, + section: &'data Elf::SectionHeader, + data: Bytes<'data>, +} + +impl<'data, 'file, Elf: FileHeader> ElfComdat<'data, 'file, Elf> { + fn parse( + file: &'file ElfFile<'data, Elf>, + index: usize, + section: &'data Elf::SectionHeader, + ) -> Option> { + if section.sh_type(file.endian) != elf::SHT_GROUP { + return None; + } + let mut data = section.data(file.endian, file.data).ok()?; + let flags = data.read::>().ok()?; + if flags.get(file.endian) != elf::GRP_COMDAT { + return None; + } + Some(ElfComdat { + file, + index: SectionIndex(index), + section, + data, + }) + } +} + +impl<'data, 'file, Elf: FileHeader> read::private::Sealed for ElfComdat<'data, 'file, Elf> {} + +impl<'data, 'file, Elf: FileHeader> ObjectComdat<'data> for ElfComdat<'data, 'file, Elf> { + type SectionIterator = ElfComdatSectionIterator<'data, 'file, Elf>; + + #[inline] + fn kind(&self) -> ComdatKind { + ComdatKind::Any + } + + #[inline] + fn symbol(&self) -> SymbolIndex { + SymbolIndex(self.section.sh_info(self.file.endian) as usize) + } + + fn name(&self) -> read::Result<&str> { + // FIXME: check sh_link + let index = self.section.sh_info(self.file.endian) as usize; + let symbol = self.file.symbols.symbol(index)?; + let name = symbol.name(self.file.endian, self.file.symbols.strings())?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 ELF COMDAT name") + } + + fn sections(&self) -> Self::SectionIterator { + ElfComdatSectionIterator { + file: self.file, + data: self.data, + } + } +} + +/// An iterator over the sections in a COMDAT section group of an `ElfFile32`. +pub type ElfComdatSectionIterator32<'data, 'file, Endian = Endianness> = + ElfComdatSectionIterator<'data, 'file, elf::FileHeader32>; +/// An iterator over the sections in a COMDAT section group of an `ElfFile64`. +pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness> = + ElfComdatSectionIterator<'data, 'file, elf::FileHeader64>; + +/// An iterator over the sections in a COMDAT section group of an `ElfFile`. +#[derive(Debug)] +pub struct ElfComdatSectionIterator<'data, 'file, Elf> +where + 'data: 'file, + Elf: FileHeader, +{ + file: &'file ElfFile<'data, Elf>, + data: Bytes<'data>, +} + +impl<'data, 'file, Elf: FileHeader> Iterator for ElfComdatSectionIterator<'data, 'file, Elf> { + type Item = SectionIndex; + + fn next(&mut self) -> Option { + if self.data.is_empty() { + None + } else { + let index = self.data.read::>().ok()?; + Some(SectionIndex(index.get(self.file.endian) as usize)) + } + } +} diff --git a/vendor/object-0.20.0/src/read/elf/compression.rs b/vendor/object/src/read/elf/compression.rs similarity index 100% rename from vendor/object-0.20.0/src/read/elf/compression.rs rename to vendor/object/src/read/elf/compression.rs diff --git a/vendor/object-0.20.0/src/read/elf/file.rs b/vendor/object/src/read/elf/file.rs similarity index 92% rename from vendor/object-0.20.0/src/read/elf/file.rs rename to vendor/object/src/read/elf/file.rs index 3afa4d0276..6ccddc85ef 100644 --- a/vendor/object-0.20.0/src/read/elf/file.rs +++ b/vendor/object/src/read/elf/file.rs @@ -1,17 +1,16 @@ -use alloc::vec::Vec; use core::fmt::Debug; use core::{mem, str}; use crate::read::{ self, util, Architecture, Error, FileFlags, Object, ReadError, SectionIndex, StringTable, - Symbol, SymbolIndex, SymbolMap, + SymbolIndex, }; use crate::{elf, endian, Bytes, Endian, Endianness, Pod, U32}; use super::{ - parse_symbol, CompressionHeader, ElfSection, ElfSectionIterator, ElfSegment, - ElfSegmentIterator, ElfSymbolIterator, NoteHeader, ProgramHeader, Rela, RelocationSections, - SectionHeader, SectionTable, Sym, SymbolTable, + CompressionHeader, ElfComdat, ElfComdatIterator, ElfSection, ElfSectionIterator, ElfSegment, + ElfSegmentIterator, ElfSymbol, ElfSymbolIterator, ElfSymbolTable, NoteHeader, ProgramHeader, + Rela, RelocationSections, SectionHeader, SectionTable, Sym, SymbolTable, }; /// A 32-bit ELF object file. @@ -104,7 +103,11 @@ where type SegmentIterator = ElfSegmentIterator<'data, 'file, Elf>; type Section = ElfSection<'data, 'file, Elf>; type SectionIterator = ElfSectionIterator<'data, 'file, Elf>; + type Comdat = ElfComdat<'data, 'file, Elf>; + type ComdatIterator = ElfComdatIterator<'data, 'file, Elf>; + type Symbol = ElfSymbol<'data, 'file, Elf>; type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf>; + type SymbolTable = ElfSymbolTable<'data, 'file, Elf>; fn architecture(&self) -> Architecture { match self.header.e_machine(self.endian) { @@ -113,6 +116,15 @@ where elf::EM_386 => Architecture::I386, elf::EM_X86_64 => Architecture::X86_64, elf::EM_MIPS => Architecture::Mips, + elf::EM_S390 => { + // This is either s390 or s390x, depending on the ELF class. + // We only support the 64-bit variant s390x here. + if self.is_64() { + Architecture::S390x + } else { + Architecture::Unknown + } + } _ => Architecture::Unknown, } } @@ -158,43 +170,54 @@ where } } - fn symbol_by_index(&self, index: SymbolIndex) -> read::Result> { + fn comdats(&'file self) -> ElfComdatIterator<'data, 'file, Elf> { + ElfComdatIterator { + file: self, + iter: self.sections.iter().enumerate(), + } + } + + fn symbol_by_index( + &'file self, + index: SymbolIndex, + ) -> read::Result> { let symbol = self.symbols.symbol(index.0)?; - let shndx = self.symbols.shndx(index.0); - let name = symbol.name(self.endian, self.symbols.strings()).ok(); - Ok(parse_symbol::( - self.endian, - index.0, + Ok(ElfSymbol { + endian: self.endian, + symbols: &self.symbols, + index, symbol, - name, - shndx, - )) + }) } fn symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf> { ElfSymbolIterator { - file: self, - symbols: self.symbols, + endian: self.endian, + symbols: &self.symbols, index: 0, } } + fn symbol_table(&'file self) -> Option> { + Some(ElfSymbolTable { + endian: self.endian, + symbols: &self.symbols, + }) + } + fn dynamic_symbols(&'file self) -> ElfSymbolIterator<'data, 'file, Elf> { ElfSymbolIterator { - file: self, - symbols: self.dynamic_symbols, + endian: self.endian, + symbols: &self.dynamic_symbols, index: 0, } } - fn symbol_map(&self) -> SymbolMap<'data> { - let mut symbols: Vec<_> = self - .symbols() - .map(|(_, s)| s) - .filter(SymbolMap::filter) - .collect(); - symbols.sort_by_key(|x| x.address); - SymbolMap { symbols } + fn dynamic_symbol_table(&'file self) -> Option> { + Some(ElfSymbolTable { + endian: self.endian, + symbols: &self.dynamic_symbols, + }) } fn has_debug_symbols(&self) -> bool { diff --git a/vendor/object-0.20.0/src/read/elf/mod.rs b/vendor/object/src/read/elf/mod.rs similarity index 93% rename from vendor/object-0.20.0/src/read/elf/mod.rs rename to vendor/object/src/read/elf/mod.rs index ec1aac51a3..5640760953 100644 --- a/vendor/object-0.20.0/src/read/elf/mod.rs +++ b/vendor/object/src/read/elf/mod.rs @@ -25,3 +25,6 @@ pub use compression::*; mod note; pub use note::*; + +mod comdat; +pub use comdat::*; diff --git a/vendor/object-0.20.0/src/read/elf/note.rs b/vendor/object/src/read/elf/note.rs similarity index 100% rename from vendor/object-0.20.0/src/read/elf/note.rs rename to vendor/object/src/read/elf/note.rs diff --git a/vendor/object-0.20.0/src/read/elf/relocation.rs b/vendor/object/src/read/elf/relocation.rs similarity index 80% rename from vendor/object-0.20.0/src/read/elf/relocation.rs rename to vendor/object/src/read/elf/relocation.rs index 64ec0931a7..023b289698 100644 --- a/vendor/object-0.20.0/src/read/elf/relocation.rs +++ b/vendor/object/src/read/elf/relocation.rs @@ -163,6 +163,47 @@ impl<'data, 'file, Elf: FileHeader> Iterator for ElfRelocationIterator<'data, 'f elf::R_X86_64_PC8 => (RelocationKind::Relative, 8), r_type => (RelocationKind::Elf(r_type), 0), }, + elf::EM_S390 => match reloc.r_type(endian) { + elf::R_390_8 => (RelocationKind::Absolute, 8), + elf::R_390_16 => (RelocationKind::Absolute, 16), + elf::R_390_32 => (RelocationKind::Absolute, 32), + elf::R_390_64 => (RelocationKind::Absolute, 64), + elf::R_390_PC16 => (RelocationKind::Relative, 16), + elf::R_390_PC32 => (RelocationKind::Relative, 32), + elf::R_390_PC64 => (RelocationKind::Relative, 64), + elf::R_390_PC16DBL => { + encoding = RelocationEncoding::S390xDbl; + (RelocationKind::Relative, 16) + } + elf::R_390_PC32DBL => { + encoding = RelocationEncoding::S390xDbl; + (RelocationKind::Relative, 32) + } + elf::R_390_PLT16DBL => { + encoding = RelocationEncoding::S390xDbl; + (RelocationKind::PltRelative, 16) + } + elf::R_390_PLT32DBL => { + encoding = RelocationEncoding::S390xDbl; + (RelocationKind::PltRelative, 32) + } + elf::R_390_GOT16 => (RelocationKind::Got, 16), + elf::R_390_GOT32 => (RelocationKind::Got, 32), + elf::R_390_GOT64 => (RelocationKind::Got, 64), + elf::R_390_GOTENT => { + encoding = RelocationEncoding::S390xDbl; + (RelocationKind::GotRelative, 32) + } + elf::R_390_GOTOFF16 => (RelocationKind::GotBaseOffset, 16), + elf::R_390_GOTOFF32 => (RelocationKind::GotBaseOffset, 32), + elf::R_390_GOTOFF64 => (RelocationKind::GotBaseOffset, 64), + elf::R_390_GOTPC => (RelocationKind::GotBaseRelative, 64), + elf::R_390_GOTPCDBL => { + encoding = RelocationEncoding::S390xDbl; + (RelocationKind::GotBaseRelative, 32) + } + r_type => (RelocationKind::Elf(r_type), 0), + }, _ => (RelocationKind::Elf(reloc.r_type(endian)), 0), }; let target = diff --git a/vendor/object-0.20.0/src/read/elf/section.rs b/vendor/object/src/read/elf/section.rs similarity index 99% rename from vendor/object-0.20.0/src/read/elf/section.rs rename to vendor/object/src/read/elf/section.rs index 9742633286..d8ec42f87b 100644 --- a/vendor/object-0.20.0/src/read/elf/section.rs +++ b/vendor/object/src/read/elf/section.rs @@ -324,7 +324,8 @@ impl<'data, 'file, Elf: FileHeader> ObjectSection<'data> for ElfSection<'data, ' | elf::SHT_HASH | elf::SHT_DYNAMIC | elf::SHT_REL - | elf::SHT_DYNSYM => SectionKind::Metadata, + | elf::SHT_DYNSYM + | elf::SHT_GROUP => SectionKind::Metadata, _ => { // TODO: maybe add more specialised kinds based on sh_type (e.g. Unwind) SectionKind::Unknown diff --git a/vendor/object-0.20.0/src/read/elf/segment.rs b/vendor/object/src/read/elf/segment.rs similarity index 100% rename from vendor/object-0.20.0/src/read/elf/segment.rs rename to vendor/object/src/read/elf/segment.rs diff --git a/vendor/object-0.20.0/src/read/elf/symbol.rs b/vendor/object/src/read/elf/symbol.rs similarity index 50% rename from vendor/object-0.20.0/src/read/elf/symbol.rs rename to vendor/object/src/read/elf/symbol.rs index 990dd6dffb..16acbae11e 100644 --- a/vendor/object-0.20.0/src/read/elf/symbol.rs +++ b/vendor/object/src/read/elf/symbol.rs @@ -1,4 +1,5 @@ use alloc::fmt; +use alloc::vec::Vec; use core::fmt::Debug; use core::slice; use core::str; @@ -8,11 +9,11 @@ use crate::endian::{self, Endianness}; use crate::pod::{Bytes, Pod}; use crate::read::util::StringTable; use crate::read::{ - self, ReadError, SectionIndex, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, - SymbolSection, + self, ObjectSymbol, ObjectSymbolTable, ReadError, SectionIndex, SymbolFlags, SymbolIndex, + SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection, }; -use super::{ElfFile, FileHeader, SectionHeader, SectionTable}; +use super::{FileHeader, SectionHeader, SectionTable}; /// A table of symbol entries in an ELF file. /// @@ -111,6 +112,12 @@ impl<'data, Elf: FileHeader> SymbolTable<'data, Elf> { self.symbols.is_empty() } + /// The number of symbols. + #[inline] + pub fn len(&self) -> usize { + self.symbols.len() + } + /// Return the symbol at the given index. pub fn symbol(&self, index: usize) -> read::Result<&'data Elf::Sym> { self.symbols @@ -123,6 +130,67 @@ impl<'data, Elf: FileHeader> SymbolTable<'data, Elf> { pub fn shndx(&self, index: usize) -> Option { self.shndx.get(index).cloned() } + + /// Construct a map from addresses to a user-defined map entry. + pub fn map Option>( + &self, + endian: Elf::Endian, + f: F, + ) -> SymbolMap { + let mut symbols = Vec::with_capacity(self.symbols.len()); + for symbol in self.symbols { + if !symbol.is_definition(endian) { + continue; + } + if let Some(entry) = f(symbol) { + symbols.push(entry); + } + } + SymbolMap::new(symbols) + } +} + +/// A symbol table of an `ElfFile32`. +pub type ElfSymbolTable32<'data, 'file, Endian = Endianness> = + ElfSymbolTable<'data, 'file, elf::FileHeader32>; +/// A symbol table of an `ElfFile32`. +pub type ElfSymbolTable64<'data, 'file, Endian = Endianness> = + ElfSymbolTable<'data, 'file, elf::FileHeader64>; + +/// A symbol table of an `ElfFile`. +#[derive(Debug, Clone, Copy)] +pub struct ElfSymbolTable<'data, 'file, Elf> +where + 'data: 'file, + Elf: FileHeader, +{ + pub(super) endian: Elf::Endian, + pub(super) symbols: &'file SymbolTable<'data, Elf>, +} + +impl<'data, 'file, Elf: FileHeader> read::private::Sealed for ElfSymbolTable<'data, 'file, Elf> {} + +impl<'data, 'file, Elf: FileHeader> ObjectSymbolTable<'data> for ElfSymbolTable<'data, 'file, Elf> { + type Symbol = ElfSymbol<'data, 'file, Elf>; + type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf>; + + fn symbols(&self) -> Self::SymbolIterator { + ElfSymbolIterator { + endian: self.endian, + symbols: self.symbols, + index: 0, + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> read::Result { + let symbol = self.symbols.symbol(index.0)?; + Ok(ElfSymbol { + endian: self.endian, + symbols: self.symbols, + index, + symbol, + }) + } } /// An iterator over the symbols of an `ElfFile32`. @@ -138,8 +206,8 @@ where 'data: 'file, Elf: FileHeader, { - pub(super) file: &'file ElfFile<'data, Elf>, - pub(super) symbols: SymbolTable<'data, Elf>, + pub(super) endian: Elf::Endian, + pub(super) symbols: &'file SymbolTable<'data, Elf>, pub(super) index: usize, } @@ -150,82 +218,154 @@ impl<'data, 'file, Elf: FileHeader> fmt::Debug for ElfSymbolIterator<'data, 'fil } impl<'data, 'file, Elf: FileHeader> Iterator for ElfSymbolIterator<'data, 'file, Elf> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = ElfSymbol<'data, 'file, Elf>; fn next(&mut self) -> Option { let index = self.index; - let shndx = self.symbols.shndx(index); - self.symbols.symbols.get(index).map(|symbol| { - self.index += 1; - let name = symbol.name(self.file.endian, self.symbols.strings()).ok(); - ( - SymbolIndex(index), - parse_symbol::(self.file.endian, index, symbol, name, shndx), - ) + let symbol = self.symbols.symbols.get(index)?; + self.index += 1; + Some(ElfSymbol { + endian: self.endian, + symbols: self.symbols, + index: SymbolIndex(index), + symbol, }) } } -pub(super) fn parse_symbol<'data, Elf: FileHeader>( - endian: Elf::Endian, - index: usize, - symbol: &Elf::Sym, - name: Option<&'data [u8]>, - shndx: Option, -) -> Symbol<'data> { - let name = name.and_then(|s| str::from_utf8(s).ok()); - let kind = match symbol.st_type() { - elf::STT_NOTYPE if index == 0 => SymbolKind::Null, - elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data, - elf::STT_FUNC => SymbolKind::Text, - elf::STT_SECTION => SymbolKind::Section, - elf::STT_FILE => SymbolKind::File, - elf::STT_TLS => SymbolKind::Tls, - _ => SymbolKind::Unknown, - }; - let section = match symbol.st_shndx(endian) { - elf::SHN_UNDEF => SymbolSection::Undefined, - elf::SHN_ABS => { - if kind == SymbolKind::File { - SymbolSection::None - } else { - SymbolSection::Absolute +/// A symbol of an `ElfFile32`. +pub type ElfSymbol32<'data, 'file, Endian = Endianness> = + ElfSymbol<'data, 'file, elf::FileHeader32>; +/// A symbol of an `ElfFile64`. +pub type ElfSymbol64<'data, 'file, Endian = Endianness> = + ElfSymbol<'data, 'file, elf::FileHeader64>; + +/// A symbol of an `ElfFile`. +#[derive(Debug, Clone, Copy)] +pub struct ElfSymbol<'data, 'file, Elf> +where + 'data: 'file, + Elf: FileHeader, +{ + pub(super) endian: Elf::Endian, + pub(super) symbols: &'file SymbolTable<'data, Elf>, + pub(super) index: SymbolIndex, + pub(super) symbol: &'data Elf::Sym, +} + +impl<'data, 'file, Elf: FileHeader> read::private::Sealed for ElfSymbol<'data, 'file, Elf> {} + +impl<'data, 'file, Elf: FileHeader> ObjectSymbol<'data> for ElfSymbol<'data, 'file, Elf> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + fn name(&self) -> read::Result<&'data str> { + let name = self.symbol.name(self.endian, self.symbols.strings())?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 ELF symbol name") + } + + #[inline] + fn address(&self) -> u64 { + self.symbol.st_value(self.endian).into() + } + + #[inline] + fn size(&self) -> u64 { + self.symbol.st_size(self.endian).into() + } + + fn kind(&self) -> SymbolKind { + match self.symbol.st_type() { + elf::STT_NOTYPE if self.index.0 == 0 => SymbolKind::Null, + elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data, + elf::STT_FUNC => SymbolKind::Text, + elf::STT_SECTION => SymbolKind::Section, + elf::STT_FILE => SymbolKind::File, + elf::STT_TLS => SymbolKind::Tls, + _ => SymbolKind::Unknown, + } + } + + fn section(&self) -> SymbolSection { + match self.symbol.st_shndx(self.endian) { + elf::SHN_UNDEF => SymbolSection::Undefined, + elf::SHN_ABS => { + if self.symbol.st_type() == elf::STT_FILE { + SymbolSection::None + } else { + SymbolSection::Absolute + } + } + elf::SHN_COMMON => SymbolSection::Common, + elf::SHN_XINDEX => match self.symbols.shndx(self.index.0) { + Some(index) => SymbolSection::Section(SectionIndex(index as usize)), + None => SymbolSection::Unknown, + }, + index if index < elf::SHN_LORESERVE => { + SymbolSection::Section(SectionIndex(index as usize)) } + _ => SymbolSection::Unknown, } - elf::SHN_COMMON => SymbolSection::Common, - elf::SHN_XINDEX => match shndx { - Some(index) => SymbolSection::Section(SectionIndex(index as usize)), - None => SymbolSection::Unknown, - }, - index if index < elf::SHN_LORESERVE => SymbolSection::Section(SectionIndex(index as usize)), - _ => SymbolSection::Unknown, - }; - let weak = symbol.st_bind() == elf::STB_WEAK; - let scope = match symbol.st_bind() { - _ if section == SymbolSection::Undefined => SymbolScope::Unknown, - elf::STB_LOCAL => SymbolScope::Compilation, - elf::STB_GLOBAL | elf::STB_WEAK => { - if symbol.st_visibility() == elf::STV_HIDDEN { - SymbolScope::Linkage - } else { - SymbolScope::Dynamic + } + + #[inline] + fn is_undefined(&self) -> bool { + self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF + } + + #[inline] + fn is_definition(&self) -> bool { + self.symbol.is_definition(self.endian) + } + + #[inline] + fn is_common(&self) -> bool { + self.symbol.st_shndx(self.endian) == elf::SHN_COMMON + } + + #[inline] + fn is_weak(&self) -> bool { + self.symbol.st_bind() == elf::STB_WEAK + } + + fn scope(&self) -> SymbolScope { + if self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF { + SymbolScope::Unknown + } else { + match self.symbol.st_bind() { + elf::STB_LOCAL => SymbolScope::Compilation, + elf::STB_GLOBAL | elf::STB_WEAK => { + if self.symbol.st_visibility() == elf::STV_HIDDEN { + SymbolScope::Linkage + } else { + SymbolScope::Dynamic + } + } + _ => SymbolScope::Unknown, } } - _ => SymbolScope::Unknown, - }; - let flags = SymbolFlags::Elf { - st_info: symbol.st_info(), - st_other: symbol.st_other(), - }; - Symbol { - name, - address: symbol.st_value(endian).into(), - size: symbol.st_size(endian).into(), - kind, - section, - weak, - scope, - flags, + } + + #[inline] + fn is_global(&self) -> bool { + self.symbol.st_bind() != elf::STB_LOCAL + } + + #[inline] + fn is_local(&self) -> bool { + self.symbol.st_bind() == elf::STB_LOCAL + } + + #[inline] + fn flags(&self) -> SymbolFlags { + SymbolFlags::Elf { + st_info: self.symbol.st_info(), + st_other: self.symbol.st_other(), + } } } @@ -255,6 +395,13 @@ pub trait Sym: Debug + Pod { .get(self.st_name(endian)) .read_error("Invalid ELF symbol name offset") } + + /// Return true if the symbol is a definition of a function or data object. + fn is_definition(&self, endian: Self::Endian) -> bool { + let st_type = self.st_type(); + (st_type == elf::STT_NOTYPE || st_type == elf::STT_FUNC || st_type == elf::STT_OBJECT) + && self.st_shndx(endian) != elf::SHN_UNDEF + } } impl Sym for elf::Sym32 { diff --git a/vendor/object-0.20.0/src/read/macho/file.rs b/vendor/object/src/read/macho/file.rs similarity index 72% rename from vendor/object-0.20.0/src/read/macho/file.rs rename to vendor/object/src/read/macho/file.rs index 1744bb05b5..d33acf4f23 100644 --- a/vendor/object-0.20.0/src/read/macho/file.rs +++ b/vendor/object/src/read/macho/file.rs @@ -3,15 +3,15 @@ use core::fmt::Debug; use core::{mem, str}; use crate::read::{ - self, Architecture, Error, FileFlags, Object, ObjectSection, ReadError, Result, SectionIndex, - Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolScope, SymbolSection, + self, Architecture, ComdatKind, Error, FileFlags, Object, ObjectComdat, ObjectMap, + ObjectSection, ReadError, Result, SectionIndex, SymbolIndex, }; use crate::{endian, macho, BigEndian, Bytes, Endian, Endianness, Pod}; use super::{ - parse_symbol, MachOLoadCommandIterator, MachOSection, MachOSectionInternal, - MachOSectionIterator, MachOSegment, MachOSegmentIterator, MachOSymbolIterator, Nlist, Section, - Segment, SymbolTable, + MachOLoadCommandIterator, MachOSection, MachOSectionInternal, MachOSectionIterator, + MachOSegment, MachOSegmentIterator, MachOSymbol, MachOSymbolIterator, MachOSymbolTable, Nlist, + Section, Segment, SymbolTable, }; /// A 32-bit Mach-O object file. @@ -88,7 +88,11 @@ where type SegmentIterator = MachOSegmentIterator<'data, 'file, Mach>; type Section = MachOSection<'data, 'file, Mach>; type SectionIterator = MachOSectionIterator<'data, 'file, Mach>; + type Comdat = MachOComdat<'data, 'file, Mach>; + type ComdatIterator = MachOComdatIterator<'data, 'file, Mach>; + type Symbol = MachOSymbol<'data, 'file, Mach>; type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach>; + type SymbolTable = MachOSymbolTable<'data, 'file, Mach>; fn architecture(&self) -> Architecture { match self.header.cputype(self.endian) { @@ -162,67 +166,41 @@ where } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { + fn comdats(&'file self) -> MachOComdatIterator<'data, 'file, Mach> { + MachOComdatIterator { file: self } + } + + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { let nlist = self.symbols.symbol(index.0)?; - parse_symbol(self, nlist, self.symbols.strings()) - .read_error("Unsupported Mach-O symbol index") + MachOSymbol::new(self, index, nlist).read_error("Unsupported Mach-O symbol index") } fn symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach> { MachOSymbolIterator { file: self, - symbols: self.symbols, index: 0, } } + #[inline] + fn symbol_table(&'file self) -> Option> { + Some(MachOSymbolTable { file: self }) + } + fn dynamic_symbols(&'file self) -> MachOSymbolIterator<'data, 'file, Mach> { - // The LC_DYSYMTAB command contains indices into the same symbol - // table as the LC_SYMTAB command, so return all of them. - self.symbols() - } - - fn symbol_map(&self) -> SymbolMap<'data> { - let mut symbols: Vec<_> = self.symbols().map(|(_, s)| s).collect(); - - // Add symbols for the end of each section. - for section in self.sections() { - symbols.push(Symbol { - name: None, - address: section.address() + section.size(), - size: 0, - kind: SymbolKind::Section, - section: SymbolSection::Undefined, - weak: false, - scope: SymbolScope::Compilation, - flags: SymbolFlags::None, - }); + MachOSymbolIterator { + file: self, + index: self.symbols.len(), } + } - // Calculate symbol sizes by sorting and finding the next symbol. - symbols.sort_by(|a, b| { - a.address.cmp(&b.address).then_with(|| { - // Place the end of section symbols last. - (a.kind == SymbolKind::Section).cmp(&(b.kind == SymbolKind::Section)) - }) - }); - - for i in 0..symbols.len() { - let (before, after) = symbols.split_at_mut(i + 1); - let symbol = &mut before[i]; - if symbol.kind != SymbolKind::Section { - if let Some(next) = after - .iter() - .skip_while(|x| x.kind != SymbolKind::Section && x.address == symbol.address) - .next() - { - symbol.size = next.address - symbol.address; - } - } - } + #[inline] + fn dynamic_symbol_table(&'file self) -> Option> { + None + } - symbols.retain(SymbolMap::filter); - SymbolMap { symbols } + fn object_map(&'file self) -> ObjectMap<'data> { + self.symbols.object_map(self.endian) } fn has_debug_symbols(&self) -> bool { @@ -251,6 +229,92 @@ where } } +/// An iterator over the COMDAT section groups of a `MachOFile64`. +pub type MachOComdatIterator32<'data, 'file, Endian = Endianness> = + MachOComdatIterator<'data, 'file, macho::MachHeader32>; +/// An iterator over the COMDAT section groups of a `MachOFile64`. +pub type MachOComdatIterator64<'data, 'file, Endian = Endianness> = + MachOComdatIterator<'data, 'file, macho::MachHeader64>; + +/// An iterator over the COMDAT section groups of a `MachOFile`. +#[derive(Debug)] +pub struct MachOComdatIterator<'data, 'file, Mach: MachHeader> { + file: &'file MachOFile<'data, Mach>, +} + +impl<'data, 'file, Mach: MachHeader> Iterator for MachOComdatIterator<'data, 'file, Mach> { + type Item = MachOComdat<'data, 'file, Mach>; + + #[inline] + fn next(&mut self) -> Option { + None + } +} + +/// A COMDAT section group of a `MachOFile32`. +pub type MachOComdat32<'data, 'file, Endian = Endianness> = + MachOComdat<'data, 'file, macho::MachHeader32>; + +/// A COMDAT section group of a `MachOFile64`. +pub type MachOComdat64<'data, 'file, Endian = Endianness> = + MachOComdat<'data, 'file, macho::MachHeader64>; + +/// A COMDAT section group of a `MachOFile`. +#[derive(Debug)] +pub struct MachOComdat<'data, 'file, Mach: MachHeader> { + file: &'file MachOFile<'data, Mach>, +} + +impl<'data, 'file, Mach: MachHeader> read::private::Sealed for MachOComdat<'data, 'file, Mach> {} + +impl<'data, 'file, Mach: MachHeader> ObjectComdat<'data> for MachOComdat<'data, 'file, Mach> { + type SectionIterator = MachOComdatSectionIterator<'data, 'file, Mach>; + + #[inline] + fn kind(&self) -> ComdatKind { + unreachable!(); + } + + #[inline] + fn symbol(&self) -> SymbolIndex { + unreachable!(); + } + + #[inline] + fn name(&self) -> Result<&str> { + unreachable!(); + } + + #[inline] + fn sections(&self) -> Self::SectionIterator { + unreachable!(); + } +} + +/// An iterator over the sections in a COMDAT section group of a `MachOFile32`. +pub type MachOComdatSectionIterator32<'data, 'file, Endian = Endianness> = + MachOComdatSectionIterator<'data, 'file, macho::MachHeader32>; +/// An iterator over the sections in a COMDAT section group of a `MachOFile64`. +pub type MachOComdatSectionIterator64<'data, 'file, Endian = Endianness> = + MachOComdatSectionIterator<'data, 'file, macho::MachHeader64>; + +/// An iterator over the sections in a COMDAT section group of a `MachOFile`. +#[derive(Debug)] +pub struct MachOComdatSectionIterator<'data, 'file, Mach: MachHeader> +where + 'data: 'file, +{ + file: &'file MachOFile<'data, Mach>, +} + +impl<'data, 'file, Mach: MachHeader> Iterator for MachOComdatSectionIterator<'data, 'file, Mach> { + type Item = SectionIndex; + + fn next(&mut self) -> Option { + None + } +} + /// A trait for generic access to `MachHeader32` and `MachHeader64`. #[allow(missing_docs)] pub trait MachHeader: Debug + Pod { diff --git a/vendor/object-0.20.0/src/read/macho/load_command.rs b/vendor/object/src/read/macho/load_command.rs similarity index 100% rename from vendor/object-0.20.0/src/read/macho/load_command.rs rename to vendor/object/src/read/macho/load_command.rs diff --git a/vendor/object-0.20.0/src/read/macho/mod.rs b/vendor/object/src/read/macho/mod.rs similarity index 100% rename from vendor/object-0.20.0/src/read/macho/mod.rs rename to vendor/object/src/read/macho/mod.rs diff --git a/vendor/object-0.20.0/src/read/macho/relocation.rs b/vendor/object/src/read/macho/relocation.rs similarity index 100% rename from vendor/object-0.20.0/src/read/macho/relocation.rs rename to vendor/object/src/read/macho/relocation.rs diff --git a/vendor/object-0.20.0/src/read/macho/section.rs b/vendor/object/src/read/macho/section.rs similarity index 100% rename from vendor/object-0.20.0/src/read/macho/section.rs rename to vendor/object/src/read/macho/section.rs diff --git a/vendor/object-0.20.0/src/read/macho/segment.rs b/vendor/object/src/read/macho/segment.rs similarity index 100% rename from vendor/object-0.20.0/src/read/macho/segment.rs rename to vendor/object/src/read/macho/segment.rs diff --git a/vendor/object/src/read/macho/symbol.rs b/vendor/object/src/read/macho/symbol.rs new file mode 100644 index 0000000000..62162d0b55 --- /dev/null +++ b/vendor/object/src/read/macho/symbol.rs @@ -0,0 +1,424 @@ +use alloc::vec::Vec; +use core::fmt::Debug; +use core::{fmt, slice, str}; + +use crate::endian::{self, Endianness}; +use crate::macho; +use crate::pod::Pod; +use crate::read::util::StringTable; +use crate::read::{ + self, ObjectMap, ObjectMapEntry, ObjectSymbol, ObjectSymbolTable, ReadError, Result, + SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, + SymbolScope, SymbolSection, +}; + +use super::{MachHeader, MachOFile}; + +/// A table of symbol entries in a Mach-O file. +/// +/// Also includes the string table used for the symbol names. +#[derive(Debug, Clone, Copy)] +pub struct SymbolTable<'data, Mach: MachHeader> { + symbols: &'data [Mach::Nlist], + strings: StringTable<'data>, +} + +impl<'data, Mach: MachHeader> Default for SymbolTable<'data, Mach> { + fn default() -> Self { + SymbolTable { + symbols: &[], + strings: Default::default(), + } + } +} + +impl<'data, Mach: MachHeader> SymbolTable<'data, Mach> { + #[inline] + pub(super) fn new(symbols: &'data [Mach::Nlist], strings: StringTable<'data>) -> Self { + SymbolTable { symbols, strings } + } + + /// Return the string table used for the symbol names. + #[inline] + pub fn strings(&self) -> StringTable<'data> { + self.strings + } + + /// Iterate over the symbols. + #[inline] + pub fn iter(&self) -> slice::Iter<'data, Mach::Nlist> { + self.symbols.iter() + } + + /// Return true if the symbol table is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.symbols.is_empty() + } + + /// The number of symbols. + #[inline] + pub fn len(&self) -> usize { + self.symbols.len() + } + + /// Return the symbol at the given index. + pub fn symbol(&self, index: usize) -> Result<&'data Mach::Nlist> { + self.symbols + .get(index) + .read_error("Invalid Mach-O symbol index") + } + + /// Construct a map from addresses to a user-defined map entry. + pub fn map Option>( + &self, + f: F, + ) -> SymbolMap { + let mut symbols = Vec::new(); + for nlist in self.symbols { + if !nlist.is_definition() { + continue; + } + if let Some(entry) = f(nlist) { + symbols.push(entry); + } + } + SymbolMap::new(symbols) + } + + /// Construct a map from addresses to symbol names and object file names. + pub fn object_map(&self, endian: Mach::Endian) -> ObjectMap<'data> { + let mut symbols = Vec::new(); + let mut objects = Vec::new(); + let mut object = None; + let mut current_function = None; + // Each module starts with one or two N_SO symbols (path, or directory + filename) + // and one N_OSO symbol. The module is terminated by an empty N_SO symbol. + for nlist in self.symbols { + let n_type = nlist.n_type(); + if n_type & macho::N_STAB == 0 { + continue; + } + // TODO: includes variables too (N_GSYM, N_STSYM). These may need to get their + // address from regular symbols though. + match n_type { + macho::N_SO => { + object = None; + } + macho::N_OSO => { + object = None; + if let Ok(name) = nlist.name(endian, self.strings) { + if !name.is_empty() { + object = Some(objects.len()); + objects.push(name); + } + } + } + macho::N_FUN => { + if let Ok(name) = nlist.name(endian, self.strings) { + if !name.is_empty() { + current_function = Some((name, nlist.n_value(endian).into())) + } else if let Some((name, address)) = current_function.take() { + if let Some(object) = object { + symbols.push(ObjectMapEntry { + address, + size: nlist.n_value(endian).into(), + name, + object, + }); + } + } + } + } + _ => {} + } + } + ObjectMap { + symbols: SymbolMap::new(symbols), + objects, + } + } +} + +/// An iterator over the symbols of a `MachOFile32`. +pub type MachOSymbolTable32<'data, 'file, Endian = Endianness> = + MachOSymbolTable<'data, 'file, macho::MachHeader32>; +/// An iterator over the symbols of a `MachOFile64`. +pub type MachOSymbolTable64<'data, 'file, Endian = Endianness> = + MachOSymbolTable<'data, 'file, macho::MachHeader64>; + +/// A symbol table of a `MachOFile`. +#[derive(Debug, Clone, Copy)] +pub struct MachOSymbolTable<'data, 'file, Mach: MachHeader> { + pub(super) file: &'file MachOFile<'data, Mach>, +} + +impl<'data, 'file, Mach: MachHeader> read::private::Sealed + for MachOSymbolTable<'data, 'file, Mach> +{ +} + +impl<'data, 'file, Mach: MachHeader> ObjectSymbolTable<'data> + for MachOSymbolTable<'data, 'file, Mach> +{ + type Symbol = MachOSymbol<'data, 'file, Mach>; + type SymbolIterator = MachOSymbolIterator<'data, 'file, Mach>; + + fn symbols(&self) -> Self::SymbolIterator { + MachOSymbolIterator { + file: self.file, + index: 0, + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + let nlist = self.file.symbols.symbol(index.0)?; + MachOSymbol::new(self.file, index, nlist).read_error("Unsupported Mach-O symbol index") + } +} + +/// An iterator over the symbols of a `MachOFile32`. +pub type MachOSymbolIterator32<'data, 'file, Endian = Endianness> = + MachOSymbolIterator<'data, 'file, macho::MachHeader32>; +/// An iterator over the symbols of a `MachOFile64`. +pub type MachOSymbolIterator64<'data, 'file, Endian = Endianness> = + MachOSymbolIterator<'data, 'file, macho::MachHeader64>; + +/// An iterator over the symbols of a `MachOFile`. +pub struct MachOSymbolIterator<'data, 'file, Mach: MachHeader> { + pub(super) file: &'file MachOFile<'data, Mach>, + pub(super) index: usize, +} + +impl<'data, 'file, Mach: MachHeader> fmt::Debug for MachOSymbolIterator<'data, 'file, Mach> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("MachOSymbolIterator").finish() + } +} + +impl<'data, 'file, Mach: MachHeader> Iterator for MachOSymbolIterator<'data, 'file, Mach> { + type Item = MachOSymbol<'data, 'file, Mach>; + + fn next(&mut self) -> Option { + loop { + let index = self.index; + let nlist = self.file.symbols.symbols.get(index)?; + self.index += 1; + if let Some(symbol) = MachOSymbol::new(self.file, SymbolIndex(index), nlist) { + return Some(symbol); + } + } + } +} + +/// A symbol of a `MachOFile32`. +pub type MachOSymbol32<'data, 'file, Endian = Endianness> = + MachOSymbol<'data, 'file, macho::MachHeader32>; +/// A symbol of a `MachOFile64`. +pub type MachOSymbol64<'data, 'file, Endian = Endianness> = + MachOSymbol<'data, 'file, macho::MachHeader64>; + +/// A symbol of a `MachOFile`. +#[derive(Debug, Clone, Copy)] +pub struct MachOSymbol<'data, 'file, Mach: MachHeader> { + file: &'file MachOFile<'data, Mach>, + index: SymbolIndex, + nlist: &'data Mach::Nlist, +} + +impl<'data, 'file, Mach: MachHeader> MachOSymbol<'data, 'file, Mach> { + pub(super) fn new( + file: &'file MachOFile<'data, Mach>, + index: SymbolIndex, + nlist: &'data Mach::Nlist, + ) -> Option { + if nlist.n_type() & macho::N_STAB != 0 { + return None; + } + Some(MachOSymbol { file, index, nlist }) + } +} + +impl<'data, 'file, Mach: MachHeader> read::private::Sealed for MachOSymbol<'data, 'file, Mach> {} + +impl<'data, 'file, Mach: MachHeader> ObjectSymbol<'data> for MachOSymbol<'data, 'file, Mach> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + fn name(&self) -> Result<&'data str> { + let name = self + .nlist + .name(self.file.endian, self.file.symbols.strings)?; + str::from_utf8(name) + .ok() + .read_error("Non UTF-8 Mach-O symbol name") + } + + #[inline] + fn address(&self) -> u64 { + self.nlist.n_value(self.file.endian).into() + } + + #[inline] + fn size(&self) -> u64 { + 0 + } + + fn kind(&self) -> SymbolKind { + self.section() + .index() + .and_then(|index| self.file.section_internal(index).ok()) + .map(|section| match section.kind { + SectionKind::Text => SymbolKind::Text, + SectionKind::Data + | SectionKind::ReadOnlyData + | SectionKind::ReadOnlyString + | SectionKind::UninitializedData + | SectionKind::Common => SymbolKind::Data, + SectionKind::Tls | SectionKind::UninitializedTls | SectionKind::TlsVariables => { + SymbolKind::Tls + } + _ => SymbolKind::Unknown, + }) + .unwrap_or(SymbolKind::Unknown) + } + + fn section(&self) -> SymbolSection { + match self.nlist.n_type() & macho::N_TYPE { + macho::N_UNDF => SymbolSection::Undefined, + macho::N_ABS => SymbolSection::Absolute, + macho::N_SECT => { + let n_sect = self.nlist.n_sect(); + if n_sect != 0 { + SymbolSection::Section(SectionIndex(n_sect as usize)) + } else { + SymbolSection::Unknown + } + } + _ => SymbolSection::Unknown, + } + } + + #[inline] + fn is_undefined(&self) -> bool { + self.nlist.n_type() & macho::N_TYPE == macho::N_UNDF + } + + #[inline] + fn is_definition(&self) -> bool { + self.nlist.is_definition() + } + + #[inline] + fn is_common(&self) -> bool { + // Mach-O common symbols are based on section, not symbol + false + } + + #[inline] + fn is_weak(&self) -> bool { + self.nlist.n_desc(self.file.endian) & (macho::N_WEAK_REF | macho::N_WEAK_DEF) != 0 + } + + fn scope(&self) -> SymbolScope { + let n_type = self.nlist.n_type(); + if n_type & macho::N_TYPE == macho::N_UNDF { + SymbolScope::Unknown + } else if n_type & macho::N_EXT == 0 { + SymbolScope::Compilation + } else if n_type & macho::N_PEXT != 0 { + SymbolScope::Linkage + } else { + SymbolScope::Dynamic + } + } + + #[inline] + fn is_global(&self) -> bool { + self.scope() != SymbolScope::Compilation + } + + #[inline] + fn is_local(&self) -> bool { + self.scope() == SymbolScope::Compilation + } + + #[inline] + fn flags(&self) -> SymbolFlags { + let n_desc = self.nlist.n_desc(self.file.endian); + SymbolFlags::MachO { n_desc } + } +} + +/// A trait for generic access to `Nlist32` and `Nlist64`. +#[allow(missing_docs)] +pub trait Nlist: Debug + Pod { + type Word: Into; + type Endian: endian::Endian; + + fn n_strx(&self, endian: Self::Endian) -> u32; + fn n_type(&self) -> u8; + fn n_sect(&self) -> u8; + fn n_desc(&self, endian: Self::Endian) -> u16; + fn n_value(&self, endian: Self::Endian) -> Self::Word; + + fn name<'data>( + &self, + endian: Self::Endian, + strings: StringTable<'data>, + ) -> Result<&'data [u8]> { + strings + .get(self.n_strx(endian)) + .read_error("Invalid Mach-O symbol name offset") + } + + /// Return true if the symbol is a definition of a function or data object. + fn is_definition(&self) -> bool { + let n_type = self.n_type(); + n_type & macho::N_STAB == 0 && n_type & macho::N_TYPE != macho::N_UNDF + } +} + +impl Nlist for macho::Nlist32 { + type Word = u32; + type Endian = Endian; + + fn n_strx(&self, endian: Self::Endian) -> u32 { + self.n_strx.get(endian) + } + fn n_type(&self) -> u8 { + self.n_type + } + fn n_sect(&self) -> u8 { + self.n_sect + } + fn n_desc(&self, endian: Self::Endian) -> u16 { + self.n_desc.get(endian) + } + fn n_value(&self, endian: Self::Endian) -> Self::Word { + self.n_value.get(endian) + } +} + +impl Nlist for macho::Nlist64 { + type Word = u64; + type Endian = Endian; + + fn n_strx(&self, endian: Self::Endian) -> u32 { + self.n_strx.get(endian) + } + fn n_type(&self) -> u8 { + self.n_type + } + fn n_sect(&self) -> u8 { + self.n_sect + } + fn n_desc(&self, endian: Self::Endian) -> u16 { + self.n_desc.get(endian) + } + fn n_value(&self, endian: Self::Endian) -> Self::Word { + self.n_value.get(endian) + } +} diff --git a/vendor/object-0.20.0/src/read/mod.rs b/vendor/object/src/read/mod.rs similarity index 72% rename from vendor/object-0.20.0/src/read/mod.rs rename to vendor/object/src/read/mod.rs index f223c504dc..7a78e403c7 100644 --- a/vendor/object-0.20.0/src/read/mod.rs +++ b/vendor/object/src/read/mod.rs @@ -2,7 +2,7 @@ use alloc::borrow::Cow; use alloc::vec::Vec; -use core::{cmp, fmt, result}; +use core::{fmt, result}; use crate::common::*; use crate::Bytes; @@ -13,6 +13,9 @@ pub use util::StringTable; mod any; pub use any::*; +#[cfg(feature = "archive")] +pub mod archive; + #[cfg(feature = "coff")] pub mod coff; @@ -145,147 +148,156 @@ impl SymbolSection { } } -/// A symbol table entry. -#[derive(Clone, Debug)] -pub struct Symbol<'data> { - name: Option<&'data str>, - address: u64, - size: u64, - kind: SymbolKind, - section: SymbolSection, - weak: bool, - scope: SymbolScope, - flags: SymbolFlags, +/// An entry in a `SymbolMap`. +pub trait SymbolMapEntry { + /// The symbol address. + fn address(&self) -> u64; } -impl<'data> Symbol<'data> { - /// Return the kind of this symbol. - #[inline] - pub fn kind(&self) -> SymbolKind { - self.kind - } +/// A map from addresses to symbols. +#[derive(Debug, Default, Clone)] +pub struct SymbolMap { + symbols: Vec, +} - /// Returns the section where the symbol is defined. - #[inline] - pub fn section(&self) -> SymbolSection { - self.section +impl SymbolMap { + /// Construct a new symbol map. + /// + /// This function will sort the symbols by address. + pub fn new(mut symbols: Vec) -> Self { + symbols.sort_unstable_by_key(|s| s.address()); + SymbolMap { symbols } } - /// Returns the section index for the section containing this symbol. - /// - /// May return `None` if the symbol is not defined in a section. - #[inline] - pub fn section_index(&self) -> Option { - self.section.index() + /// Get the symbol before the given address. + pub fn get(&self, address: u64) -> Option<&T> { + let index = match self + .symbols + .binary_search_by_key(&address, |symbol| symbol.address()) + { + Ok(index) => index, + Err(index) => index.checked_sub(1)?, + }; + self.symbols.get(index) } - /// Return true if the symbol is undefined. + /// Get all symbols in the map. #[inline] - pub fn is_undefined(&self) -> bool { - self.section == SymbolSection::Undefined + pub fn symbols(&self) -> &[T] { + &self.symbols } +} - /// Return true if the symbol is common data. - /// - /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. - #[inline] - fn is_common(&self) -> bool { - self.section == SymbolSection::Common +/// A `SymbolMap` entry for symbol names. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SymbolMapName<'data> { + address: u64, + name: &'data str, +} + +impl<'data> SymbolMapName<'data> { + /// Construct a `SymbolMapName`. + pub fn new(address: u64, name: &'data str) -> Self { + SymbolMapName { address, name } } - /// Return true if the symbol is weak. + /// The symbol address. #[inline] - pub fn is_weak(&self) -> bool { - self.weak + pub fn address(&self) -> u64 { + self.address } - /// Return true if the symbol visible outside of the compilation unit. - /// - /// This treats `SymbolScope::Unknown` as global. + /// The symbol name. #[inline] - pub fn is_global(&self) -> bool { - !self.is_local() + pub fn name(&self) -> &'data str { + self.name } +} - /// Return true if the symbol is only visible within the compilation unit. +impl<'data> SymbolMapEntry for SymbolMapName<'data> { #[inline] - pub fn is_local(&self) -> bool { - self.scope == SymbolScope::Compilation + fn address(&self) -> u64 { + self.address } +} - /// Returns the symbol scope. - #[inline] - pub fn scope(&self) -> SymbolScope { - self.scope +/// A map from addresses to symbol names and object files. +/// +/// This is derived from STAB entries in Mach-O files. +#[derive(Debug, Default, Clone)] +pub struct ObjectMap<'data> { + symbols: SymbolMap>, + objects: Vec<&'data [u8]>, +} + +impl<'data> ObjectMap<'data> { + /// Get the entry containing the given address. + pub fn get(&self, address: u64) -> Option<&ObjectMapEntry<'data>> { + self.symbols + .get(address) + .filter(|entry| entry.size == 0 || address.wrapping_sub(entry.address) < entry.size) } - /// Symbol flags that are specific to each file format. + /// Get all symbols in the map. #[inline] - pub fn flags(&self) -> SymbolFlags { - self.flags + pub fn symbols(&self) -> &[ObjectMapEntry<'data>] { + self.symbols.symbols() } - /// The name of the symbol. + /// Get all objects in the map. #[inline] - pub fn name(&self) -> Option<&'data str> { - self.name + pub fn objects(&self) -> &[&'data [u8]] { + &self.objects } +} - /// The address of the symbol. May be zero if the address is unknown. +/// A `ObjectMap` entry. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ObjectMapEntry<'data> { + address: u64, + size: u64, + name: &'data [u8], + object: usize, +} + +impl<'data> ObjectMapEntry<'data> { + /// Get the symbol address. #[inline] pub fn address(&self) -> u64 { self.address } - /// The size of the symbol. May be zero if the size is unknown. + /// Get the symbol size. + /// + /// This may be 0 if the size is unknown. #[inline] pub fn size(&self) -> u64 { self.size } -} -/// A map from addresses to symbols. -#[derive(Debug)] -pub struct SymbolMap<'data> { - symbols: Vec>, -} + /// Get the symbol name. + #[inline] + pub fn name(&self) -> &'data [u8] { + self.name + } -impl<'data> SymbolMap<'data> { - /// Get the symbol containing the given address. - pub fn get(&self, address: u64) -> Option<&Symbol<'data>> { - self.symbols - .binary_search_by(|symbol| { - if address < symbol.address { - cmp::Ordering::Greater - } else if address < symbol.address + symbol.size { - cmp::Ordering::Equal - } else { - cmp::Ordering::Less - } - }) - .ok() - .and_then(|index| self.symbols.get(index)) + /// Get the index of the object file name. + #[inline] + pub fn object_index(&self) -> usize { + self.object } - /// Get all symbols in the map. + /// Get the object file name. #[inline] - pub fn symbols(&self) -> &[Symbol<'data>] { - &self.symbols + pub fn object(&self, map: &ObjectMap<'data>) -> &'data [u8] { + map.objects[self.object] } +} - /// Return true for symbols that should be included in the map. - fn filter(symbol: &Symbol<'_>) -> bool { - match symbol.kind() { - SymbolKind::Unknown | SymbolKind::Text | SymbolKind::Data => {} - SymbolKind::Null - | SymbolKind::Section - | SymbolKind::File - | SymbolKind::Label - | SymbolKind::Tls => { - return false; - } - } - !symbol.is_undefined() && !symbol.is_common() && symbol.size() > 0 +impl<'data> SymbolMapEntry for ObjectMapEntry<'data> { + #[inline] + fn address(&self) -> u64 { + self.address } } diff --git a/vendor/object-0.20.0/src/read/pe/file.rs b/vendor/object/src/read/pe/file.rs similarity index 80% rename from vendor/object-0.20.0/src/read/pe/file.rs rename to vendor/object/src/read/pe/file.rs index 0183a99d90..426e5001b0 100644 --- a/vendor/object-0.20.0/src/read/pe/file.rs +++ b/vendor/object/src/read/pe/file.rs @@ -1,11 +1,10 @@ -use alloc::vec::Vec; use core::fmt::Debug; use core::{mem, str}; -use crate::read::coff::{parse_symbol, CoffSymbolIterator, SymbolTable}; +use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable}; use crate::read::{ - self, Architecture, Error, FileFlags, Object, ReadError, Result, SectionIndex, Symbol, - SymbolIndex, SymbolMap, + self, Architecture, ComdatKind, Error, FileFlags, Object, ObjectComdat, ReadError, Result, + SectionIndex, SymbolIndex, }; use crate::{pe, Bytes, LittleEndian as LE, Pod}; @@ -22,8 +21,7 @@ pub struct PeFile<'data, Pe: ImageNtHeaders> { pub(super) dos_header: &'data pe::ImageDosHeader, pub(super) nt_headers: &'data Pe, pub(super) data_directories: &'data [pe::ImageDataDirectory], - pub(super) sections: SectionTable<'data>, - pub(super) symbols: SymbolTable<'data>, + pub(super) common: CoffCommon<'data>, pub(super) data: Bytes<'data>, } @@ -49,13 +47,17 @@ impl<'data, Pe: ImageNtHeaders> PeFile<'data, Pe> { let (nt_headers, data_directories, nt_tail) = dos_header.nt_headers::(data)?; let sections = nt_headers.sections(nt_tail)?; let symbols = nt_headers.symbols(data)?; + let image_base = u64::from(nt_headers.optional_header().image_base()); Ok(PeFile { dos_header, nt_headers, data_directories, - sections, - symbols, + common: CoffCommon { + sections, + symbols, + image_base, + }, data, }) } @@ -76,7 +78,11 @@ where type SegmentIterator = PeSegmentIterator<'data, 'file, Pe>; type Section = PeSection<'data, 'file, Pe>; type SectionIterator = PeSectionIterator<'data, 'file, Pe>; + type Comdat = PeComdat<'data, 'file, Pe>; + type ComdatIterator = PeComdatIterator<'data, 'file, Pe>; + type Symbol = CoffSymbol<'data, 'file>; type SymbolIterator = CoffSymbolIterator<'data, 'file>; + type SymbolTable = CoffSymbolTable<'data, 'file>; fn architecture(&self) -> Architecture { match self.nt_headers.file_header().machine.get(LE) { @@ -101,13 +107,14 @@ where fn segments(&'file self) -> PeSegmentIterator<'data, 'file, Pe> { PeSegmentIterator { file: self, - iter: self.sections.iter(), + iter: self.common.sections.iter(), } } fn section_by_name(&'file self, section_name: &str) -> Option> { - self.sections - .section_by_name(self.symbols.strings(), section_name.as_bytes()) + self.common + .sections + .section_by_name(self.common.symbols.strings(), section_name.as_bytes()) .map(|(index, section)| PeSection { file: self, index: SectionIndex(index), @@ -116,7 +123,7 @@ where } fn section_by_index(&'file self, index: SectionIndex) -> Result> { - let section = self.sections.section(index.0)?; + let section = self.common.sections.section(index.0)?; Ok(PeSection { file: self, index, @@ -127,43 +134,44 @@ where fn sections(&'file self) -> PeSectionIterator<'data, 'file, Pe> { PeSectionIterator { file: self, - iter: self.sections.iter().enumerate(), + iter: self.common.sections.iter().enumerate(), } } - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - let symbol = self - .symbols - .get(index.0) - .read_error("Invalid PE symbol index")?; - Ok(parse_symbol(&self.symbols, index.0, symbol)) + fn comdats(&'file self) -> PeComdatIterator<'data, 'file, Pe> { + PeComdatIterator { file: self } + } + + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + let symbol = self.common.symbols.symbol(index.0)?; + Ok(CoffSymbol { + file: &self.common, + index, + symbol, + }) } fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, index: 0, } } + fn symbol_table(&'file self) -> Option> { + Some(CoffSymbolTable { file: &self.common }) + } + fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file> { - // TODO: return exports/imports CoffSymbolIterator { - symbols: &self.symbols, + file: &self.common, // Hack: don't return any. - index: self.symbols.len(), + index: self.common.symbols.len(), } } - fn symbol_map(&self) -> SymbolMap<'data> { - // TODO: untested - let mut symbols: Vec<_> = self - .symbols() - .map(|(_, s)| s) - .filter(SymbolMap::filter) - .collect(); - symbols.sort_by_key(|x| x.address); - SymbolMap { symbols } + fn dynamic_symbol_table(&'file self) -> Option> { + None } fn has_debug_symbols(&self) -> bool { @@ -181,6 +189,87 @@ where } } +/// An iterator over the COMDAT section groups of a `PeFile32`. +pub type PeComdatIterator32<'data, 'file> = PeComdatIterator<'data, 'file, pe::ImageNtHeaders32>; +/// An iterator over the COMDAT section groups of a `PeFile64`. +pub type PeComdatIterator64<'data, 'file> = PeComdatIterator<'data, 'file, pe::ImageNtHeaders64>; + +/// An iterator over the COMDAT section groups of a `PeFile`. +#[derive(Debug)] +pub struct PeComdatIterator<'data, 'file, Pe: ImageNtHeaders> { + file: &'file PeFile<'data, Pe>, +} + +impl<'data, 'file, Pe: ImageNtHeaders> Iterator for PeComdatIterator<'data, 'file, Pe> { + type Item = PeComdat<'data, 'file, Pe>; + + #[inline] + fn next(&mut self) -> Option { + None + } +} + +/// A COMDAT section group of a `PeFile32`. +pub type PeComdat32<'data, 'file> = PeComdat<'data, 'file, pe::ImageNtHeaders32>; +/// A COMDAT section group of a `PeFile64`. +pub type PeComdat64<'data, 'file> = PeComdat<'data, 'file, pe::ImageNtHeaders64>; + +/// A COMDAT section group of a `PeFile`. +#[derive(Debug)] +pub struct PeComdat<'data, 'file, Pe: ImageNtHeaders> { + file: &'file PeFile<'data, Pe>, +} + +impl<'data, 'file, Pe: ImageNtHeaders> read::private::Sealed for PeComdat<'data, 'file, Pe> {} + +impl<'data, 'file, Pe: ImageNtHeaders> ObjectComdat<'data> for PeComdat<'data, 'file, Pe> { + type SectionIterator = PeComdatSectionIterator<'data, 'file, Pe>; + + #[inline] + fn kind(&self) -> ComdatKind { + unreachable!(); + } + + #[inline] + fn symbol(&self) -> SymbolIndex { + unreachable!(); + } + + #[inline] + fn name(&self) -> Result<&str> { + unreachable!(); + } + + #[inline] + fn sections(&self) -> Self::SectionIterator { + unreachable!(); + } +} + +/// An iterator over the sections in a COMDAT section group of a `PeFile32`. +pub type PeComdatSectionIterator32<'data, 'file> = + PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders32>; +/// An iterator over the sections in a COMDAT section group of a `PeFile64`. +pub type PeComdatSectionIterator64<'data, 'file> = + PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders64>; + +/// An iterator over the sections in a COMDAT section group of a `PeFile`. +#[derive(Debug)] +pub struct PeComdatSectionIterator<'data, 'file, Pe: ImageNtHeaders> +where + 'data: 'file, +{ + file: &'file PeFile<'data, Pe>, +} + +impl<'data, 'file, Pe: ImageNtHeaders> Iterator for PeComdatSectionIterator<'data, 'file, Pe> { + type Item = SectionIndex; + + fn next(&mut self) -> Option { + None + } +} + impl pe::ImageDosHeader { /// Read the DOS header. /// diff --git a/vendor/object-0.20.0/src/read/pe/mod.rs b/vendor/object/src/read/pe/mod.rs similarity index 100% rename from vendor/object-0.20.0/src/read/pe/mod.rs rename to vendor/object/src/read/pe/mod.rs diff --git a/vendor/object-0.20.0/src/read/pe/section.rs b/vendor/object/src/read/pe/section.rs similarity index 98% rename from vendor/object-0.20.0/src/read/pe/section.rs rename to vendor/object/src/read/pe/section.rs index 086c37216c..82e2d1c2da 100644 --- a/vendor/object-0.20.0/src/read/pe/section.rs +++ b/vendor/object/src/read/pe/section.rs @@ -101,7 +101,7 @@ impl<'data, 'file, Pe: ImageNtHeaders> ObjectSegment<'data> for PeSegment<'data, #[inline] fn name(&self) -> Result> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; Ok(Some( str::from_utf8(name) .ok() @@ -218,7 +218,7 @@ impl<'data, 'file, Pe: ImageNtHeaders> ObjectSection<'data> for PeSection<'data, #[inline] fn name(&self) -> Result<&str> { - let name = self.section.name(self.file.symbols.strings())?; + let name = self.section.name(self.file.common.symbols.strings())?; str::from_utf8(name) .ok() .read_error("Non UTF-8 PE section name") diff --git a/vendor/object-0.20.0/src/read/traits.rs b/vendor/object/src/read/traits.rs similarity index 57% rename from vendor/object-0.20.0/src/read/traits.rs rename to vendor/object/src/read/traits.rs index 6a9d0d6028..0440db10c1 100644 --- a/vendor/object-0.20.0/src/read/traits.rs +++ b/vendor/object/src/read/traits.rs @@ -1,13 +1,15 @@ use alloc::borrow::Cow; +use alloc::vec::Vec; use crate::read::{ - self, Architecture, CompressedData, FileFlags, Relocation, Result, SectionFlags, SectionIndex, - SectionKind, Symbol, SymbolIndex, SymbolMap, + self, Architecture, ComdatKind, CompressedData, FileFlags, ObjectMap, Relocation, Result, + SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, + SymbolMapName, SymbolScope, SymbolSection, }; use crate::Endianness; /// An object file. -pub trait Object<'data, 'file>: read::private::Sealed { +pub trait Object<'data: 'file, 'file>: read::private::Sealed { /// A segment in the object file. type Segment: ObjectSegment<'data>; @@ -20,8 +22,24 @@ pub trait Object<'data, 'file>: read::private::Sealed { /// An iterator over the sections in the object file. type SectionIterator: Iterator; - /// An iterator over the symbols in the object file. - type SymbolIterator: Iterator)>; + /// A COMDAT section group in the object file. + type Comdat: ObjectComdat<'data>; + + /// An iterator over the COMDAT section groups in the object file. + type ComdatIterator: Iterator; + + /// A symbol in the object file. + type Symbol: ObjectSymbol<'data>; + + /// An iterator over symbols in the object file. + type SymbolIterator: Iterator; + + /// A symbol table in the object file. + type SymbolTable: ObjectSymbolTable< + 'data, + Symbol = Self::Symbol, + SymbolIterator = Self::SymbolIterator, + >; /// Get the architecture type of the file. fn architecture(&self) -> Architecture; @@ -76,49 +94,61 @@ pub trait Object<'data, 'file>: read::private::Sealed { /// Get an iterator over the sections in the file. fn sections(&'file self) -> Self::SectionIterator; + /// Get an iterator over the COMDAT section groups in the file. + fn comdats(&'file self) -> Self::ComdatIterator; + + /// Get the symbol table, if any. + fn symbol_table(&'file self) -> Option; + /// Get the debugging symbol at the given index. /// /// The meaning of the index depends on the object file. /// /// Returns an error if the index is invalid. - fn symbol_by_index(&self, index: SymbolIndex) -> Result>; + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result; /// Get an iterator over the debugging symbols in the file. /// /// This may skip over symbols that are malformed or unsupported. + /// + /// For Mach-O files, this does not include STAB entries. fn symbols(&'file self) -> Self::SymbolIterator; - /// Get the data for the given symbol. + /// Get the dynamic linking symbol table, if any. + /// + /// Only ELF has a separate dynamic linking symbol table. + fn dynamic_symbol_table(&'file self) -> Option; + + /// Get an iterator over the dynamic linking symbols in the file. /// - /// This may iterate over segments. + /// This may skip over symbols that are malformed or unsupported. + fn dynamic_symbols(&'file self) -> Self::SymbolIterator; + + /// Construct a map from addresses to symbol names. /// - /// Returns `Ok(None)` for undefined symbols or if the data could not be found. - fn symbol_data(&'file self, symbol: &Symbol<'data>) -> Result> { - if symbol.is_undefined() { - return Ok(None); - } - let address = symbol.address(); - let size = symbol.size(); - if let Some(index) = symbol.section_index() { - let section = self.section_by_index(index)?; - section.data_range(address, size) - } else { - for segment in self.segments() { - if let Some(data) = segment.data_range(address, size)? { - return Ok(Some(data)); + /// The map will only contain defined text and data symbols. + /// The dynamic symbol table will only be used if there are no debugging symbols. + fn symbol_map(&'file self) -> SymbolMap> { + let mut symbols = Vec::new(); + if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) { + for symbol in table.symbols() { + if !symbol.is_definition() { + continue; + } + if let Ok(name) = symbol.name() { + symbols.push(SymbolMapName::new(symbol.address(), name)); } } - Ok(None) } + SymbolMap::new(symbols) } - /// Get an iterator over the dynamic linking symbols in the file. + /// Construct a map from addresses to symbol names and object file names. /// - /// This may skip over symbols that are malformed or unsupported. - fn dynamic_symbols(&'file self) -> Self::SymbolIterator; - - /// Construct a map from addresses to symbols. - fn symbol_map(&self) -> SymbolMap<'data>; + /// This is derived from Mach-O STAB entries. + fn object_map(&'file self) -> ObjectMap<'data> { + ObjectMap::default() + } /// Return true if the file contains debug information sections, false if not. fn has_debug_symbols(&self) -> bool; @@ -245,3 +275,99 @@ pub trait ObjectSection<'data>: read::private::Sealed { /// Section flags that are specific to each file format. fn flags(&self) -> SectionFlags; } + +/// A COMDAT section group defined in an object file. +pub trait ObjectComdat<'data>: read::private::Sealed { + /// An iterator over the sections in the object file. + type SectionIterator: Iterator; + + /// Returns the COMDAT selection kind. + fn kind(&self) -> ComdatKind; + + /// Returns the index of the symbol used for the name of COMDAT section group. + fn symbol(&self) -> SymbolIndex; + + /// Returns the name of the COMDAT section group. + fn name(&self) -> Result<&str>; + + /// Get the sections in this section group. + fn sections(&self) -> Self::SectionIterator; +} + +/// A symbol table. +pub trait ObjectSymbolTable<'data>: read::private::Sealed { + /// A symbol table entry. + type Symbol: ObjectSymbol<'data>; + + /// An iterator over the symbols in a symbol table. + type SymbolIterator: Iterator; + + /// Get an iterator over the symbols in the table. + /// + /// This may skip over symbols that are malformed or unsupported. + fn symbols(&self) -> Self::SymbolIterator; + + /// Get the symbol at the given index. + /// + /// The meaning of the index depends on the object file. + /// + /// Returns an error if the index is invalid. + fn symbol_by_index(&self, index: SymbolIndex) -> Result; +} + +/// A symbol table entry. +pub trait ObjectSymbol<'data>: read::private::Sealed { + /// The index of the symbol. + fn index(&self) -> SymbolIndex; + + /// The name of the symbol. + fn name(&self) -> Result<&'data str>; + + /// The address of the symbol. May be zero if the address is unknown. + fn address(&self) -> u64; + + /// The size of the symbol. May be zero if the size is unknown. + fn size(&self) -> u64; + + /// Return the kind of this symbol. + fn kind(&self) -> SymbolKind; + + /// Returns the section where the symbol is defined. + fn section(&self) -> SymbolSection; + + /// Returns the section index for the section containing this symbol. + /// + /// May return `None` if the symbol is not defined in a section. + fn section_index(&self) -> Option { + self.section().index() + } + + /// Return true if the symbol is undefined. + fn is_undefined(&self) -> bool; + + /// Return true if the symbol is a definition of a function or data object + /// that has a known address. + fn is_definition(&self) -> bool; + + /// Return true if the symbol is common data. + /// + /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. + fn is_common(&self) -> bool; + + /// Return true if the symbol is weak. + fn is_weak(&self) -> bool; + + /// Returns the symbol scope. + fn scope(&self) -> SymbolScope; + + /// Return true if the symbol visible outside of the compilation unit. + /// + /// This treats `SymbolScope::Unknown` as global. + fn is_global(&self) -> bool; + + /// Return true if the symbol is only visible within the compilation unit. + fn is_local(&self) -> bool; + + /// Symbol flags that are specific to each file format. + fn flags(&self) -> SymbolFlags; +} diff --git a/vendor/object-0.20.0/src/read/util.rs b/vendor/object/src/read/util.rs similarity index 100% rename from vendor/object-0.20.0/src/read/util.rs rename to vendor/object/src/read/util.rs diff --git a/vendor/object-0.20.0/src/read/wasm.rs b/vendor/object/src/read/wasm.rs similarity index 76% rename from vendor/object-0.20.0/src/read/wasm.rs rename to vendor/object/src/read/wasm.rs index 4d1dba58b1..89e10d3dee 100644 --- a/vendor/object-0.20.0/src/read/wasm.rs +++ b/vendor/object/src/read/wasm.rs @@ -10,9 +10,10 @@ use core::{slice, str}; use wasmparser as wp; use crate::read::{ - self, Architecture, CompressedData, Error, FileFlags, Object, ObjectSection, ObjectSegment, - ReadError, Relocation, Result, SectionFlags, SectionIndex, SectionKind, Symbol, SymbolFlags, - SymbolIndex, SymbolKind, SymbolMap, SymbolScope, SymbolSection, + self, Architecture, ComdatKind, CompressedData, Error, FileFlags, Object, ObjectComdat, + ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadError, Relocation, Result, + SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, + SymbolSection, }; const SECTION_CUSTOM: usize = 0; @@ -41,7 +42,7 @@ pub struct WasmFile<'data> { // Whether the file has DWARF information. has_debug_symbols: bool, // Symbols collected from imports, exports, code and name sections. - symbols: Vec>, + symbols: Vec>, // Address of the function body for the entry point. entry: u64, } @@ -66,15 +67,13 @@ impl<'data> WasmFile<'data> { let mut file = WasmFile::default(); - let mut main_file_symbol = Some(Symbol { - name: None, + let mut main_file_symbol = Some(WasmSymbolInternal { + name: "", address: 0, size: 0, kind: SymbolKind::File, section: SymbolSection::None, - weak: false, scope: SymbolScope::Compilation, - flags: SymbolFlags::None, }); let mut imported_funcs_count = 0; @@ -93,20 +92,18 @@ impl<'data> WasmFile<'data> { .read_error("Couldn't read header of the import section")? { let import = import.read_error("Couldn't read an import item")?; - let module_name = Some(import.module); + let module_name = import.module; - if last_module_name != module_name { - file.symbols.push(Symbol { + if last_module_name != Some(module_name) { + file.symbols.push(WasmSymbolInternal { name: module_name, address: 0, size: 0, kind: SymbolKind::File, section: SymbolSection::None, - weak: false, scope: SymbolScope::Dynamic, - flags: SymbolFlags::None, }); - last_module_name = module_name; + last_module_name = Some(module_name); } let kind = match import.ty { @@ -119,15 +116,13 @@ impl<'data> WasmFile<'data> { | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data, }; - file.symbols.push(Symbol { - name: Some(import.field), + file.symbols.push(WasmSymbolInternal { + name: import.field, address: 0, size: 0, kind, section: SymbolSection::Undefined, - weak: false, scope: SymbolScope::Dynamic, - flags: SymbolFlags::None, }); } } @@ -176,15 +171,13 @@ impl<'data> WasmFile<'data> { | wp::ExternalKind::Global => (SymbolKind::Data, SECTION_DATA), }; - file.symbols.push(Symbol { - name: Some(export.field), + file.symbols.push(WasmSymbolInternal { + name: export.field, address: 0, size: 0, kind, section: SymbolSection::Section(SectionIndex(section_idx)), - weak: false, scope: SymbolScope::Dynamic, - flags: SymbolFlags::None, }); } } @@ -222,15 +215,13 @@ impl<'data> WasmFile<'data> { *local_func_kind = LocalFunctionKind::Local { symbol_id: file.symbols.len() as u32, }; - file.symbols.push(Symbol { - section: SymbolSection::Section(SectionIndex(SECTION_CODE)), + file.symbols.push(WasmSymbolInternal { + name: "", address, size, kind: SymbolKind::Text, - name: None, - weak: false, + section: SymbolSection::Section(SectionIndex(SECTION_CODE)), scope: SymbolScope::Compilation, - flags: SymbolFlags::None, }); } LocalFunctionKind::Exported { symbol_ids } => { @@ -270,7 +261,7 @@ impl<'data> WasmFile<'data> { if let LocalFunctionKind::Local { symbol_id } = local_func_kinds[local_index as usize] { - file.symbols[symbol_id as usize].name = Some(naming.name); + file.symbols[symbol_id as usize].name = naming.name; } } } @@ -302,7 +293,11 @@ where type SegmentIterator = WasmSegmentIterator<'data, 'file>; type Section = WasmSection<'data, 'file>; type SectionIterator = WasmSectionIterator<'data, 'file>; + type Comdat = WasmComdat<'data, 'file>; + type ComdatIterator = WasmComdatIterator<'data, 'file>; + type Symbol = WasmSymbol<'data, 'file>; type SymbolIterator = WasmSymbolIterator<'data, 'file>; + type SymbolTable = WasmSymbolTable<'data, 'file>; #[inline] fn architecture(&self) -> Architecture { @@ -350,12 +345,17 @@ where } } + fn comdats(&'file self) -> Self::ComdatIterator { + WasmComdatIterator { file: self } + } + #[inline] - fn symbol_by_index(&self, index: SymbolIndex) -> Result> { - self.symbols + fn symbol_by_index(&'file self, index: SymbolIndex) -> Result> { + let symbol = self + .symbols .get(index.0) - .cloned() - .read_error("Invalid Wasm symbol index") + .read_error("Invalid Wasm symbol index")?; + Ok(WasmSymbol { index, symbol }) } fn symbols(&'file self) -> Self::SymbolIterator { @@ -364,16 +364,21 @@ where } } + fn symbol_table(&'file self) -> Option> { + Some(WasmSymbolTable { + symbols: &self.symbols, + }) + } + fn dynamic_symbols(&'file self) -> Self::SymbolIterator { WasmSymbolIterator { symbols: [].iter().enumerate(), } } - fn symbol_map(&self) -> SymbolMap<'data> { - SymbolMap { - symbols: self.symbols.clone(), - } + #[inline] + fn dynamic_symbol_table(&'file self) -> Option> { + None } fn has_debug_symbols(&self) -> bool { @@ -575,18 +580,203 @@ impl<'data, 'file> ObjectSection<'data> for WasmSection<'data, 'file> { } } +/// An iterator over the COMDAT section groups of a `WasmFile`. +#[derive(Debug)] +pub struct WasmComdatIterator<'data, 'file> { + file: &'file WasmFile<'data>, +} + +impl<'data, 'file> Iterator for WasmComdatIterator<'data, 'file> { + type Item = WasmComdat<'data, 'file>; + + #[inline] + fn next(&mut self) -> Option { + None + } +} + +/// A COMDAT section group of a `WasmFile`. +#[derive(Debug)] +pub struct WasmComdat<'data, 'file> { + file: &'file WasmFile<'data>, +} + +impl<'data, 'file> read::private::Sealed for WasmComdat<'data, 'file> {} + +impl<'data, 'file> ObjectComdat<'data> for WasmComdat<'data, 'file> { + type SectionIterator = WasmComdatSectionIterator<'data, 'file>; + + #[inline] + fn kind(&self) -> ComdatKind { + unreachable!(); + } + + #[inline] + fn symbol(&self) -> SymbolIndex { + unreachable!(); + } + + #[inline] + fn name(&self) -> Result<&str> { + unreachable!(); + } + + #[inline] + fn sections(&self) -> Self::SectionIterator { + unreachable!(); + } +} + +/// An iterator over the sections in a COMDAT section group of a `WasmFile`. +#[derive(Debug)] +pub struct WasmComdatSectionIterator<'data, 'file> +where + 'data: 'file, +{ + file: &'file WasmFile<'data>, +} + +impl<'data, 'file> Iterator for WasmComdatSectionIterator<'data, 'file> { + type Item = SectionIndex; + + fn next(&mut self) -> Option { + None + } +} + +/// A symbol table of a `WasmFile`. +#[derive(Debug)] +pub struct WasmSymbolTable<'data, 'file> { + symbols: &'file [WasmSymbolInternal<'data>], +} + +impl<'data, 'file> read::private::Sealed for WasmSymbolTable<'data, 'file> {} + +impl<'data, 'file> ObjectSymbolTable<'data> for WasmSymbolTable<'data, 'file> { + type Symbol = WasmSymbol<'data, 'file>; + type SymbolIterator = WasmSymbolIterator<'data, 'file>; + + fn symbols(&self) -> Self::SymbolIterator { + WasmSymbolIterator { + symbols: self.symbols.iter().enumerate(), + } + } + + fn symbol_by_index(&self, index: SymbolIndex) -> Result { + let symbol = self + .symbols + .get(index.0) + .read_error("Invalid Wasm symbol index")?; + Ok(WasmSymbol { index, symbol }) + } +} + /// An iterator over the symbols of a `WasmFile`. #[derive(Debug)] pub struct WasmSymbolIterator<'data, 'file> { - symbols: core::iter::Enumerate>>, + symbols: core::iter::Enumerate>>, } impl<'data, 'file> Iterator for WasmSymbolIterator<'data, 'file> { - type Item = (SymbolIndex, Symbol<'data>); + type Item = WasmSymbol<'data, 'file>; fn next(&mut self) -> Option { let (index, symbol) = self.symbols.next()?; - Some((SymbolIndex(index), symbol.clone())) + Some(WasmSymbol { + index: SymbolIndex(index), + symbol, + }) + } +} + +/// A symbol of a `WasmFile`. +#[derive(Clone, Copy, Debug)] +pub struct WasmSymbol<'data, 'file> { + index: SymbolIndex, + symbol: &'file WasmSymbolInternal<'data>, +} + +#[derive(Clone, Debug)] +struct WasmSymbolInternal<'data> { + name: &'data str, + address: u64, + size: u64, + kind: SymbolKind, + section: SymbolSection, + scope: SymbolScope, +} + +impl<'data, 'file> read::private::Sealed for WasmSymbol<'data, 'file> {} + +impl<'data, 'file> ObjectSymbol<'data> for WasmSymbol<'data, 'file> { + #[inline] + fn index(&self) -> SymbolIndex { + self.index + } + + #[inline] + fn name(&self) -> read::Result<&'data str> { + Ok(self.symbol.name) + } + + #[inline] + fn address(&self) -> u64 { + self.symbol.address + } + + #[inline] + fn size(&self) -> u64 { + self.symbol.size + } + + #[inline] + fn kind(&self) -> SymbolKind { + self.symbol.kind + } + + #[inline] + fn section(&self) -> SymbolSection { + self.symbol.section + } + + #[inline] + fn is_undefined(&self) -> bool { + self.symbol.section == SymbolSection::Undefined + } + + #[inline] + fn is_definition(&self) -> bool { + self.symbol.kind == SymbolKind::Text && self.symbol.section != SymbolSection::Undefined + } + + #[inline] + fn is_common(&self) -> bool { + self.symbol.section == SymbolSection::Common + } + + #[inline] + fn is_weak(&self) -> bool { + false + } + + #[inline] + fn scope(&self) -> SymbolScope { + self.symbol.scope + } + + #[inline] + fn is_global(&self) -> bool { + self.symbol.scope != SymbolScope::Compilation + } + + #[inline] + fn is_local(&self) -> bool { + self.symbol.scope == SymbolScope::Compilation + } + + #[inline] + fn flags(&self) -> SymbolFlags { + SymbolFlags::None } } diff --git a/vendor/object-0.20.0/src/write/coff.rs b/vendor/object/src/write/coff.rs similarity index 87% rename from vendor/object-0.20.0/src/write/coff.rs rename to vendor/object/src/write/coff.rs index 888beb8829..c103d929c5 100644 --- a/vendor/object-0.20.0/src/write/coff.rs +++ b/vendor/object/src/write/coff.rs @@ -4,7 +4,7 @@ use std::vec::Vec; use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32}; use crate::pe as coff; -use crate::pod::BytesMut; +use crate::pod::{bytes_of, WritableBuffer}; use crate::write::string::*; use crate::write::util::*; use crate::write::*; @@ -14,6 +14,8 @@ struct SectionOffsets { offset: usize, str_id: Option, reloc_offset: usize, + selection: u8, + associative_section: u16, } #[derive(Default, Clone, Copy)] @@ -137,7 +139,7 @@ impl Object { stub_id } - pub(crate) fn coff_write(&self) -> Result> { + pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { // Calculate offsets of everything, and build strtab. let mut offset = 0; let mut strtab = StringTable::default(); @@ -173,6 +175,49 @@ impl Object { } } + // Set COMDAT flags. + for comdat in &self.comdats { + let symbol = &self.symbols[comdat.symbol.0]; + let comdat_section = match symbol.section { + SymbolSection::Section(id) => id.0, + _ => { + return Err(Error(format!( + "unsupported COMDAT symbol `{}` section {:?}", + symbol.name().unwrap_or(""), + symbol.section + ))); + } + }; + section_offsets[comdat_section].selection = match comdat.kind { + ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES, + ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY, + ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE, + ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH, + ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST, + ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST, + ComdatKind::Unknown => { + return Err(Error(format!( + "unsupported COMDAT symbol `{}` kind {:?}", + symbol.name().unwrap_or(""), + comdat.kind + ))); + } + }; + for id in &comdat.sections { + let section = &self.sections[id.0]; + if section.symbol.is_none() { + return Err(Error(format!( + "missing symbol for COMDAT section `{}`", + section.name().unwrap_or(""), + ))); + } + if id.0 != comdat_section { + section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE; + section_offsets[id.0].associative_section = comdat_section as u16 + 1; + } + } + } + // Calculate size of symbols and add symbol strings to strtab. let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; let mut symtab_count = 0; @@ -214,7 +259,9 @@ impl Object { offset += strtab_len; // Start writing. - let mut buffer = BytesMut(Vec::with_capacity(offset)); + buffer + .reserve(offset) + .map_err(|_| Error(String::from("Cannot allocate buffer")))?; // Write file header. let header = coff::ImageFileHeader { @@ -241,17 +288,20 @@ impl Object { _ => U16::default(), }, }; - buffer.write(&header); + buffer.extend(bytes_of(&header)); // Write section headers. for (index, section) in self.sections.iter().enumerate() { - // TODO: IMAGE_SCN_LNK_COMDAT - let characteristics = match section.flags { + let mut characteristics = match section.flags { SectionFlags::Coff { characteristics, .. } => characteristics, _ => 0, - } | match section.kind { + }; + if section_offsets[index].selection != 0 { + characteristics |= coff::IMAGE_SCN_LNK_COMDAT; + }; + characteristics |= match section.kind { SectionKind::Text => { coff::IMAGE_SCN_CNT_CODE | coff::IMAGE_SCN_MEM_EXECUTE @@ -365,16 +415,16 @@ impl Object { return Err(Error(format!("invalid section name offset {}", str_offset))); } } - buffer.write(&coff_section); + buffer.extend(bytes_of(&coff_section)); } // Write section data and relocations. for (index, section) in self.sections.iter().enumerate() { let len = section.data.len(); if len != 0 { - write_align(&mut buffer, 4); + write_align(buffer, 4); debug_assert_eq!(section_offsets[index].offset, buffer.len()); - buffer.write_bytes(§ion.data); + buffer.extend(section.data.as_slice()); } if !section.relocations.is_empty() { @@ -429,7 +479,7 @@ impl Object { ), typ: U16Bytes::new(LE, typ), }; - buffer.write(&coff_relocation); + buffer.extend(bytes_of(&coff_relocation)); } } } @@ -519,7 +569,7 @@ impl Object { let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32)); } - buffer.write(&coff_symbol); + buffer.extend(bytes_of(&coff_symbol)); // Write auxiliary symbols. match symbol.kind { @@ -532,26 +582,23 @@ impl Object { } SymbolKind::Section => { debug_assert_eq!(number_of_aux_symbols, 1); - let section = &self.sections[symbol.section.id().unwrap().0]; - let (selection, number) = match symbol.flags { - SymbolFlags::CoffSection { - selection, - associative_section, - } => (selection, associative_section.0 as u16), - _ => (0, 0), - }; + let section_index = symbol.section.id().unwrap().0; + let section = &self.sections[section_index]; let aux = coff::ImageAuxSymbolSection { length: U32Bytes::new(LE, section.size as u32), number_of_relocations: U16Bytes::new(LE, section.relocations.len() as u16), number_of_linenumbers: U16Bytes::default(), - check_sum: U32Bytes::new(LE, checksum(§ion.data.0)), - number: U16Bytes::new(LE, number), - selection, + check_sum: U32Bytes::new(LE, checksum(section.data.as_slice())), + number: U16Bytes::new( + LE, + section_offsets[section_index].associative_section, + ), + selection: section_offsets[section_index].selection, reserved: 0, // TODO: bigobj high_number: U16Bytes::default(), }; - buffer.write(&aux); + buffer.extend(bytes_of(&aux)); } _ => { debug_assert_eq!(number_of_aux_symbols, 0); @@ -564,7 +611,9 @@ impl Object { buffer.extend(&u32::to_le_bytes(strtab_len as u32)); buffer.extend(&strtab_data); - Ok(buffer.0) + debug_assert_eq!(offset, buffer.len()); + + Ok(()) } } diff --git a/vendor/object-0.20.0/src/write/elf.rs b/vendor/object/src/write/elf.rs similarity index 80% rename from vendor/object-0.20.0/src/write/elf.rs rename to vendor/object/src/write/elf.rs index e90ba63ea6..ef8069d9b8 100644 --- a/vendor/object-0.20.0/src/write/elf.rs +++ b/vendor/object/src/write/elf.rs @@ -3,11 +3,18 @@ use std::vec::Vec; use crate::elf; use crate::endian::*; -use crate::pod::BytesMut; +use crate::pod::{bytes_of, BytesMut, WritableBuffer}; use crate::write::string::*; use crate::write::util::*; use crate::write::*; +#[derive(Default, Clone, Copy)] +struct ComdatOffsets { + offset: usize, + str_id: Option, + len: usize, +} + #[derive(Default, Clone, Copy)] struct SectionOffsets { index: usize, @@ -68,6 +75,7 @@ impl Object { Architecture::Aarch64 => true, Architecture::I386 => false, Architecture::X86_64 => true, + Architecture::S390x => true, _ => { return Err(Error(format!( "unimplemented architecture {:?}", @@ -132,7 +140,7 @@ impl Object { } } - pub(crate) fn elf_write(&self) -> Result> { + pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { let address_size = self.architecture.address_size().unwrap(); let endian = self.endian; let elf32 = Elf32 { endian }; @@ -171,9 +179,27 @@ impl Object { // Calculate size of section data. let mut shstrtab = StringTable::default(); + let mut comdat_offsets = vec![ComdatOffsets::default(); self.comdats.len()]; let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; // Null section. let mut section_num = 1; + for (index, comdat) in self.comdats.iter().enumerate() { + if comdat.kind != ComdatKind::Any { + return Err(Error(format!( + "unsupported COMDAT symbol `{}` kind {:?}", + self.symbols[comdat.symbol.0].name().unwrap_or(""), + comdat.kind + ))); + } + + comdat_offsets[index].str_id = Some(shstrtab.add(b".group")); + section_num += 1; + offset = align(offset, 4); + comdat_offsets[index].offset = offset; + let len = (comdat.sections.len() + 1) * 4; + comdat_offsets[index].len = len; + offset += len; + } for (index, section) in self.sections.iter().enumerate() { section_offsets[index].str_id = Some(shstrtab.add(§ion.name)); section_offsets[index].index = section_num; @@ -293,7 +319,9 @@ impl Object { offset += section_num * e_shentsize; // Start writing. - let mut buffer = BytesMut(Vec::with_capacity(offset)); + buffer + .reserve(offset) + .map_err(|_| Error(String::from("Cannot allocate buffer")))?; // Write file header. let e_ident = elf::Ident { @@ -318,6 +346,7 @@ impl Object { Architecture::Aarch64 => elf::EM_AARCH64, Architecture::I386 => elf::EM_386, Architecture::X86_64 => elf::EM_X86_64, + Architecture::S390x => elf::EM_S390, _ => { return Err(Error(format!( "unimplemented architecture {:?}", @@ -342,7 +371,7 @@ impl Object { }; elf.write_file_header( - &mut buffer, + buffer, FileHeader { e_ident, e_type, @@ -362,20 +391,32 @@ impl Object { ); // Write section data. + for (index, comdat) in self.comdats.iter().enumerate() { + let mut data = BytesMut::new(); + data.write(&U32::new(endian, elf::GRP_COMDAT)); + for section in &comdat.sections { + data.write(&U32::new(endian, section_offsets[section.0].index as u32)); + } + + write_align(buffer, 4); + debug_assert_eq!(comdat_offsets[index].offset, buffer.len()); + debug_assert_eq!(comdat_offsets[index].len, data.len()); + buffer.extend(data.as_slice()); + } for (index, section) in self.sections.iter().enumerate() { let len = section.data.len(); if len != 0 { - write_align(&mut buffer, section.align as usize); + write_align(buffer, section.align as usize); debug_assert_eq!(section_offsets[index].offset, buffer.len()); - buffer.write_bytes(§ion.data); + buffer.extend(section.data.as_slice()); } } // Write symbols. - write_align(&mut buffer, pointer_align); + write_align(buffer, pointer_align); debug_assert_eq!(symtab_offset, buffer.len()); elf.write_symbol( - &mut buffer, + buffer, Sym { st_name: 0, st_info: 0, @@ -427,12 +468,12 @@ impl Object { } } }; - let st_bind = if symbol.is_undefined() { + let st_bind = if symbol.weak { + elf::STB_WEAK + } else if symbol.is_undefined() { elf::STB_GLOBAL } else if symbol.is_local() { elf::STB_LOCAL - } else if symbol.weak { - elf::STB_WEAK } else { elf::STB_GLOBAL }; @@ -470,7 +511,7 @@ impl Object { .map(|id| strtab.get_offset(id)) .unwrap_or(0) as u32; elf.write_symbol( - &mut buffer, + buffer, Sym { st_name, st_info, @@ -498,7 +539,7 @@ impl Object { if need_symtab_shndx { debug_assert_eq!(symtab_shndx_offset, buffer.len()); debug_assert_eq!(symtab_shndx_len, symtab_shndx.len()); - buffer.write_bytes(&symtab_shndx); + buffer.extend(symtab_shndx.as_slice()); } // Write strtab section. @@ -508,7 +549,7 @@ impl Object { // Write relocations. for (index, section) in self.sections.iter().enumerate() { if !section.relocations.is_empty() { - write_align(&mut buffer, pointer_align); + write_align(buffer, pointer_align); debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); for reloc in §ion.relocations { let r_type = match self.architecture { @@ -563,6 +604,72 @@ impl Object { return Err(Error(format!("unimplemented relocation {:?}", reloc))); } }, + Architecture::S390x => match (reloc.kind, reloc.encoding, reloc.size) { + (RelocationKind::Absolute, RelocationEncoding::Generic, 8) => { + elf::R_390_8 + } + (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { + elf::R_390_16 + } + (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { + elf::R_390_32 + } + (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => { + elf::R_390_64 + } + (RelocationKind::Relative, RelocationEncoding::Generic, 16) => { + elf::R_390_PC16 + } + (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { + elf::R_390_PC32 + } + (RelocationKind::Relative, RelocationEncoding::Generic, 64) => { + elf::R_390_PC64 + } + (RelocationKind::Relative, RelocationEncoding::S390xDbl, 16) => { + elf::R_390_PC16DBL + } + (RelocationKind::Relative, RelocationEncoding::S390xDbl, 32) => { + elf::R_390_PC32DBL + } + (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 16) => { + elf::R_390_PLT16DBL + } + (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 32) => { + elf::R_390_PLT32DBL + } + (RelocationKind::Got, RelocationEncoding::Generic, 16) => { + elf::R_390_GOT16 + } + (RelocationKind::Got, RelocationEncoding::Generic, 32) => { + elf::R_390_GOT32 + } + (RelocationKind::Got, RelocationEncoding::Generic, 64) => { + elf::R_390_GOT64 + } + (RelocationKind::GotRelative, RelocationEncoding::S390xDbl, 32) => { + elf::R_390_GOTENT + } + (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 16) => { + elf::R_390_GOTOFF16 + } + (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 32) => { + elf::R_390_GOTOFF32 + } + (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 64) => { + elf::R_390_GOTOFF64 + } + (RelocationKind::GotBaseRelative, RelocationEncoding::Generic, 64) => { + elf::R_390_GOTPC + } + (RelocationKind::GotBaseRelative, RelocationEncoding::S390xDbl, 32) => { + elf::R_390_GOTPCDBL + } + (RelocationKind::Elf(x), _, _) => x, + _ => { + return Err(Error(format!("unimplemented relocation {:?}", reloc))); + } + }, _ => { return Err(Error(format!( "unimplemented architecture {:?}", @@ -572,7 +679,7 @@ impl Object { }; let r_sym = symbol_offsets[reloc.symbol.0].index as u32; elf.write_rel( - &mut buffer, + buffer, is_rela, Rel { r_offset: reloc.offset, @@ -590,10 +697,10 @@ impl Object { buffer.extend(&shstrtab_data); // Write section headers. - write_align(&mut buffer, pointer_align); + write_align(buffer, pointer_align); debug_assert_eq!(e_shoff, buffer.len()); elf.write_section_header( - &mut buffer, + buffer, SectionHeader { sh_name: 0, sh_type: 0, @@ -616,6 +723,27 @@ impl Object { sh_entsize: 0, }, ); + for (index, comdat) in self.comdats.iter().enumerate() { + let sh_name = comdat_offsets[index] + .str_id + .map(|id| shstrtab.get_offset(id)) + .unwrap_or(0) as u32; + elf.write_section_header( + buffer, + SectionHeader { + sh_name, + sh_type: elf::SHT_GROUP, + sh_flags: 0, + sh_addr: 0, + sh_offset: comdat_offsets[index].offset as u64, + sh_size: comdat_offsets[index].len as u64, + sh_link: symtab_index as u32, + sh_info: symbol_offsets[comdat.symbol.0].index as u32, + sh_addralign: 4, + sh_entsize: 4, + }, + ); + } for (index, section) in self.sections.iter().enumerate() { let sh_type = match section.kind { SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS, @@ -661,7 +789,7 @@ impl Object { .map(|id| shstrtab.get_offset(id)) .unwrap_or(0) as u32; elf.write_section_header( - &mut buffer, + buffer, SectionHeader { sh_name, sh_type, @@ -682,7 +810,7 @@ impl Object { .map(|id| shstrtab.get_offset(id)) .unwrap_or(0); elf.write_section_header( - &mut buffer, + buffer, SectionHeader { sh_name: sh_name as u32, sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL }, @@ -701,7 +829,7 @@ impl Object { // Write symtab section header. elf.write_section_header( - &mut buffer, + buffer, SectionHeader { sh_name: shstrtab.get_offset(symtab_str_id) as u32, sh_type: elf::SHT_SYMTAB, @@ -719,7 +847,7 @@ impl Object { // Write symtab_shndx section header. if need_symtab_shndx { elf.write_section_header( - &mut buffer, + buffer, SectionHeader { sh_name: shstrtab.get_offset(symtab_shndx_str_id.unwrap()) as u32, sh_type: elf::SHT_SYMTAB_SHNDX, @@ -737,7 +865,7 @@ impl Object { // Write strtab section header. elf.write_section_header( - &mut buffer, + buffer, SectionHeader { sh_name: shstrtab.get_offset(strtab_str_id) as u32, sh_type: elf::SHT_STRTAB, @@ -754,7 +882,7 @@ impl Object { // Write shstrtab section header. elf.write_section_header( - &mut buffer, + buffer, SectionHeader { sh_name: shstrtab.get_offset(shstrtab_str_id) as u32, sh_type: elf::SHT_STRTAB, @@ -769,7 +897,9 @@ impl Object { }, ); - Ok(buffer.0) + debug_assert_eq!(offset, buffer.len()); + + Ok(()) } } @@ -828,10 +958,10 @@ trait Elf { fn section_header_size(&self) -> usize; fn symbol_size(&self) -> usize; fn rel_size(&self, is_rela: bool) -> usize; - fn write_file_header(&self, buffer: &mut BytesMut, section: FileHeader); - fn write_section_header(&self, buffer: &mut BytesMut, section: SectionHeader); - fn write_symbol(&self, buffer: &mut BytesMut, symbol: Sym); - fn write_rel(&self, buffer: &mut BytesMut, is_rela: bool, rel: Rel); + fn write_file_header(&self, buffer: &mut dyn WritableBuffer, section: FileHeader); + fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader); + fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym); + fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel); } struct Elf32 { @@ -859,7 +989,7 @@ impl Elf for Elf32 { } } - fn write_file_header(&self, buffer: &mut BytesMut, file: FileHeader) { + fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) { let endian = self.endian; let file = elf::FileHeader32 { e_ident: file.e_ident, @@ -877,10 +1007,10 @@ impl Elf for Elf32 { e_shnum: U16::new(endian, file.e_shnum), e_shstrndx: U16::new(endian, file.e_shstrndx), }; - buffer.write(&file); + buffer.extend(bytes_of(&file)); } - fn write_section_header(&self, buffer: &mut BytesMut, section: SectionHeader) { + fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { let endian = self.endian; let section = elf::SectionHeader32 { sh_name: U32::new(endian, section.sh_name), @@ -894,10 +1024,10 @@ impl Elf for Elf32 { sh_addralign: U32::new(endian, section.sh_addralign as u32), sh_entsize: U32::new(endian, section.sh_entsize as u32), }; - buffer.write(§ion); + buffer.extend(bytes_of(§ion)); } - fn write_symbol(&self, buffer: &mut BytesMut, symbol: Sym) { + fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) { let endian = self.endian; let symbol = elf::Sym32 { st_name: U32::new(endian, symbol.st_name), @@ -907,10 +1037,10 @@ impl Elf for Elf32 { st_value: U32::new(endian, symbol.st_value as u32), st_size: U32::new(endian, symbol.st_size as u32), }; - buffer.write(&symbol); + buffer.extend(bytes_of(&symbol)); } - fn write_rel(&self, buffer: &mut BytesMut, is_rela: bool, rel: Rel) { + fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) { let endian = self.endian; if is_rela { let rel = elf::Rela32 { @@ -918,13 +1048,13 @@ impl Elf for Elf32 { r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), r_addend: I32::new(endian, rel.r_addend as i32), }; - buffer.write(&rel); + buffer.extend(bytes_of(&rel)); } else { let rel = elf::Rel32 { r_offset: U32::new(endian, rel.r_offset as u32), r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), }; - buffer.write(&rel); + buffer.extend(bytes_of(&rel)); } } } @@ -954,7 +1084,7 @@ impl Elf for Elf64 { } } - fn write_file_header(&self, buffer: &mut BytesMut, file: FileHeader) { + fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) { let endian = self.endian; let file = elf::FileHeader64 { e_ident: file.e_ident, @@ -972,10 +1102,10 @@ impl Elf for Elf64 { e_shnum: U16::new(endian, file.e_shnum), e_shstrndx: U16::new(endian, file.e_shstrndx), }; - buffer.write(&file) + buffer.extend(bytes_of(&file)) } - fn write_section_header(&self, buffer: &mut BytesMut, section: SectionHeader) { + fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { let endian = self.endian; let section = elf::SectionHeader64 { sh_name: U32::new(endian, section.sh_name), @@ -989,10 +1119,10 @@ impl Elf for Elf64 { sh_addralign: U64::new(endian, section.sh_addralign), sh_entsize: U64::new(endian, section.sh_entsize), }; - buffer.write(§ion); + buffer.extend(bytes_of(§ion)); } - fn write_symbol(&self, buffer: &mut BytesMut, symbol: Sym) { + fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) { let endian = self.endian; let symbol = elf::Sym64 { st_name: U32::new(endian, symbol.st_name), @@ -1002,10 +1132,10 @@ impl Elf for Elf64 { st_value: U64::new(endian, symbol.st_value), st_size: U64::new(endian, symbol.st_size), }; - buffer.write(&symbol); + buffer.extend(bytes_of(&symbol)); } - fn write_rel(&self, buffer: &mut BytesMut, is_rela: bool, rel: Rel) { + fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) { let endian = self.endian; if is_rela { let rel = elf::Rela64 { @@ -1013,13 +1143,13 @@ impl Elf for Elf64 { r_info: elf::Rela64::r_info(endian, rel.r_sym, rel.r_type), r_addend: I64::new(endian, rel.r_addend), }; - buffer.write(&rel); + buffer.extend(bytes_of(&rel)); } else { let rel = elf::Rel64 { r_offset: U64::new(endian, rel.r_offset), r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type), }; - buffer.write(&rel); + buffer.extend(bytes_of(&rel)); } } } diff --git a/vendor/object-0.20.0/src/write/macho.rs b/vendor/object/src/write/macho.rs similarity index 93% rename from vendor/object-0.20.0/src/write/macho.rs rename to vendor/object/src/write/macho.rs index 95d07a26a3..abecc93818 100644 --- a/vendor/object-0.20.0/src/write/macho.rs +++ b/vendor/object/src/write/macho.rs @@ -3,7 +3,7 @@ use std::vec::Vec; use crate::endian::*; use crate::macho; -use crate::pod::BytesMut; +use crate::pod::{bytes_of, WritableBuffer}; use crate::write::string::*; use crate::write::util::*; use crate::write::*; @@ -185,7 +185,7 @@ impl Object { constant } - pub(crate) fn macho_write(&self) -> Result> { + pub(crate) fn macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { let address_size = self.architecture.address_size().unwrap(); let endian = self.endian; let macho32 = MachO32 { endian }; @@ -313,7 +313,9 @@ impl Object { } // Start writing. - let mut buffer = BytesMut(Vec::with_capacity(offset)); + buffer + .reserve(offset) + .map_err(|_| Error(String::from("Cannot allocate buffer")))?; // Write file header. let (cputype, cpusubtype) = match self.architecture { @@ -334,7 +336,7 @@ impl Object { _ => 0, }; macho.write_mach_header( - &mut buffer, + buffer, MachHeader { cputype, cpusubtype, @@ -348,7 +350,7 @@ impl Object { // Write segment command. debug_assert_eq!(segment_command_offset, buffer.len()); macho.write_segment_command( - &mut buffer, + buffer, SegmentCommand { cmdsize: segment_command_len as u32, segname: [0; 16], @@ -396,7 +398,7 @@ impl Object { } }; macho.write_section( - &mut buffer, + buffer, SectionHeader { sectname, segname, @@ -421,21 +423,21 @@ impl Object { stroff: U32::new(endian, strtab_offset as u32), strsize: U32::new(endian, strtab_data.len() as u32), }; - buffer.write(&symtab_command); + buffer.extend(bytes_of(&symtab_command)); // Write section data. debug_assert_eq!(segment_data_offset, buffer.len()); for (index, section) in self.sections.iter().enumerate() { let len = section.data.len(); if len != 0 { - write_align(&mut buffer, section.align as usize); + write_align(buffer, section.align as usize); debug_assert_eq!(section_offsets[index].offset, buffer.len()); - buffer.write_bytes(§ion.data); + buffer.extend(section.data.as_slice()); } } // Write symtab. - write_align(&mut buffer, pointer_align); + write_align(buffer, pointer_align); debug_assert_eq!(symtab_offset, buffer.len()); for (index, symbol) in self.symbols.iter().enumerate() { if !symbol_offsets[index].emit { @@ -489,7 +491,7 @@ impl Object { .unwrap_or(0); macho.write_nlist( - &mut buffer, + buffer, Nlist { n_strx: n_strx as u32, n_type, @@ -507,7 +509,7 @@ impl Object { // Write relocations. for (index, section) in self.sections.iter().enumerate() { if !section.relocations.is_empty() { - write_align(&mut buffer, 4); + write_align(buffer, 4); debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); for reloc in §ion.relocations { let r_extern; @@ -578,12 +580,14 @@ impl Object { r_extern, r_type, }; - buffer.write(&reloc_info.relocation(endian)); + buffer.extend(bytes_of(&reloc_info.relocation(endian))); } } } - Ok(buffer.0) + debug_assert_eq!(offset, buffer.len()); + + Ok(()) } } @@ -634,10 +638,10 @@ trait MachO { fn segment_command_size(&self) -> usize; fn section_header_size(&self) -> usize; fn nlist_size(&self) -> usize; - fn write_mach_header(&self, buffer: &mut BytesMut, section: MachHeader); - fn write_segment_command(&self, buffer: &mut BytesMut, segment: SegmentCommand); - fn write_section(&self, buffer: &mut BytesMut, section: SectionHeader); - fn write_nlist(&self, buffer: &mut BytesMut, nlist: Nlist); + fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader); + fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand); + fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader); + fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist); } struct MachO32 { @@ -661,7 +665,7 @@ impl MachO for MachO32 { mem::size_of::>() } - fn write_mach_header(&self, buffer: &mut BytesMut, header: MachHeader) { + fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { let endian = self.endian; let magic = if endian.is_big_endian() { macho::MH_MAGIC @@ -677,10 +681,10 @@ impl MachO for MachO32 { sizeofcmds: U32::new(endian, header.sizeofcmds), flags: U32::new(endian, header.flags), }; - buffer.write(&header); + buffer.extend(bytes_of(&header)); } - fn write_segment_command(&self, buffer: &mut BytesMut, segment: SegmentCommand) { + fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { let endian = self.endian; let segment = macho::SegmentCommand32 { cmd: U32::new(endian, macho::LC_SEGMENT), @@ -695,10 +699,10 @@ impl MachO for MachO32 { nsects: U32::new(endian, segment.nsects), flags: U32::new(endian, segment.flags), }; - buffer.write(&segment); + buffer.extend(bytes_of(&segment)); } - fn write_section(&self, buffer: &mut BytesMut, section: SectionHeader) { + fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { let endian = self.endian; let section = macho::Section32 { sectname: section.sectname, @@ -713,10 +717,10 @@ impl MachO for MachO32 { reserved1: U32::default(), reserved2: U32::default(), }; - buffer.write(§ion); + buffer.extend(bytes_of(§ion)); } - fn write_nlist(&self, buffer: &mut BytesMut, nlist: Nlist) { + fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { let endian = self.endian; let nlist = macho::Nlist32 { n_strx: U32::new(endian, nlist.n_strx), @@ -725,7 +729,7 @@ impl MachO for MachO32 { n_desc: U16::new(endian, nlist.n_desc), n_value: U32::new(endian, nlist.n_value as u32), }; - buffer.write(&nlist); + buffer.extend(bytes_of(&nlist)); } } @@ -750,7 +754,7 @@ impl MachO for MachO64 { mem::size_of::>() } - fn write_mach_header(&self, buffer: &mut BytesMut, header: MachHeader) { + fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { let endian = self.endian; let magic = if endian.is_big_endian() { macho::MH_MAGIC_64 @@ -767,10 +771,10 @@ impl MachO for MachO64 { flags: U32::new(endian, header.flags), reserved: U32::default(), }; - buffer.write(&header); + buffer.extend(bytes_of(&header)); } - fn write_segment_command(&self, buffer: &mut BytesMut, segment: SegmentCommand) { + fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { let endian = self.endian; let segment = macho::SegmentCommand64 { cmd: U32::new(endian, macho::LC_SEGMENT_64), @@ -785,10 +789,10 @@ impl MachO for MachO64 { nsects: U32::new(endian, segment.nsects), flags: U32::new(endian, segment.flags), }; - buffer.write(&segment); + buffer.extend(bytes_of(&segment)); } - fn write_section(&self, buffer: &mut BytesMut, section: SectionHeader) { + fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { let endian = self.endian; let section = macho::Section64 { sectname: section.sectname, @@ -804,10 +808,10 @@ impl MachO for MachO64 { reserved2: U32::default(), reserved3: U32::default(), }; - buffer.write(§ion); + buffer.extend(bytes_of(§ion)); } - fn write_nlist(&self, buffer: &mut BytesMut, nlist: Nlist) { + fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { let endian = self.endian; let nlist = macho::Nlist64 { n_strx: U32::new(endian, nlist.n_strx), @@ -816,6 +820,6 @@ impl MachO for MachO64 { n_desc: U16::new(endian, nlist.n_desc), n_value: U64Bytes::new(endian, nlist.n_value), }; - buffer.write(&nlist); + buffer.extend(bytes_of(&nlist)); } } diff --git a/vendor/object-0.20.0/src/write/mod.rs b/vendor/object/src/write/mod.rs similarity index 93% rename from vendor/object-0.20.0/src/write/mod.rs rename to vendor/object/src/write/mod.rs index 8f14438ef5..c348ee0689 100644 --- a/vendor/object-0.20.0/src/write/mod.rs +++ b/vendor/object/src/write/mod.rs @@ -12,10 +12,10 @@ use std::vec::Vec; use std::{error, fmt, result, str}; use crate::endian::{Endianness, U32, U64}; -use crate::pod::BytesMut; +use crate::pod::{BytesMut, WritableBuffer}; use crate::{ - AddressSize, Architecture, BinaryFormat, FileFlags, RelocationEncoding, RelocationKind, - SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, + AddressSize, Architecture, BinaryFormat, ComdatKind, FileFlags, RelocationEncoding, + RelocationKind, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, }; #[cfg(feature = "coff")] @@ -54,6 +54,7 @@ pub struct Object { symbols: Vec, symbol_map: HashMap, SymbolId>, stub_symbols: HashMap, + comdats: Vec, /// File flags that are specific to each file format. pub flags: FileFlags, /// The symbol name mangling scheme. @@ -74,6 +75,7 @@ impl Object { symbols: Vec::new(), symbol_map: HashMap::new(), stub_symbols: HashMap::new(), + comdats: Vec::new(), flags: FileFlags::None, mangling: Mangling::default(format, architecture), tlv_bootstrap: None, @@ -256,6 +258,25 @@ impl Object { } } + /// Get the COMDAT section group with the given `ComdatId`. + #[inline] + pub fn comdat(&self, comdat: ComdatId) -> &Comdat { + &self.comdats[comdat.0] + } + + /// Mutably get the COMDAT section group with the given `ComdatId`. + #[inline] + pub fn comdat_mut(&mut self, comdat: ComdatId) -> &mut Comdat { + &mut self.comdats[comdat.0] + } + + /// Add a new COMDAT section group and return its `ComdatId`. + pub fn add_comdat(&mut self, comdat: Comdat) -> ComdatId { + let comdat_id = ComdatId(self.comdats.len()); + self.comdats.push(comdat); + comdat_id + } + /// Get the `SymbolId` of the symbol with the given name. pub fn symbol_id(&self, name: &[u8]) -> Option { self.symbol_map.get(name).cloned() @@ -502,13 +523,20 @@ impl Object { /// Write the object to a `Vec`. pub fn write(&self) -> Result> { + let mut buffer = BytesMut::new(); + self.emit(&mut buffer)?; + Ok(buffer.0) + } + + /// Write the object to a `WritableBuffer`. + pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { match self.format { #[cfg(feature = "coff")] - BinaryFormat::Coff => self.coff_write(), + BinaryFormat::Coff => self.coff_write(buffer), #[cfg(feature = "elf")] - BinaryFormat::Elf => self.elf_write(), + BinaryFormat::Elf => self.elf_write(buffer), #[cfg(feature = "macho")] - BinaryFormat::MachO => self.macho_write(), + BinaryFormat::MachO => self.macho_write(buffer), _ => unimplemented!(), } } @@ -765,6 +793,27 @@ pub struct Relocation { pub addend: i64, } +/// An identifier used to reference a COMDAT section group. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ComdatId(usize); + +/// A COMDAT section group. +#[derive(Debug)] +pub struct Comdat { + /// The COMDAT selection kind. + /// + /// This determines the way in which the linker resolves multiple definitions of the COMDAT + /// sections. + pub kind: ComdatKind, + /// The COMDAT symbol. + /// + /// If this symbol is referenced, then all sections in the group will be included by the + /// linker. + pub symbol: SymbolId, + /// The sections in the group. + pub sections: Vec, +} + /// The symbol name mangling scheme. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Mangling { diff --git a/vendor/object-0.20.0/src/write/string.rs b/vendor/object/src/write/string.rs similarity index 100% rename from vendor/object-0.20.0/src/write/string.rs rename to vendor/object/src/write/string.rs diff --git a/vendor/object-0.20.0/src/write/util.rs b/vendor/object/src/write/util.rs similarity index 72% rename from vendor/object-0.20.0/src/write/util.rs rename to vendor/object/src/write/util.rs index cd3c2a1330..af8e4332a7 100644 --- a/vendor/object-0.20.0/src/write/util.rs +++ b/vendor/object/src/write/util.rs @@ -1,4 +1,4 @@ -use crate::pod::BytesMut; +use crate::pod::WritableBuffer; pub(crate) fn align(offset: usize, size: usize) -> usize { (offset + (size - 1)) & !(size - 1) @@ -8,7 +8,7 @@ pub(crate) fn align_u64(offset: u64, size: u64) -> u64 { (offset + (size - 1)) & !(size - 1) } -pub(crate) fn write_align(buffer: &mut BytesMut, size: usize) { +pub(crate) fn write_align(buffer: &mut dyn WritableBuffer, size: usize) { let new_len = align(buffer.len(), size); buffer.resize(new_len, 0); } diff --git a/vendor/object-0.20.0/tests/integration.rs b/vendor/object/tests/integration.rs similarity index 100% rename from vendor/object-0.20.0/tests/integration.rs rename to vendor/object/tests/integration.rs diff --git a/vendor/object-0.20.0/tests/parse_self.rs b/vendor/object/tests/parse_self.rs similarity index 100% rename from vendor/object-0.20.0/tests/parse_self.rs rename to vendor/object/tests/parse_self.rs diff --git a/vendor/object-0.20.0/tests/round_trip/bss.rs b/vendor/object/tests/round_trip/bss.rs similarity index 91% rename from vendor/object-0.20.0/tests/round_trip/bss.rs rename to vendor/object/tests/round_trip/bss.rs index 6339379ef2..b297221d6a 100644 --- a/vendor/object-0.20.0/tests/round_trip/bss.rs +++ b/vendor/object/tests/round_trip/bss.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, SectionKind, SymbolFlags, SymbolKind, SymbolScope, @@ -63,9 +63,9 @@ fn coff_x86_64_bss() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -73,9 +73,9 @@ fn coff_x86_64_bss() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.address(), 0); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -145,13 +145,13 @@ fn elf_x86_64_bss() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -160,9 +160,9 @@ fn elf_x86_64_bss() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 18); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -236,9 +236,9 @@ fn macho_x86_64_bss() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v1")); + assert_eq!(symbol.name(), Ok("_v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -246,9 +246,9 @@ fn macho_x86_64_bss() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.address(), 0); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v2")); + assert_eq!(symbol.name(), Ok("_v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(bss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); diff --git a/vendor/object/tests/round_trip/comdat.rs b/vendor/object/tests/round_trip/comdat.rs new file mode 100644 index 0000000000..eb8a1e0f7d --- /dev/null +++ b/vendor/object/tests/round_trip/comdat.rs @@ -0,0 +1,225 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::pe; +use object::read::{Object, ObjectComdat, ObjectSection, ObjectSymbol}; +use object::{read, write}; +use object::{ + Architecture, BinaryFormat, ComdatKind, Endianness, SectionKind, SymbolFlags, SymbolKind, + SymbolScope, +}; + +#[test] +fn coff_x86_64_comdat() { + let mut object = + write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); + + let (section1, offset) = + object.add_subsection(write::StandardSection::Text, b"s1", &[0, 1, 2, 3], 4); + object.section_symbol(section1); + let (section2, _) = + object.add_subsection(write::StandardSection::Data, b"s1", &[0, 1, 2, 3], 4); + object.section_symbol(section2); + + let symbol = object.add_symbol(write::Symbol { + name: b"s1".to_vec(), + value: offset, + size: 4, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(section1), + flags: SymbolFlags::None, + }); + + object.add_comdat(write::Comdat { + kind: ComdatKind::NoDuplicates, + symbol, + sections: vec![section1, section2], + }); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"comdat.o", &bytes).unwrap(); + + let object = read::File::parse(&bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let section1 = sections.next().unwrap(); + println!("{:?}", section1); + let section1_index = section1.index(); + assert_eq!(section1.name(), Ok(".text$s1")); + assert_eq!(section1.kind(), SectionKind::Text); + assert_eq!(section1.address(), 0); + assert_eq!(section1.size(), 4); + + let section2 = sections.next().unwrap(); + println!("{:?}", section2); + let section2_index = section2.index(); + assert_eq!(section2.name(), Ok(".data$s1")); + assert_eq!(section2.kind(), SectionKind::Data); + assert_eq!(section2.address(), 0); + assert_eq!(section2.size(), 4); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok(".text$s1")); + assert_eq!(symbol.kind(), SymbolKind::Section); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section1.index()) + ); + assert_eq!( + symbol.flags(), + SymbolFlags::CoffSection { + selection: pe::IMAGE_COMDAT_SELECT_NODUPLICATES, + associative_section: None + } + ); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok(".data$s1")); + assert_eq!(symbol.kind(), SymbolKind::Section); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section2.index()) + ); + assert_eq!( + symbol.flags(), + SymbolFlags::CoffSection { + selection: pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE, + associative_section: Some(section1_index) + } + ); + + let symbol = symbols.next().unwrap(); + let symbol_index = symbol.index(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("s1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section1.index()) + ); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 0); + + let symbol = symbols.next(); + assert!(symbol.is_none(), format!("unexpected symbol {:?}", symbol)); + + let mut comdats = object.comdats(); + + let comdat = comdats.next().unwrap(); + println!("{:?}", comdat); + assert_eq!(comdat.kind(), ComdatKind::NoDuplicates); + assert_eq!(comdat.symbol(), symbol_index); + + let mut comdat_sections = comdat.sections(); + assert_eq!(comdat_sections.next(), Some(section1_index)); + assert_eq!(comdat_sections.next(), Some(section2_index)); + assert_eq!(comdat_sections.next(), None); +} + +#[test] +fn elf_x86_64_common() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + let (section1, offset) = + object.add_subsection(write::StandardSection::Text, b"s1", &[0, 1, 2, 3], 4); + let (section2, _) = + object.add_subsection(write::StandardSection::Data, b"s1", &[0, 1, 2, 3], 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"s1".to_vec(), + value: offset, + size: 4, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(section1), + flags: SymbolFlags::None, + }); + + object.add_comdat(write::Comdat { + kind: ComdatKind::Any, + symbol, + sections: vec![section1, section2], + }); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"comdat.o", &bytes).unwrap(); + + let object = read::File::parse(&bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let section = sections.next().unwrap(); + println!("{:?}", section); + assert_eq!(section.name(), Ok("")); + + let section = sections.next().unwrap(); + println!("{:?}", section); + assert_eq!(section.name(), Ok(".group")); + + let section1 = sections.next().unwrap(); + println!("{:?}", section1); + let section1_index = section1.index(); + assert_eq!(section1.name(), Ok(".text.s1")); + assert_eq!(section1.kind(), SectionKind::Text); + assert_eq!(section1.address(), 0); + assert_eq!(section1.size(), 4); + + let section2 = sections.next().unwrap(); + println!("{:?}", section2); + let section2_index = section2.index(); + assert_eq!(section2.name(), Ok(".data.s1")); + assert_eq!(section2.kind(), SectionKind::Data); + assert_eq!(section2.address(), 0); + assert_eq!(section2.size(), 4); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("")); + + let symbol = symbols.next().unwrap(); + let symbol_index = symbol.index(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("s1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section1.index()) + ); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 0); + + let symbol = symbols.next(); + assert!(symbol.is_none(), format!("unexpected symbol {:?}", symbol)); + + let mut comdats = object.comdats(); + + let comdat = comdats.next().unwrap(); + println!("{:?}", comdat); + assert_eq!(comdat.kind(), ComdatKind::Any); + assert_eq!(comdat.symbol(), symbol_index); + + let mut comdat_sections = comdat.sections(); + assert_eq!(comdat_sections.next(), Some(section1_index)); + assert_eq!(comdat_sections.next(), Some(section2_index)); + assert_eq!(comdat_sections.next(), None); +} diff --git a/vendor/object-0.20.0/tests/round_trip/common.rs b/vendor/object/tests/round_trip/common.rs similarity index 89% rename from vendor/object-0.20.0/tests/round_trip/common.rs rename to vendor/object/tests/round_trip/common.rs index c63c7f489d..a92386999d 100644 --- a/vendor/object-0.20.0/tests/round_trip/common.rs +++ b/vendor/object/tests/round_trip/common.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, SectionKind, SymbolFlags, SymbolKind, SymbolScope, @@ -58,9 +58,9 @@ fn coff_x86_64_common() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -69,9 +69,9 @@ fn coff_x86_64_common() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 4); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -80,12 +80,12 @@ fn coff_x86_64_common() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 8); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v3")); + assert_eq!(symbol.name(), Ok("v3")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Undefined); - assert_eq!(symbol.scope(), SymbolScope::Unknown); + assert_eq!(symbol.scope(), SymbolScope::Linkage); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), true); assert_eq!(symbol.address(), 0); @@ -134,13 +134,13 @@ fn elf_x86_64_common() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.name(), Ok("v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -149,9 +149,9 @@ fn elf_x86_64_common() { assert_eq!(symbol.address(), 0); assert_eq!(symbol.size(), 4); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.name(), Ok("v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section(), read::SymbolSection::Common); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -223,9 +223,9 @@ fn macho_x86_64_common() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v1")); + assert_eq!(symbol.name(), Ok("_v1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(common_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -233,9 +233,9 @@ fn macho_x86_64_common() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.address(), 0); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_v2")); + assert_eq!(symbol.name(), Ok("_v2")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(common_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); diff --git a/vendor/object-0.20.0/tests/round_trip/elf.rs b/vendor/object/tests/round_trip/elf.rs similarity index 96% rename from vendor/object-0.20.0/tests/round_trip/elf.rs rename to vendor/object/tests/round_trip/elf.rs index ddd7933049..b5bb11ca5d 100644 --- a/vendor/object-0.20.0/tests/round_trip/elf.rs +++ b/vendor/object/tests/round_trip/elf.rs @@ -1,8 +1,8 @@ use object::read::elf::{FileHeader, SectionHeader}; -use object::read::Object; +use object::read::{Object, ObjectSymbol}; use object::{ - elf, read, write, Architecture, BinaryFormat, Bytes, Endianness, LittleEndian, SectionFlags, - SectionIndex, SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection, U32, + elf, read, write, Architecture, BinaryFormat, Bytes, Endianness, LittleEndian, SectionIndex, + SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection, U32, }; use std::io::Write; @@ -34,10 +34,10 @@ fn symtab_shndx() { assert_eq!(object.format(), BinaryFormat::Elf); assert_eq!(object.architecture(), Architecture::X86_64); - for (index, symbol) in object.symbols().skip(1) { + for symbol in object.symbols().skip(1) { assert_eq!( symbol.section(), - SymbolSection::Section(SectionIndex(index.0)) + SymbolSection::Section(SectionIndex(symbol.index().0)) ); } } diff --git a/vendor/object-0.20.0/tests/round_trip/mod.rs b/vendor/object/tests/round_trip/mod.rs similarity index 87% rename from vendor/object-0.20.0/tests/round_trip/mod.rs rename to vendor/object/tests/round_trip/mod.rs index cec27c2d91..cf82b81ce7 100644 --- a/vendor/object-0.20.0/tests/round_trip/mod.rs +++ b/vendor/object/tests/round_trip/mod.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationKind, SectionKind, @@ -8,6 +8,7 @@ use object::{ }; mod bss; +mod comdat; mod common; mod elf; mod tls; @@ -68,18 +69,19 @@ fn coff_x86_64() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("file.c")); + assert_eq!(symbol.name(), Ok("file.c")); assert_eq!(symbol.address(), 0); assert_eq!(symbol.kind(), SymbolKind::File); assert_eq!(symbol.section(), SymbolSection::None); assert_eq!(symbol.scope(), SymbolScope::Compilation); assert_eq!(symbol.is_weak(), false); - let (func1_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("func1")); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("func1")); assert_eq!(symbol.address(), func1_offset); assert_eq!(symbol.kind(), SymbolKind::Text); assert_eq!(symbol.section_index(), Some(text_index)); @@ -100,6 +102,12 @@ fn coff_x86_64() { read::RelocationTarget::Symbol(func1_symbol) ); assert_eq!(relocation.addend(), 0); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "func1"); + assert_eq!(map.get(func1_offset - 1), None); } #[test] @@ -165,9 +173,9 @@ fn elf_x86_64() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); assert_eq!(symbol.address(), 0); assert_eq!(symbol.kind(), SymbolKind::Null); assert_eq!(symbol.section_index(), None); @@ -175,18 +183,19 @@ fn elf_x86_64() { assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), true); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("file.c")); + assert_eq!(symbol.name(), Ok("file.c")); assert_eq!(symbol.address(), 0); assert_eq!(symbol.kind(), SymbolKind::File); assert_eq!(symbol.section(), SymbolSection::None); assert_eq!(symbol.scope(), SymbolScope::Compilation); assert_eq!(symbol.is_weak(), false); - let (func1_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("func1")); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("func1")); assert_eq!(symbol.address(), func1_offset); assert_eq!(symbol.kind(), SymbolKind::Text); assert_eq!(symbol.section_index(), Some(text_index)); @@ -207,6 +216,12 @@ fn elf_x86_64() { read::RelocationTarget::Symbol(func1_symbol) ); assert_eq!(relocation.addend(), 0); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "func1"); + assert_eq!(map.get(func1_offset - 1), None); } #[test] @@ -282,9 +297,10 @@ fn macho_x86_64() { let mut symbols = object.symbols(); - let (func1_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_func1")); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_func1")); assert_eq!(symbol.address(), func1_offset); assert_eq!(symbol.kind(), SymbolKind::Text); assert_eq!(symbol.section_index(), Some(text_index)); @@ -317,4 +333,10 @@ fn macho_x86_64() { read::RelocationTarget::Symbol(func1_symbol) ); assert_eq!(relocation.addend(), -4); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "_func1"); + assert_eq!(map.get(func1_offset - 1), None); } diff --git a/vendor/object-0.20.0/tests/round_trip/tls.rs b/vendor/object/tests/round_trip/tls.rs similarity index 91% rename from vendor/object-0.20.0/tests/round_trip/tls.rs rename to vendor/object/tests/round_trip/tls.rs index 6d577658aa..7a438b45fe 100644 --- a/vendor/object-0.20.0/tests/round_trip/tls.rs +++ b/vendor/object/tests/round_trip/tls.rs @@ -1,6 +1,6 @@ #![cfg(all(feature = "read", feature = "write"))] -use object::read::{Object, ObjectSection}; +use object::read::{Object, ObjectSection, ObjectSymbol}; use object::{read, write}; use object::{ Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationKind, SectionKind, @@ -45,9 +45,9 @@ fn coff_x86_64_tls() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("tls1")); + assert_eq!(symbol.name(), Ok("tls1")); assert_eq!(symbol.kind(), SymbolKind::Data); assert_eq!(symbol.section_index(), Some(tls_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -118,13 +118,13 @@ fn elf_x86_64_tls() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("")); + assert_eq!(symbol.name(), Ok("")); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("tls1")); + assert_eq!(symbol.name(), Ok("tls1")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(tdata_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -132,9 +132,9 @@ fn elf_x86_64_tls() { assert_eq!(symbol.is_undefined(), false); assert_eq!(symbol.size(), 30); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("tls2")); + assert_eq!(symbol.name(), Ok("tls2")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(tbss_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); @@ -216,45 +216,48 @@ fn macho_x86_64_tls() { let mut symbols = object.symbols(); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls1")); + assert_eq!(symbol.name(), Ok("_tls1")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_vars_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), false); - let (tls1_init_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls1$tlv$init")); + let tls1_init_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_tls1$tlv$init")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_data_index)); assert_eq!(symbol.scope(), SymbolScope::Compilation); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), false); - let (tlv_bootstrap_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("__tlv_bootstrap")); + let tlv_bootstrap_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("__tlv_bootstrap")); assert_eq!(symbol.kind(), SymbolKind::Unknown); assert_eq!(symbol.section_index(), None); assert_eq!(symbol.scope(), SymbolScope::Unknown); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), true); - let (_, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls2")); + assert_eq!(symbol.name(), Ok("_tls2")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_vars_index)); assert_eq!(symbol.scope(), SymbolScope::Linkage); assert_eq!(symbol.is_weak(), false); assert_eq!(symbol.is_undefined(), false); - let (tls2_init_symbol, symbol) = symbols.next().unwrap(); + let symbol = symbols.next().unwrap(); println!("{:?}", symbol); - assert_eq!(symbol.name(), Some("_tls2$tlv$init")); + let tls2_init_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_tls2$tlv$init")); assert_eq!(symbol.kind(), SymbolKind::Tls); assert_eq!(symbol.section_index(), Some(thread_bss_index)); assert_eq!(symbol.scope(), SymbolScope::Compilation); diff --git a/vendor/serde/.cargo-checksum.json b/vendor/serde/.cargo-checksum.json index ce86133bd3..9b2c12c28c 100644 --- a/vendor/serde/.cargo-checksum.json +++ b/vendor/serde/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"736542df95689176d660863d0493740313de4a030a09ffa2b5559c80223769ac","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"d6af5a05be728765c2d98d960406ba648333745ed8644be311d2a1f52d7075f0","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/de/from_primitive.rs":"058fa17313ed3a9c29ec04c6ec67f21a756f6f28cdeb4b0dfcd7012b3e702d0b","src/de/ignored_any.rs":"6a0527edd497a56a103ae65f5e73da675b3f99094d6dcad3c335c8d932daaf40","src/de/impls.rs":"077487d2bacd1fd2093e3ef2fa0d52abe7b9530a84d1ccf9eefb4ad81b6bbad1","src/de/mod.rs":"b59c365b05e4e09a7467c958f85b2c64435514c59c17275be019397ad7ccb00e","src/de/utf8.rs":"f17524ee0af98ec3abcfd7d0b812fbd1033263bd8e2ce2f57c1e1999ce153558","src/de/value.rs":"a878f6bdd57d25b0b93bfc6288ed1e46c50870dc8703748b6fbb8c0965a6b586","src/export.rs":"2ebdf0eccaa64c5e98c6dfd13b4980474f627fc3fae90cfc2c741acf860afd5d","src/integer128.rs":"b213ec6c1ecf8c8228d9591e0b2c31b78d972cd4c6a0b231468090f15784f6f6","src/lib.rs":"c8b0d22a63c9250342fbd3a3b263435e7bca98d9091a3bad5db026eac4877ef9","src/macros.rs":"f18fc25c5fb857238bf119cdee5c7987a8584dea69c51f27ca718b7dfd871d0f","src/private/de.rs":"bce814fa2f2fd689c6d4a354839f38d7ea260509339181ce83d9b0fdbe0e1b3b","src/private/macros.rs":"ebb6affd4c89e3b5f9a42e03f8b7d966bc588875e9b44e962d0b7aba7f80a10f","src/private/mod.rs":"f8f2cd5edbfc26c268b34cdb89db1b34e6348f81384f03d18532e7568575006d","src/private/ser.rs":"96a1e23ad7f3c8ee51a02d799d92780e19dd3c18fa0f1ad791abef7cb346e224","src/ser/fmt.rs":"7827ed07fd8897e6324f75625ba0c926a4c4e7ec2914cd067391ce54d942ac7b","src/ser/impls.rs":"ce9996998c6485c88bbc77516611e9f5a9a92cbb12d34bb4f8ae022530be85e0","src/ser/impossible.rs":"3dd0e165b88fc67e698e675f16569b91fab9e054caa4c3e1997f929ba364fe90","src/ser/mod.rs":"9c26100d8058a5c39aea72512fb78de959e4ed9199481eef47996f0864df0f2c","src/std_error.rs":"3aac687856c035517fae44ed2906dd4a1e3184bae4bf613adcdeb73f74126c57"},"package":"96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"} \ No newline at end of file +{"files":{"Cargo.toml":"4a6098c5140bc095bf8f96fb08b3262ec6939ec3da831ff762a034ff98a017ce","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"d6af5a05be728765c2d98d960406ba648333745ed8644be311d2a1f52d7075f0","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/de/from_primitive.rs":"058fa17313ed3a9c29ec04c6ec67f21a756f6f28cdeb4b0dfcd7012b3e702d0b","src/de/ignored_any.rs":"6a0527edd497a56a103ae65f5e73da675b3f99094d6dcad3c335c8d932daaf40","src/de/impls.rs":"5972a9c0d9a0e811b543ff3850a402b3adfc5237e62c5db18c5e0f71928ea74e","src/de/mod.rs":"b59c365b05e4e09a7467c958f85b2c64435514c59c17275be019397ad7ccb00e","src/de/utf8.rs":"f17524ee0af98ec3abcfd7d0b812fbd1033263bd8e2ce2f57c1e1999ce153558","src/de/value.rs":"1b58860694b753886b087e20f6afbeea2cb69a1d12b6e72d9934f5649a1ec219","src/export.rs":"2ebdf0eccaa64c5e98c6dfd13b4980474f627fc3fae90cfc2c741acf860afd5d","src/integer128.rs":"b213ec6c1ecf8c8228d9591e0b2c31b78d972cd4c6a0b231468090f15784f6f6","src/lib.rs":"45a70c9c81c0e2cdc8b4c9ed3441a1b605b38e0705cfa3d9fae06bd96614917d","src/macros.rs":"f18fc25c5fb857238bf119cdee5c7987a8584dea69c51f27ca718b7dfd871d0f","src/private/de.rs":"bce814fa2f2fd689c6d4a354839f38d7ea260509339181ce83d9b0fdbe0e1b3b","src/private/macros.rs":"ebb6affd4c89e3b5f9a42e03f8b7d966bc588875e9b44e962d0b7aba7f80a10f","src/private/mod.rs":"f8f2cd5edbfc26c268b34cdb89db1b34e6348f81384f03d18532e7568575006d","src/private/ser.rs":"96a1e23ad7f3c8ee51a02d799d92780e19dd3c18fa0f1ad791abef7cb346e224","src/ser/fmt.rs":"7827ed07fd8897e6324f75625ba0c926a4c4e7ec2914cd067391ce54d942ac7b","src/ser/impls.rs":"496b7ba45529e569ffdf5d755c6df99c1321fddc89b9f64f5cc58e24052caefc","src/ser/impossible.rs":"3dd0e165b88fc67e698e675f16569b91fab9e054caa4c3e1997f929ba364fe90","src/ser/mod.rs":"9c26100d8058a5c39aea72512fb78de959e4ed9199481eef47996f0864df0f2c","src/std_error.rs":"3aac687856c035517fae44ed2906dd4a1e3184bae4bf613adcdeb73f74126c57"},"package":"06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"} \ No newline at end of file diff --git a/vendor/serde/Cargo.toml b/vendor/serde/Cargo.toml index 4e6fa348f2..984ecbd647 100644 --- a/vendor/serde/Cargo.toml +++ b/vendor/serde/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "serde" -version = "1.0.116" +version = "1.0.118" authors = ["Erick Tryzelaar ", "David Tolnay "] build = "build.rs" include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] @@ -30,7 +30,7 @@ targets = ["x86_64-unknown-linux-gnu"] [package.metadata.playground] features = ["derive", "rc"] [dependencies.serde_derive] -version = "=1.0.116" +version = "=1.0.118" optional = true [dev-dependencies.serde_derive] version = "1.0" diff --git a/vendor/serde/src/de/impls.rs b/vendor/serde/src/de/impls.rs index ae4f9dc806..d9af210e47 100644 --- a/vendor/serde/src/de/impls.rs +++ b/vendor/serde/src/de/impls.rs @@ -1871,7 +1871,7 @@ impl<'de> Deserialize<'de> for Duration { enum Field { Secs, Nanos, - }; + } impl<'de> Deserialize<'de> for Field { fn deserialize(deserializer: D) -> Result @@ -1996,7 +1996,7 @@ impl<'de> Deserialize<'de> for SystemTime { enum Field { Secs, Nanos, - }; + } impl<'de> Deserialize<'de> for Field { fn deserialize(deserializer: D) -> Result @@ -2334,10 +2334,7 @@ where 0 => Ok(Field::Unbounded), 1 => Ok(Field::Included), 2 => Ok(Field::Excluded), - _ => Err(Error::invalid_value( - Unexpected::Unsigned(value), - &self, - )), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self)), } } @@ -2499,10 +2496,7 @@ where match value { 0 => Ok(Field::Ok), 1 => Ok(Field::Err), - _ => Err(Error::invalid_value( - Unexpected::Unsigned(value), - &self, - )), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self)), } } @@ -2570,7 +2564,6 @@ where //////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "std")] impl<'de, T> Deserialize<'de> for Wrapping where T: Deserialize<'de>, diff --git a/vendor/serde/src/de/value.rs b/vendor/serde/src/de/value.rs index d0a185da2e..4044f322bc 100644 --- a/vendor/serde/src/de/value.rs +++ b/vendor/serde/src/de/value.rs @@ -1034,7 +1034,7 @@ where let value = self.value.take(); // Panic because this indicates a bug in the program rather than an // expected failure. - let value = value.expect("MapAccess::visit_value called before visit_key"); + let value = value.expect("MapAccess::next_value called before next_key"); seed.deserialize(value.into_deserializer()) } diff --git a/vendor/serde/src/lib.rs b/vendor/serde/src/lib.rs index fe40eb1ca8..12154da250 100644 --- a/vendor/serde/src/lib.rs +++ b/vendor/serde/src/lib.rs @@ -82,7 +82,7 @@ //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.116")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.118")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] // Unstable functionality only if the user asks for it. For tracking and @@ -118,6 +118,8 @@ zero_prefixed_literal, // correctly used enum_glob_use, + map_err_ignore, + result_unit_err, wildcard_imports, // not practical needless_pass_by_value, @@ -164,6 +166,7 @@ mod lib { pub use self::core::default::{self, Default}; pub use self::core::fmt::{self, Debug, Display}; pub use self::core::marker::{self, PhantomData}; + pub use self::core::num::Wrapping; pub use self::core::ops::Range; pub use self::core::option::{self, Option}; pub use self::core::result::{self, Result}; @@ -215,8 +218,6 @@ mod lib { #[cfg(feature = "std")] pub use std::io::Write; #[cfg(feature = "std")] - pub use std::num::Wrapping; - #[cfg(feature = "std")] pub use std::path::{Path, PathBuf}; #[cfg(feature = "std")] pub use std::sync::{Mutex, RwLock}; diff --git a/vendor/serde/src/ser/impls.rs b/vendor/serde/src/ser/impls.rs index 0dc8085f49..431a478cc5 100644 --- a/vendor/serde/src/ser/impls.rs +++ b/vendor/serde/src/ser/impls.rs @@ -753,10 +753,10 @@ impl Serialize for net::SocketAddrV6 { S: Serializer, { if serializer.is_human_readable() { - const MAX_LEN: usize = 47; + const MAX_LEN: usize = 58; debug_assert_eq!( MAX_LEN, - "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len() + "[1001:1002:1003:1004:1005:1006:1007:1008%4294967295]:65000".len() ); serialize_display_bounded_length!(self, MAX_LEN, serializer) } else { @@ -824,7 +824,6 @@ impl Serialize for OsString { //////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "std")] impl Serialize for Wrapping where T: Serialize, diff --git a/vendor/serde_derive/.cargo-checksum.json b/vendor/serde_derive/.cargo-checksum.json index 915ba422d6..e4cbc53489 100644 --- a/vendor/serde_derive/.cargo-checksum.json +++ b/vendor/serde_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"74677f4031ffe40137aad8407d240dfe0bd3ed5d07c518afb1983b384f4ee283","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"17fac4a28904e90c1e46b517839bd17fd54dbc69cfbff7451f695ecf7bab34ef","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/bound.rs":"66643d6cd044a2167b2bb8a1970e5b2a07069e362ce1326a4b00fef7bcfcd5c8","src/de.rs":"8bea1aa8057c824264bb4700fa6531747bfaed88be2d1f90bb6455600aa8e222","src/dummy.rs":"7bc4267039808046fe0a7fbeb462b301ac30ea1152fcbde8a3b934dc143fe468","src/fragment.rs":"5548ba65a53d90a296f60c1328a7a7fb040db467f59c2f5210b2fb320457145d","src/internals/ast.rs":"f1a1b13cf6b68e2bf27c5cdcdbde6883f86cde1ba8c0595dffdbf2e11c4ec8b1","src/internals/attr.rs":"554bf48da8fb4e8a5ac2d16143cc9dc05e9bc493b4a4c8a196ace360bce110d5","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"9a01a0db1fc3086891e998f544836e7498ebfc7cc5e1956199d0526e6a8d9a3c","src/internals/ctxt.rs":"6fa544ae52914498a62a395818ebdc1b36ac2fb5903c60afb741a864ad559f1c","src/internals/mod.rs":"989df41dae7a9066eec3e5afd5b262fd94a12281df30f4c03f319370811beea0","src/internals/symbol.rs":"9f2b4b9cd83dc09def75165187c97d0050bffa4218782c27b478bcf93f925a74","src/lib.rs":"ae786031bb024d49a73e8c0aee126441a9e61dd2bc50ddf7aad4a586fa89081d","src/pretend.rs":"ffeb23da4c2abc4e501c378cffa8b776bab506735ea70d4ed10f4c0f3755321b","src/ser.rs":"4ac3d23e5a84b72137d42eaa38ef8ec1516c4d4d9ca040dc5ce2abbf33126443","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":"f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"} \ No newline at end of file +{"files":{"Cargo.toml":"11158dadd2edd6f90098847974f61b27958d992874cb82b345a807d8dad0d745","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"17fac4a28904e90c1e46b517839bd17fd54dbc69cfbff7451f695ecf7bab34ef","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/bound.rs":"66643d6cd044a2167b2bb8a1970e5b2a07069e362ce1326a4b00fef7bcfcd5c8","src/de.rs":"39832ecad5aedbb57bc1e8f8f62e18e1cc7e659456aca9856c3dfcceb6cf0d16","src/dummy.rs":"7bc4267039808046fe0a7fbeb462b301ac30ea1152fcbde8a3b934dc143fe468","src/fragment.rs":"5548ba65a53d90a296f60c1328a7a7fb040db467f59c2f5210b2fb320457145d","src/internals/ast.rs":"f1a1b13cf6b68e2bf27c5cdcdbde6883f86cde1ba8c0595dffdbf2e11c4ec8b1","src/internals/attr.rs":"554bf48da8fb4e8a5ac2d16143cc9dc05e9bc493b4a4c8a196ace360bce110d5","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"9a01a0db1fc3086891e998f544836e7498ebfc7cc5e1956199d0526e6a8d9a3c","src/internals/ctxt.rs":"6fa544ae52914498a62a395818ebdc1b36ac2fb5903c60afb741a864ad559f1c","src/internals/mod.rs":"989df41dae7a9066eec3e5afd5b262fd94a12281df30f4c03f319370811beea0","src/internals/symbol.rs":"9f2b4b9cd83dc09def75165187c97d0050bffa4218782c27b478bcf93f925a74","src/lib.rs":"03d0fc248521ae2ea1ef52ffd4db3839131358ccaf79145942deffded2f743c1","src/pretend.rs":"ffeb23da4c2abc4e501c378cffa8b776bab506735ea70d4ed10f4c0f3755321b","src/ser.rs":"4ac3d23e5a84b72137d42eaa38ef8ec1516c4d4d9ca040dc5ce2abbf33126443","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":"c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"} \ No newline at end of file diff --git a/vendor/serde_derive/Cargo.toml b/vendor/serde_derive/Cargo.toml index d06a1bb40a..485fb7abcb 100644 --- a/vendor/serde_derive/Cargo.toml +++ b/vendor/serde_derive/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "serde_derive" -version = "1.0.116" +version = "1.0.118" authors = ["Erick Tryzelaar ", "David Tolnay "] include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" diff --git a/vendor/serde_derive/src/de.rs b/vendor/serde_derive/src/de.rs index 1f5733a6d5..55ab808bc4 100644 --- a/vendor/serde_derive/src/de.rs +++ b/vendor/serde_derive/src/de.rs @@ -12,6 +12,7 @@ use internals::{attr, ungroup, Ctxt, Derive}; use pretend; use std::collections::BTreeSet; +use std::ptr; pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result> { let ctxt = Ctxt::new(); @@ -359,7 +360,7 @@ fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { let assign = fields.iter().map(|field| { let member = &field.member; - if field as *const Field == transparent_field as *const Field { + if ptr::eq(field, transparent_field) { quote!(#member: __transparent) } else { let value = match field.attrs.default() { diff --git a/vendor/serde_derive/src/lib.rs b/vendor/serde_derive/src/lib.rs index 9307ae8147..266bc9dedb 100644 --- a/vendor/serde_derive/src/lib.rs +++ b/vendor/serde_derive/src/lib.rs @@ -13,7 +13,7 @@ //! //! [https://serde.rs/derive.html]: https://serde.rs/derive.html -#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.116")] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.118")] #![allow(unknown_lints, bare_trait_objects)] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints @@ -38,6 +38,7 @@ clippy::filter_map, clippy::indexing_slicing, clippy::items_after_statements, + clippy::map_err_ignore, clippy::match_same_arms, clippy::module_name_repetitions, clippy::must_use_candidate, diff --git a/vendor/socket2/.cargo-checksum.json b/vendor/socket2/.cargo-checksum.json index 9e07dc7d73..ce4dc4c890 100644 --- a/vendor/socket2/.cargo-checksum.json +++ b/vendor/socket2/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"1f63c96afd80714e740a345de9f2f2d40dd8f2ea1ae8736220695ecb861c3934","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"9c3d94f57a3464986df30edf46250fa70200b40b9c70d8cac6b2fc3a76d24631","src/lib.rs":"1f2159502b551883652e32a02a6f4d60b284ad916cd970994c8beb40b4cc9118","src/sockaddr.rs":"f1e9cf21aa3e454b94d3fbecc3e700935aa15dcc141451825fe4585f23cbc5cd","src/socket.rs":"bca588782081a2643143d96544e63864c6c06a84a4eef49f4652fe56632e75aa","src/sys/unix.rs":"2591e08e60c0af86d97520d1aa3d1a96c29dacadf253d90f31fbe55dd798e304","src/sys/windows.rs":"5180e6fbe029fcfc710e1d3498646f4a13b39a7eb62a2b3b0b01c29a7e9dc411","src/tests.rs":"d17e44cc61c646f41b4a18a7f7cb4e632ea34dc1c7d347928e0ed6295840a0ae","src/utils.rs":"53968de8c8e078a650fa316438622be9bb78bca95ed07c4f8da2c940ae27e0ae"},"package":"03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"} \ No newline at end of file +{"files":{"9f0fbf2.diff":"887a86c962053911d3ec997a24088d76bd8dcfdf1d5d6607cab63241669ac7f7","Cargo.toml":"626888321ce5bffbb9a7d30bb261068bfbfe77669babea026e1b1752890ea984","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"9c3d94f57a3464986df30edf46250fa70200b40b9c70d8cac6b2fc3a76d24631","TODO":"29a59a39f03f1a591fe06e7386067c4189bcdbe55345f12b0c9e5374a5547274","TODO.refactor":"5ee39d5ce03115489c2556d8e976f3306ad3a966fcec0e037a8cfc0dc99f3454","check_targets.bash":"dd9de020e3991988c8183327ab1d1b7c0cfbb21364676a6c4b8a4a0f8fafd6ef","socket_type.diff":"b9dc1dbec2c4aee70a73015ddbb7d558aa630cfb5e134e127a359555e9b84dc5","src/lib.rs":"1f2159502b551883652e32a02a6f4d60b284ad916cd970994c8beb40b4cc9118","src/sockaddr.rs":"8221f66a33b6d845562fb4213f7f0d008b495781a1ce462874557cec4b7ce311","src/socket.rs":"d721c313e41c7fc0f23de728d2f4ac3fc48643032a64aa2a62c3e89c5df4560d","src/sys/unix.rs":"a033647d6ba812d81e7534fb055e6365f17ecbfb2a3c2b608005fe26f4c4b041","src/sys/windows.rs":"5180e6fbe029fcfc710e1d3498646f4a13b39a7eb62a2b3b0b01c29a7e9dc411","src/tests.rs":"d17e44cc61c646f41b4a18a7f7cb4e632ea34dc1c7d347928e0ed6295840a0ae","src/utils.rs":"53968de8c8e078a650fa316438622be9bb78bca95ed07c4f8da2c940ae27e0ae"},"package":"7fd8b795c389288baa5f355489c65e71fd48a02104600d15c4cfbc561e9e429d"} \ No newline at end of file diff --git a/vendor/socket2/9f0fbf2.diff b/vendor/socket2/9f0fbf2.diff new file mode 100644 index 0000000000..4fa2688476 --- /dev/null +++ b/vendor/socket2/9f0fbf2.diff @@ -0,0 +1,2623 @@ +src/socket.rs +src/sys/unix.rs +src/sys/windows.rs + + + + +commit 9f0fbf2ed487668e4e2b5357a8e4a167e7ec903a +Author: Thomas de Zeeuw +Date: Sat Jan 18 16:43:21 2020 +0100 + + Part 1 of the rewrite + + Currently not functional on Windows and a lot of methods are removed, + but its a start. + +diff --git a/src/socket.rs b/src/socket.rs +index 354c5cf..424e094 100644 +--- a/src/socket.rs ++++ b/src/socket.rs +@@ -8,201 +8,107 @@ + // option. This file may not be copied, modified, or distributed + // except according to those terms. + +-use std::fmt; +-use std::io::{self, Read, Write}; +-use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; +-#[cfg(all(unix, feature = "unix"))] +-use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; +-use std::time::Duration; ++use std::net::{Shutdown, TcpListener, TcpStream, UdpSocket}; ++#[cfg(unix)] ++use std::os::unix::io::{FromRawFd, IntoRawFd}; ++use std::{fmt, io}; + +-use crate::sys; ++use crate::sys::{self, c_int}; + use crate::{Domain, Protocol, SockAddr, Type}; + +-/// Newtype, owned, wrapper around a system socket. ++/// An owned system socket. + /// +-/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix +-/// and an instance of `SOCKET` on Windows. This is the main type exported by +-/// this crate and is intended to mirror the raw semantics of sockets on +-/// platforms as closely as possible. Almost all methods correspond to +-/// precisely one libc or OS API call which is essentially just a "Rustic +-/// translation" of what's below. ++/// This type simply wraps an instance of a file descriptor (`int`) on Unix and ++/// an instance of `SOCKET` on Windows. This is the main type exported by this ++/// crate and is intended to mirror the raw semantics of sockets on platforms as ++/// closely as possible. All methods correspond to precisely one libc or OS API ++/// call which is essentially just a "Rustic translation" of what's below. ++/// ++/// # Notes ++/// ++/// This type can be converted to and from all network types provided by the ++/// standard library using the [`From`] and [`Into`] traits. Is up to the user ++/// to ensure the socket is setup correctly for a given type! + /// + /// # Examples + /// +-/// ```no_run +-/// use std::net::SocketAddr; +-/// use socket2::{Socket, Domain, Type, SockAddr}; ++/// ``` ++/// # fn main() -> std::io::Result<()> { ++/// use std::net::{SocketAddr, TcpListener}; ++/// use socket2::{Socket, Domain, Type}; + /// +-/// // create a TCP listener bound to two addresses +-/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); ++/// // Create a new `Socket`. ++/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None)?; + /// +-/// socket.bind(&"127.0.0.1:12345".parse::().unwrap().into()).unwrap(); +-/// socket.bind(&"127.0.0.1:12346".parse::().unwrap().into()).unwrap(); +-/// socket.listen(128).unwrap(); ++/// // Bind the socket to an addresses. ++/// let addr1: SocketAddr = "127.0.0.1:15123".parse().unwrap(); ++/// socket.bind(&addr1.into())?; + /// +-/// let listener = socket.into_tcp_listener(); +-/// // ... ++/// // Start listening on the socket. ++/// socket.listen(128)?; ++/// ++/// // Finally convert it to `TcpListener` from the standard library. Now it can ++/// // be used like any other `TcpListener`. ++/// let listener: TcpListener = socket.into(); ++/// # drop(listener); ++/// # Ok(()) ++/// # } + /// ``` + pub struct Socket { +- // The `sys` module most have access to the socket. +- pub(crate) inner: sys::Socket, ++ // The `sys` module must have access to the raw socket to implement OS ++ // specific additional methods, e.g. Unix Domain sockets (UDS). ++ pub(crate) inner: sys::RawSocket, + } + + impl Socket { + /// Creates a new socket ready to be configured. + /// +- /// This function corresponds to `socket(2)` and simply creates a new +- /// socket, no other configuration is done and further functions must be +- /// invoked to configure this socket. ++ /// This function corresponds to `socket(2)`. + pub fn new(domain: Domain, type_: Type, protocol: Option) -> io::Result { +- let protocol = protocol.map(|p| p.0).unwrap_or(0); +- Ok(Socket { +- inner: sys::Socket::new(domain.0, type_.0, protocol)?, +- }) +- } +- +- /// Creates a pair of sockets which are connected to each other. +- /// +- /// This function corresponds to `socketpair(2)`. +- /// +- /// This function is only available on Unix when the `pair` feature is +- /// enabled. +- #[cfg(all(unix, feature = "pair"))] +- pub fn pair( +- domain: Domain, +- type_: Type, +- protocol: Option, +- ) -> io::Result<(Socket, Socket)> { +- let protocol = protocol.map(|p| p.0).unwrap_or(0); +- let sockets = sys::Socket::pair(domain.0, type_.0, protocol)?; +- Ok((Socket { inner: sockets.0 }, Socket { inner: sockets.1 })) +- } +- +- /// Consumes this `Socket`, converting it to a `TcpStream`. +- pub fn into_tcp_stream(self) -> net::TcpStream { +- self.into() +- } +- +- /// Consumes this `Socket`, converting it to a `TcpListener`. +- pub fn into_tcp_listener(self) -> net::TcpListener { +- self.into() +- } +- +- /// Consumes this `Socket`, converting it to a `UdpSocket`. +- pub fn into_udp_socket(self) -> net::UdpSocket { +- self.into() +- } +- +- /// Consumes this `Socket`, converting it into a `UnixStream`. +- /// +- /// This function is only available on Unix when the `unix` feature is +- /// enabled. +- #[cfg(all(unix, feature = "unix"))] +- pub fn into_unix_stream(self) -> UnixStream { +- self.into() +- } +- +- /// Consumes this `Socket`, converting it into a `UnixListener`. +- /// +- /// This function is only available on Unix when the `unix` feature is +- /// enabled. +- #[cfg(all(unix, feature = "unix"))] +- pub fn into_unix_listener(self) -> UnixListener { +- self.into() +- } +- +- /// Consumes this `Socket`, converting it into a `UnixDatagram`. +- /// +- /// This function is only available on Unix when the `unix` feature is +- /// enabled. +- #[cfg(all(unix, feature = "unix"))] +- pub fn into_unix_datagram(self) -> UnixDatagram { +- self.into() ++ sys::socket(domain.0, type_.0, protocol.map(|p| p.0).unwrap_or(0)) + } + + /// Initiate a connection on this socket to the specified address. + /// +- /// This function directly corresponds to the connect(2) function on Windows +- /// and Unix. +- /// +- /// An error will be returned if `listen` or `connect` has already been +- /// called on this builder. ++ /// This function directly corresponds to the `connect(2)` function. + pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { +- self.inner.connect(addr) +- } +- +- /// Initiate a connection on this socket to the specified address, only +- /// only waiting for a certain period of time for the connection to be +- /// established. +- /// +- /// Unlike many other methods on `Socket`, this does *not* correspond to a +- /// single C function. It sets the socket to nonblocking mode, connects via +- /// connect(2), and then waits for the connection to complete with poll(2) +- /// on Unix and select on Windows. When the connection is complete, the +- /// socket is set back to blocking mode. On Unix, this will loop over +- /// `EINTR` errors. +- /// +- /// # Warnings +- /// +- /// The nonblocking state of the socket is overridden by this function - +- /// it will be returned in blocking mode on success, and in an indeterminate +- /// state on failure. +- /// +- /// If the connection request times out, it may still be processing in the +- /// background - a second call to `connect` or `connect_timeout` may fail. +- pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { +- self.inner.connect_timeout(addr, timeout) ++ sys::connect(self.inner, addr.as_ptr(), addr.len()) + } + + /// Binds this socket to the specified address. + /// +- /// This function directly corresponds to the bind(2) function on Windows +- /// and Unix. ++ /// This function directly corresponds to the `bind(2)` function. + pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { +- self.inner.bind(addr) ++ sys::bind(self.inner, addr.as_ptr(), addr.len()) + } + +- /// Mark a socket as ready to accept incoming connection requests using +- /// accept() ++ /// Returns the socket address of the local half of this connection. + /// +- /// This function directly corresponds to the listen(2) function on Windows +- /// and Unix. +- /// +- /// An error will be returned if `listen` or `connect` has already been +- /// called on this builder. +- pub fn listen(&self, backlog: i32) -> io::Result<()> { +- self.inner.listen(backlog) ++ /// This function directly corresponds to the `getsockname(2)` function. ++ pub fn local_addr(&self) -> io::Result { ++ sys::getsockname(self.inner) + } + +- /// Accept a new incoming connection from this listener. ++ /// Returns the socket address of the remote peer of this connection. + /// +- /// This function will block the calling thread until a new connection is +- /// established. When established, the corresponding `Socket` and the +- /// remote peer's address will be returned. +- pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { +- self.inner +- .accept() +- .map(|(socket, addr)| (Socket { inner: socket }, addr)) +- } +- +- /// Returns the socket address of the local half of this TCP connection. +- pub fn local_addr(&self) -> io::Result { +- self.inner.local_addr() ++ /// This function directly corresponds to the `getpeername(2)` function. ++ pub fn peer_addr(&self) -> io::Result { ++ sys::getpeername(self.inner) + } + +- /// Returns the socket address of the remote peer of this TCP connection. +- pub fn peer_addr(&self) -> io::Result { +- self.inner.peer_addr() ++ /// Mark a socket as ready to accept incoming connection requests using ++ /// `accept(2)`. ++ /// ++ /// This function directly corresponds to the `listen(2)` function. ++ pub fn listen(&self, backlog: c_int) -> io::Result<()> { ++ sys::listen(self.inner, backlog) + } + +- /// Creates a new independently owned handle to the underlying socket. ++ /// Accept a new incoming connection from this listener. + /// +- /// The returned `TcpStream` is a reference to the same stream that this +- /// object references. Both handles will read and write the same stream of +- /// data, and options set on one stream will be propagated to the other +- /// stream. +- pub fn try_clone(&self) -> io::Result { +- self.inner.try_clone().map(|s| Socket { inner: s }) ++ /// This function directly corresponds to the `accept(2)` function. ++ pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { ++ sys::accept(self.inner) + } + + /// Get the value of the `SO_ERROR` option on this socket. +@@ -211,15 +117,14 @@ impl Socket { + /// the field in the process. This can be useful for checking errors between + /// calls. + pub fn take_error(&self) -> io::Result> { +- self.inner.take_error() +- } +- +- /// Moves this TCP stream into or out of nonblocking mode. +- /// +- /// On Unix this corresponds to calling fcntl, and on Windows this +- /// corresponds to calling ioctlsocket. +- pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { +- self.inner.set_nonblocking(nonblocking) ++ self.getsockopt::(libc::SOL_SOCKET, libc::SO_ERROR) ++ .map(|errno| { ++ if errno == 0 { ++ None ++ } else { ++ Some(io::Error::from_raw_os_error(errno)) ++ } ++ }) + } + + /// Shuts down the read, write, or both halves of this connection. +@@ -227,689 +132,110 @@ impl Socket { + /// This function will cause all pending and future I/O on the specified + /// portions to return immediately with an appropriate value. + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { +- self.inner.shutdown(how) +- } +- +- /// Receives data on the socket from the remote address to which it is +- /// connected. +- /// +- /// The [`connect`] method will connect this socket to a remote address. This +- /// method will fail if the socket is not connected. +- /// +- /// [`connect`]: #method.connect +- pub fn recv(&self, buf: &mut [u8]) -> io::Result { +- self.inner.recv(buf) +- } +- +- /// Receives data on the socket from the remote adress to which it is +- /// connected, without removing that data from the queue. On success, +- /// returns the number of bytes peeked. +- /// +- /// Successive calls return the same data. This is accomplished by passing +- /// `MSG_PEEK` as a flag to the underlying `recv` system call. +- pub fn peek(&self, buf: &mut [u8]) -> io::Result { +- self.inner.peek(buf) +- } +- +- /// Receives data from the socket. On success, returns the number of bytes +- /// read and the address from whence the data came. +- pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { +- self.inner.recv_from(buf) +- } +- +- /// Receives data from the socket, without removing it from the queue. +- /// +- /// Successive calls return the same data. This is accomplished by passing +- /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. +- /// +- /// On success, returns the number of bytes peeked and the address from +- /// whence the data came. +- pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { +- self.inner.peek_from(buf) +- } +- +- /// Sends data on the socket to a connected peer. +- /// +- /// This is typically used on TCP sockets or datagram sockets which have +- /// been connected. +- /// +- /// On success returns the number of bytes that were sent. +- pub fn send(&self, buf: &[u8]) -> io::Result { +- self.inner.send(buf) +- } +- +- /// Sends data on the socket to the given address. On success, returns the +- /// number of bytes written. +- /// +- /// This is typically used on UDP or datagram-oriented sockets. On success +- /// returns the number of bytes that were sent. +- pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result { +- self.inner.send_to(buf, addr) +- } +- +- // ================================================ +- +- /// Gets the value of the `IP_TTL` option for this socket. +- /// +- /// For more information about this option, see [`set_ttl`][link]. +- /// +- /// [link]: #method.set_ttl +- pub fn ttl(&self) -> io::Result { +- self.inner.ttl() +- } +- +- /// Sets the value for the `IP_TTL` option on this socket. +- /// +- /// This value sets the time-to-live field that is used in every packet sent +- /// from this socket. +- pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { +- self.inner.set_ttl(ttl) +- } +- +- /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. +- /// +- /// Specifies the hop limit for ipv6 unicast packets +- pub fn unicast_hops_v6(&self) -> io::Result { +- self.inner.unicast_hops_v6() +- } +- +- /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. +- /// +- /// Specifies the hop limit for ipv6 unicast packets +- pub fn set_unicast_hops_v6(&self, ttl: u32) -> io::Result<()> { +- self.inner.set_unicast_hops_v6(ttl) +- } +- +- /// Gets the value of the `IPV6_V6ONLY` option for this socket. +- /// +- /// For more information about this option, see [`set_only_v6`][link]. +- /// +- /// [link]: #method.set_only_v6 +- pub fn only_v6(&self) -> io::Result { +- self.inner.only_v6() +- } +- +- /// Sets the value for the `IPV6_V6ONLY` option on this socket. +- /// +- /// If this is set to `true` then the socket is restricted to sending and +- /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications +- /// can bind the same port at the same time. +- /// +- /// If this is set to `false` then the socket can be used to send and +- /// receive packets from an IPv4-mapped IPv6 address. +- pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { +- self.inner.set_only_v6(only_v6) +- } +- +- /// Returns the read timeout of this socket. +- /// +- /// If the timeout is `None`, then `read` calls will block indefinitely. +- pub fn read_timeout(&self) -> io::Result> { +- self.inner.read_timeout() +- } +- +- /// Sets the read timeout to the timeout specified. +- /// +- /// If the value specified is `None`, then `read` calls will block +- /// indefinitely. It is an error to pass the zero `Duration` to this +- /// method. +- pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { +- self.inner.set_read_timeout(dur) +- } +- +- /// Returns the write timeout of this socket. +- /// +- /// If the timeout is `None`, then `write` calls will block indefinitely. +- pub fn write_timeout(&self) -> io::Result> { +- self.inner.write_timeout() +- } +- +- /// Sets the write timeout to the timeout specified. +- /// +- /// If the value specified is `None`, then `write` calls will block +- /// indefinitely. It is an error to pass the zero `Duration` to this +- /// method. +- pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { +- self.inner.set_write_timeout(dur) +- } +- +- /// Gets the value of the `TCP_NODELAY` option on this socket. +- /// +- /// For more information about this option, see [`set_nodelay`][link]. +- /// +- /// [link]: #method.set_nodelay +- pub fn nodelay(&self) -> io::Result { +- self.inner.nodelay() +- } +- +- /// Sets the value of the `TCP_NODELAY` option on this socket. +- /// +- /// If set, this option disables the Nagle algorithm. This means that +- /// segments are always sent as soon as possible, even if there is only a +- /// small amount of data. When not set, data is buffered until there is a +- /// sufficient amount to send out, thereby avoiding the frequent sending of +- /// small packets. +- pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { +- self.inner.set_nodelay(nodelay) +- } +- +- /// Sets the value of the `SO_BROADCAST` option for this socket. +- /// +- /// When enabled, this socket is allowed to send packets to a broadcast +- /// address. +- pub fn broadcast(&self) -> io::Result { +- self.inner.broadcast() +- } +- +- /// Gets the value of the `SO_BROADCAST` option for this socket. +- /// +- /// For more information about this option, see +- /// [`set_broadcast`][link]. +- /// +- /// [link]: #method.set_broadcast +- pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { +- self.inner.set_broadcast(broadcast) +- } +- +- /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. +- /// +- /// For more information about this option, see +- /// [`set_multicast_loop_v4`][link]. +- /// +- /// [link]: #method.set_multicast_loop_v4 +- pub fn multicast_loop_v4(&self) -> io::Result { +- self.inner.multicast_loop_v4() +- } +- +- /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. +- /// +- /// If enabled, multicast packets will be looped back to the local socket. +- /// Note that this may not have any affect on IPv6 sockets. +- pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { +- self.inner.set_multicast_loop_v4(multicast_loop_v4) +- } +- +- /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. +- /// +- /// For more information about this option, see +- /// [`set_multicast_ttl_v4`][link]. +- /// +- /// [link]: #method.set_multicast_ttl_v4 +- pub fn multicast_ttl_v4(&self) -> io::Result { +- self.inner.multicast_ttl_v4() +- } +- +- /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. +- /// +- /// Indicates the time-to-live value of outgoing multicast packets for +- /// this socket. The default value is 1 which means that multicast packets +- /// don't leave the local network unless explicitly requested. +- /// +- /// Note that this may not have any affect on IPv6 sockets. +- pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { +- self.inner.set_multicast_ttl_v4(multicast_ttl_v4) +- } +- +- /// Gets the value of the `IPV6_MULTICAST_HOPS` option for this socket +- /// +- /// For more information about this option, see +- /// [`set_multicast_hops_v6`][link]. +- /// +- /// [link]: #method.set_multicast_hops_v6 +- pub fn multicast_hops_v6(&self) -> io::Result { +- self.inner.multicast_hops_v6() +- } +- +- /// Sets the value of the `IPV6_MULTICAST_HOPS` option for this socket +- /// +- /// Indicates the number of "routers" multicast packets will transit for +- /// this socket. The default value is 1 which means that multicast packets +- /// don't leave the local network unless explicitly requested. +- pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { +- self.inner.set_multicast_hops_v6(hops) +- } +- +- /// Gets the value of the `IP_MULTICAST_IF` option for this socket. +- /// +- /// For more information about this option, see +- /// [`set_multicast_if_v4`][link]. +- /// +- /// [link]: #method.set_multicast_if_v4 +- /// +- /// Returns the interface to use for routing multicast packets. +- pub fn multicast_if_v4(&self) -> io::Result { +- self.inner.multicast_if_v4() +- } +- +- /// Sets the value of the `IP_MULTICAST_IF` option for this socket. +- /// +- /// Specifies the interface to use for routing multicast packets. +- pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { +- self.inner.set_multicast_if_v4(interface) +- } +- +- /// Gets the value of the `IPV6_MULTICAST_IF` option for this socket. +- /// +- /// For more information about this option, see +- /// [`set_multicast_if_v6`][link]. +- /// +- /// [link]: #method.set_multicast_if_v6 +- /// +- /// Returns the interface to use for routing multicast packets. +- pub fn multicast_if_v6(&self) -> io::Result { +- self.inner.multicast_if_v6() +- } +- +- /// Sets the value of the `IPV6_MULTICAST_IF` option for this socket. +- /// +- /// Specifies the interface to use for routing multicast packets. Unlike ipv4, this +- /// is generally required in ipv6 contexts where network routing prefixes may +- /// overlap. +- pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { +- self.inner.set_multicast_if_v6(interface) +- } +- +- /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. +- /// +- /// For more information about this option, see +- /// [`set_multicast_loop_v6`][link]. +- /// +- /// [link]: #method.set_multicast_loop_v6 +- pub fn multicast_loop_v6(&self) -> io::Result { +- self.inner.multicast_loop_v6() +- } +- +- /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. +- /// +- /// Controls whether this socket sees the multicast packets it sends itself. +- /// Note that this may not have any affect on IPv4 sockets. +- pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { +- self.inner.set_multicast_loop_v6(multicast_loop_v6) +- } +- +- /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. +- /// +- /// This function specifies a new multicast group for this socket to join. +- /// The address must be a valid multicast address, and `interface` is the +- /// address of the local interface with which the system should join the +- /// multicast group. If it's equal to `INADDR_ANY` then an appropriate +- /// interface is chosen by the system. +- pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { +- self.inner.join_multicast_v4(multiaddr, interface) +- } +- +- /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. +- /// +- /// This function specifies a new multicast group for this socket to join. +- /// The address must be a valid multicast address, and `interface` is the +- /// index of the interface to join/leave (or 0 to indicate any interface). +- pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { +- self.inner.join_multicast_v6(multiaddr, interface) +- } +- +- /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. +- /// +- /// For more information about this option, see +- /// [`join_multicast_v4`][link]. +- /// +- /// [link]: #method.join_multicast_v4 +- pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { +- self.inner.leave_multicast_v4(multiaddr, interface) +- } +- +- /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. +- /// +- /// For more information about this option, see +- /// [`join_multicast_v6`][link]. +- /// +- /// [link]: #method.join_multicast_v6 +- pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { +- self.inner.leave_multicast_v6(multiaddr, interface) +- } +- +- /// Reads the linger duration for this socket by getting the SO_LINGER +- /// option +- pub fn linger(&self) -> io::Result> { +- self.inner.linger() +- } +- +- /// Sets the linger duration of this socket by setting the SO_LINGER option +- pub fn set_linger(&self, dur: Option) -> io::Result<()> { +- self.inner.set_linger(dur) +- } +- +- /// Check the `SO_REUSEADDR` option on this socket. +- pub fn reuse_address(&self) -> io::Result { +- self.inner.reuse_address() ++ sys::shutdown(self.inner, how) + } ++} + +- /// Set value for the `SO_REUSEADDR` option on this socket. ++impl Socket { ++ /// Set a socket option. + /// +- /// This indicates that futher calls to `bind` may allow reuse of local +- /// addresses. For IPv4 sockets this means that a socket may bind even when +- /// there's a socket already listening on this port. +- pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { +- self.inner.set_reuse_address(reuse) ++ /// This function directly corresponds to the `setsockopt(2)` function. As ++ /// different options use different option types the user must define the ++ /// correct type `T`! ++ pub fn setsockopt(&self, level: c_int, optname: c_int, opt: &T) -> io::Result<()> { ++ sys::setsockopt(self.inner, level, optname, opt) + } + +- /// Gets the value of the `SO_RCVBUF` option on this socket. +- /// +- /// For more information about this option, see +- /// [`set_recv_buffer_size`][link]. ++ /// Get a socket option. + /// +- /// [link]: #method.set_recv_buffer_size +- pub fn recv_buffer_size(&self) -> io::Result { +- self.inner.recv_buffer_size() +- } +- +- /// Sets the value of the `SO_RCVBUF` option on this socket. ++ /// This function directly corresponds to the `getsockopt(2)` function. As ++ /// different options have different return types the user must define the ++ /// return type `T` correctly! + /// +- /// Changes the size of the operating system's receive buffer associated +- /// with the socket. +- pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { +- self.inner.set_recv_buffer_size(size) +- } +- +- /// Gets the value of the `SO_SNDBUF` option on this socket. ++ /// For an example usage see [`Socket::take_error`]. + /// +- /// For more information about this option, see [`set_send_buffer`][link]. ++ /// # Notes + /// +- /// [link]: #method.set_send_buffer +- pub fn send_buffer_size(&self) -> io::Result { +- self.inner.send_buffer_size() ++ /// Currently this will panic (in debug mode) if `T` isn't completely ++ /// written to, it doesn't support options which partly write to `T`. ++ pub fn getsockopt(&self, level: c_int, optname: c_int) -> io::Result { ++ sys::getsockopt(self.inner, level, optname) + } + +- /// Sets the value of the `SO_SNDBUF` option on this socket. ++ /// Manipulate the file descriptor options of the socket. + /// +- /// Changes the size of the operating system's send buffer associated with +- /// the socket. +- pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { +- self.inner.set_send_buffer_size(size) +- } +- +- /// Returns whether keepalive messages are enabled on this socket, and if so +- /// the duration of time between them. ++ /// This function directly corresponds to the `fcntl(2)` function. As ++ /// different command have different options the user must defined the ++ /// correct type `T`! + /// +- /// For more information about this option, see [`set_keepalive`][link]. ++ /// # Examples + /// +- /// [link]: #method.set_keepalive +- pub fn keepalive(&self) -> io::Result> { +- self.inner.keepalive() +- } +- +- /// Sets whether keepalive messages are enabled to be sent on this socket. ++ /// The following example retrieves and sets the file descriptor flags. + /// +- /// On Unix, this option will set the `SO_KEEPALIVE` as well as the +- /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). +- /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. ++ /// ``` ++ /// use std::io; ++ /// use socket2::{Domain, Socket, Type}; + /// +- /// If `None` is specified then keepalive messages are disabled, otherwise +- /// the duration specified will be the time to remain idle before sending a +- /// TCP keepalive probe. ++ /// # fn main() -> io::Result<()> { ++ /// let socket = Socket::new(Domain::ipv4(), Type::stream(), None)?; + /// +- /// Some platforms specify this value in seconds, so sub-second +- /// specifications may be omitted. +- pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { +- self.inner.set_keepalive(keepalive) +- } +- +- /// Check the value of the `SO_REUSEPORT` option on this socket. ++ /// // Retrieve the flags, using nothing `()` as argument. ++ /// let flags = socket.fcntl(libc::F_GETFD, ())?; ++ /// assert!((flags & libc::FD_CLOEXEC) == 0); + /// +- /// This function is only available on Unix. +- #[cfg(all(unix, not(target_os = "solaris")))] +- pub fn reuse_port(&self) -> io::Result { +- self.inner.reuse_port() +- } +- +- /// Set value for the `SO_REUSEPORT` option on this socket. ++ /// // Now we set the `FD_CLOEXEC` flag. ++ /// socket.fcntl(libc::F_SETFD, flags | libc::FD_CLOEXEC)?; + /// +- /// This indicates that further calls to `bind` may allow reuse of local +- /// addresses. For IPv4 sockets this means that a socket may bind even when +- /// there's a socket already listening on this port. ++ /// // Now the flag should be set. ++ /// let flags = socket.fcntl(libc::F_GETFD, ())?; ++ /// assert!((flags & libc::FD_CLOEXEC) != 0); + /// +- /// This function is only available on Unix. +- #[cfg(all(unix, not(target_os = "solaris")))] +- pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { +- self.inner.set_reuse_port(reuse) ++ /// # Ok(()) ++ /// # } ++ /// ``` ++ pub fn fcntl(&self, cmd: c_int, arg: T) -> io::Result { ++ sys::fcntl(self.inner, cmd, arg) + } + } + +-impl Read for Socket { +- fn read(&mut self, buf: &mut [u8]) -> io::Result { +- self.inner.read(buf) ++impl From for Socket { ++ fn from(socket: TcpStream) -> Socket { ++ unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } + } + +-impl<'a> Read for &'a Socket { +- fn read(&mut self, buf: &mut [u8]) -> io::Result { +- (&self.inner).read(buf) ++impl Into for Socket { ++ fn into(self) -> TcpStream { ++ unsafe { TcpStream::from_raw_fd(self.into_raw_fd()) } + } + } + +-impl Write for Socket { +- fn write(&mut self, buf: &[u8]) -> io::Result { +- self.inner.write(buf) +- } +- +- fn flush(&mut self) -> io::Result<()> { +- self.inner.flush() ++impl From for Socket { ++ fn from(socket: TcpListener) -> Socket { ++ unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } + } + +-impl<'a> Write for &'a Socket { +- fn write(&mut self, buf: &[u8]) -> io::Result { +- (&self.inner).write(buf) +- } +- +- fn flush(&mut self) -> io::Result<()> { +- (&self.inner).flush() ++impl Into for Socket { ++ fn into(self) -> TcpListener { ++ unsafe { TcpListener::from_raw_fd(self.into_raw_fd()) } + } + } + +-impl fmt::Debug for Socket { +- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +- self.inner.fmt(f) ++impl From for Socket { ++ fn from(socket: UdpSocket) -> Socket { ++ unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } + } + +-impl From for Socket { +- fn from(socket: net::TcpStream) -> Socket { +- Socket { +- inner: socket.into(), +- } ++impl Into for Socket { ++ fn into(self) -> UdpSocket { ++ unsafe { UdpSocket::from_raw_fd(self.into_raw_fd()) } + } + } + +-impl From for Socket { +- fn from(socket: net::TcpListener) -> Socket { +- Socket { +- inner: socket.into(), +- } +- } +-} +- +-impl From for Socket { +- fn from(socket: net::UdpSocket) -> Socket { +- Socket { +- inner: socket.into(), +- } +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for Socket { +- fn from(socket: UnixStream) -> Socket { +- Socket { +- inner: socket.into(), +- } +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for Socket { +- fn from(socket: UnixListener) -> Socket { +- Socket { +- inner: socket.into(), +- } +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for Socket { +- fn from(socket: UnixDatagram) -> Socket { +- Socket { +- inner: socket.into(), +- } +- } +-} +- +-impl From for net::TcpStream { +- fn from(socket: Socket) -> net::TcpStream { +- socket.inner.into() +- } +-} +- +-impl From for net::TcpListener { +- fn from(socket: Socket) -> net::TcpListener { +- socket.inner.into() +- } +-} +- +-impl From for net::UdpSocket { +- fn from(socket: Socket) -> net::UdpSocket { +- socket.inner.into() +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for UnixStream { +- fn from(socket: Socket) -> UnixStream { +- socket.inner.into() +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for UnixListener { +- fn from(socket: Socket) -> UnixListener { +- socket.inner.into() +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for UnixDatagram { +- fn from(socket: Socket) -> UnixDatagram { +- socket.inner.into() +- } +-} +- +-#[cfg(test)] +-mod test { +- use std::net::SocketAddr; +- +- use super::*; +- +- #[test] +- fn connect_timeout_unrouteable() { +- // this IP is unroutable, so connections should always time out +- let addr = "10.255.255.1:80".parse::().unwrap().into(); +- +- let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +- match socket.connect_timeout(&addr, Duration::from_millis(250)) { +- Ok(_) => panic!("unexpected success"), +- Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {} +- Err(e) => panic!("unexpected error {}", e), +- } +- } +- +- #[test] +- fn connect_timeout_unbound() { +- // bind and drop a socket to track down a "probably unassigned" port +- let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +- let addr = "127.0.0.1:0".parse::().unwrap().into(); +- socket.bind(&addr).unwrap(); +- let addr = socket.local_addr().unwrap(); +- drop(socket); +- +- let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +- match socket.connect_timeout(&addr, Duration::from_millis(250)) { +- Ok(_) => panic!("unexpected success"), +- Err(ref e) +- if e.kind() == io::ErrorKind::ConnectionRefused +- || e.kind() == io::ErrorKind::TimedOut => {} +- Err(e) => panic!("unexpected error {}", e), +- } +- } +- +- #[test] +- fn connect_timeout_valid() { +- let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +- socket +- .bind(&"127.0.0.1:0".parse::().unwrap().into()) +- .unwrap(); +- socket.listen(128).unwrap(); +- +- let addr = socket.local_addr().unwrap(); +- +- let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +- socket +- .connect_timeout(&addr, Duration::from_millis(250)) +- .unwrap(); +- } +- +- #[test] +- #[cfg(all(unix, feature = "pair", feature = "unix"))] +- fn pair() { +- let (mut a, mut b) = Socket::pair(Domain::unix(), Type::stream(), None).unwrap(); +- a.write_all(b"hello world").unwrap(); +- let mut buf = [0; 11]; +- b.read_exact(&mut buf).unwrap(); +- assert_eq!(buf, &b"hello world"[..]); +- } +- +- #[test] +- #[cfg(all(unix, feature = "unix"))] +- fn unix() { +- use tempdir::TempDir; +- +- let dir = TempDir::new("unix").unwrap(); +- let addr = SockAddr::unix(dir.path().join("sock")).unwrap(); +- +- let listener = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); +- listener.bind(&addr).unwrap(); +- listener.listen(10).unwrap(); +- +- let mut a = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); +- a.connect(&addr).unwrap(); +- +- let mut b = listener.accept().unwrap().0; +- +- a.write_all(b"hello world").unwrap(); +- let mut buf = [0; 11]; +- b.read_exact(&mut buf).unwrap(); +- assert_eq!(buf, &b"hello world"[..]); +- } +- +- #[test] +- fn keepalive() { +- let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +- socket.set_keepalive(Some(Duration::from_secs(7))).unwrap(); +- // socket.keepalive() doesn't work on Windows #24 +- #[cfg(unix)] +- assert_eq!(socket.keepalive().unwrap(), Some(Duration::from_secs(7))); +- socket.set_keepalive(None).unwrap(); +- #[cfg(unix)] +- assert_eq!(socket.keepalive().unwrap(), None); +- } +- +- #[test] +- fn nodelay() { +- let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +- +- assert!(socket.set_nodelay(true).is_ok()); +- +- let result = socket.nodelay(); +- +- assert!(result.is_ok()); +- assert!(result.unwrap()); ++impl fmt::Debug for Socket { ++ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ++ self.inner.fmt(f) + } + } +diff --git a/src/sys/unix.rs b/src/sys/unix.rs +index 3612f77..3cc08f6 100644 +--- a/src/sys/unix.rs ++++ b/src/sys/unix.rs +@@ -8,23 +8,13 @@ + // option. This file may not be copied, modified, or distributed + // except according to those terms. + +-use std::cmp; +-use std::fmt; + use std::io; +-use std::io::{ErrorKind, Read, Write}; +-use std::mem; ++use std::mem::{self, size_of, MaybeUninit}; + use std::net::Shutdown; +-use std::net::{self, Ipv4Addr, Ipv6Addr}; +-use std::ops::Neg; +-#[cfg(feature = "unix")] ++use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; + use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; +-use std::os::unix::prelude::*; +-use std::sync::atomic::{AtomicBool, Ordering}; +-use std::time::{Duration, Instant}; + +-use libc::{self, c_void, socklen_t, ssize_t}; +- +-use crate::{Domain, Type}; ++use crate::{Domain, Protocol, SockAddr, Socket, Type}; + + // Used in conversions for `Domain`, `Type` and `Protocol`. + #[allow(non_camel_case_types)] +@@ -36,43 +26,8 @@ pub(crate) use libc::{AF_INET, AF_INET6}; + pub(crate) use libc::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM}; + // Used in `Protocol`. + pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP}; +- +-cfg_if::cfg_if! { +- if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", +- target_os = "ios", target_os = "macos", +- target_os = "openbsd", target_os = "netbsd", +- target_os = "solaris", target_os = "haiku"))] { +- use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; +- use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; +- } else { +- use libc::IPV6_ADD_MEMBERSHIP; +- use libc::IPV6_DROP_MEMBERSHIP; +- } +-} +- +-cfg_if::cfg_if! { +- if #[cfg(any(target_os = "linux", target_os = "android", +- target_os = "dragonfly", target_os = "freebsd", +- target_os = "openbsd", target_os = "netbsd", +- target_os = "haiku", target_os = "bitrig"))] { +- use libc::MSG_NOSIGNAL; +- } else { +- const MSG_NOSIGNAL: c_int = 0x0; +- } +-} +- +-cfg_if::cfg_if! { +- if #[cfg(any(target_os = "macos", target_os = "ios"))] { +- use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; +- } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))] { +- use libc::SO_KEEPALIVE as KEEPALIVE_OPTION; +- } else { +- use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; +- } +-} +- +-use crate::utils::One; +-use crate::SockAddr; ++// Used in `Socket`. ++pub(crate) use std::os::unix::io::RawFd as RawSocket; + + /// Unix only API. + impl Domain { +@@ -131,1036 +86,241 @@ impl Type { + } + } + +-pub struct Socket { +- fd: c_int, ++/// Helper macro to execute a system call that returns an `io::Result`. ++macro_rules! syscall { ++ ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{ ++ let res = unsafe { libc::$fn($($arg, )*) }; ++ if res == -1 { ++ Err(std::io::Error::last_os_error()) ++ } else { ++ Ok(res) ++ } ++ }}; ++} ++ ++pub(crate) fn socket(domain: c_int, type_: c_int, protocol: c_int) -> io::Result { ++ syscall!(socket(domain, type_, protocol)).map(|fd| Socket { inner: fd }) ++} ++ ++pub(crate) fn connect( ++ sockfd: RawSocket, ++ addr: *const libc::sockaddr_storage, ++ addrlen: libc::socklen_t, ++) -> io::Result<()> { ++ // Most OSes don't actually use `sockaddr_storage` in the `connect(2)` call, ++ // but `sockaddr_storage` can be converted safely into the correct type. ++ syscall!(connect(sockfd, addr as *const _, addrlen)).map(|_| ()) ++} ++ ++pub(crate) fn bind( ++ sockfd: RawSocket, ++ addr: *const libc::sockaddr_storage, ++ addrlen: libc::socklen_t, ++) -> io::Result<()> { ++ // Most OSes don't actually use `sockaddr_storage` in the `bind(2)` call, ++ // but `sockaddr_storage` can be converted safely into the correct type. ++ syscall!(bind(sockfd, addr as *const _, addrlen)).map(|_| ()) ++} ++ ++pub(crate) fn listen(sockfd: RawSocket, backlog: c_int) -> io::Result<()> { ++ syscall!(listen(sockfd, backlog)).map(|_| ()) ++} ++ ++pub(crate) fn accept(sockfd: RawSocket) -> io::Result<(Socket, SockAddr)> { ++ let mut addr: MaybeUninit = MaybeUninit::uninit(); ++ let mut addrlen = size_of::() as libc::socklen_t; ++ syscall!(accept(sockfd, addr.as_mut_ptr() as *mut _, &mut addrlen)).map(|stream_fd| { ++ // This is safe because `accept(2)` filled in the address for us. ++ let addr = unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) }; ++ (Socket { inner: stream_fd }, addr) ++ }) ++} ++ ++pub(crate) fn getsockname(sockfd: RawSocket) -> io::Result { ++ let mut addr: MaybeUninit = MaybeUninit::uninit(); ++ let mut addrlen = size_of::() as libc::socklen_t; ++ syscall!(getsockname( ++ sockfd, ++ addr.as_mut_ptr() as *mut _, ++ &mut addrlen ++ )) ++ .map(|_| { ++ // This is safe because `getsockname(2)` filled in the address for us. ++ unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) } ++ }) ++} ++ ++pub(crate) fn getpeername(sockfd: RawSocket) -> io::Result { ++ let mut addr: MaybeUninit = MaybeUninit::uninit(); ++ let mut addrlen = size_of::() as libc::socklen_t; ++ syscall!(getpeername( ++ sockfd, ++ addr.as_mut_ptr() as *mut _, ++ &mut addrlen ++ )) ++ .map(|_| { ++ // This is safe because `getpeername(2)` filled in the address for us. ++ unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) } ++ }) ++} ++ ++pub(crate) fn shutdown(sockfd: RawSocket, how: Shutdown) -> io::Result<()> { ++ let how = match how { ++ Shutdown::Write => libc::SHUT_WR, ++ Shutdown::Read => libc::SHUT_RD, ++ Shutdown::Both => libc::SHUT_RDWR, ++ }; ++ syscall!(shutdown(sockfd, how)).map(|_| ()) ++} ++ ++pub(crate) fn setsockopt( ++ sockfd: RawSocket, ++ level: c_int, ++ optname: c_int, ++ opt: &T, ++) -> io::Result<()> { ++ syscall!(setsockopt( ++ sockfd, ++ level, ++ optname, ++ opt as *const _ as *const _, ++ size_of::() as libc::socklen_t, ++ )) ++ .map(|_| ()) ++} ++ ++pub(crate) fn getsockopt(sockfd: RawSocket, level: c_int, optname: c_int) -> io::Result { ++ let mut optval: MaybeUninit = MaybeUninit::uninit(); ++ let mut optlen = size_of::() as libc::socklen_t; ++ syscall!(getsockopt( ++ sockfd, ++ level, ++ optname, ++ optval.as_mut_ptr() as *mut _, ++ &mut optlen ++ )) ++ .map(|_| unsafe { ++ // Safe because `getsockopt(2)` initialised the value for us. ++ debug_assert_eq!(optlen as usize, size_of::()); ++ optval.assume_init() ++ }) ++} ++ ++pub(crate) fn fcntl(sockfd: RawSocket, cmd: c_int, arg: T) -> io::Result { ++ syscall!(fcntl(sockfd, cmd, arg)) + } + ++/// Unix only API. + impl Socket { +- pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result { +- unsafe { +- // On linux we first attempt to pass the SOCK_CLOEXEC flag to +- // atomically create the socket and set it as CLOEXEC. Support for +- // this option, however, was added in 2.6.27, and we still support +- // 2.6.18 as a kernel, so if the returned error is EINVAL we +- // fallthrough to the fallback. +- #[cfg(target_os = "linux")] +- { +- match cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, protocol)) { +- Ok(fd) => return Ok(Socket::from_raw_fd(fd)), +- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} +- Err(e) => return Err(e), +- } +- } +- +- let fd = cvt(libc::socket(family, ty, protocol))?; +- let fd = Socket::from_raw_fd(fd); +- set_cloexec(fd.as_raw_fd())?; +- #[cfg(target_os = "macos")] +- { +- fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; +- } +- Ok(fd) +- } +- } +- +- pub fn pair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<(Socket, Socket)> { +- unsafe { +- let mut fds = [0, 0]; +- cvt(libc::socketpair(family, ty, protocol, fds.as_mut_ptr()))?; +- let fds = (Socket::from_raw_fd(fds[0]), Socket::from_raw_fd(fds[1])); +- set_cloexec(fds.0.as_raw_fd())?; +- set_cloexec(fds.1.as_raw_fd())?; +- #[cfg(target_os = "macos")] +- { +- fds.0 +- .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; +- fds.1 +- .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; +- } +- Ok(fds) +- } +- } +- +- pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { +- unsafe { cvt(libc::bind(self.fd, addr.as_ptr(), addr.len() as _)).map(|_| ()) } +- } +- +- pub fn listen(&self, backlog: i32) -> io::Result<()> { +- unsafe { cvt(libc::listen(self.fd, backlog)).map(|_| ()) } +- } +- +- pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { +- unsafe { cvt(libc::connect(self.fd, addr.as_ptr(), addr.len())).map(|_| ()) } +- } +- +- pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { +- self.set_nonblocking(true)?; +- let r = self.connect(addr); +- self.set_nonblocking(false)?; +- +- match r { +- Ok(()) => return Ok(()), +- // there's no io::ErrorKind conversion registered for EINPROGRESS :( +- Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} +- Err(e) => return Err(e), +- } +- +- let mut pollfd = libc::pollfd { +- fd: self.fd, +- events: libc::POLLOUT, +- revents: 0, +- }; +- +- if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { +- return Err(io::Error::new( +- io::ErrorKind::InvalidInput, +- "cannot set a 0 duration timeout", +- )); +- } +- +- let start = Instant::now(); +- +- loop { +- let elapsed = start.elapsed(); +- if elapsed >= timeout { +- return Err(io::Error::new( +- io::ErrorKind::TimedOut, +- "connection timed out", +- )); +- } +- +- let timeout = timeout - elapsed; +- let mut timeout = timeout +- .as_secs() +- .saturating_mul(1_000) +- .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); +- if timeout == 0 { +- timeout = 1; +- } +- +- let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; +- +- match unsafe { libc::poll(&mut pollfd, 1, timeout) } { +- -1 => { +- let err = io::Error::last_os_error(); +- if err.kind() != io::ErrorKind::Interrupted { +- return Err(err); +- } +- } +- 0 => { +- return Err(io::Error::new( +- io::ErrorKind::TimedOut, +- "connection timed out", +- )) +- } +- _ => { +- // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look +- // for POLLHUP rather than read readiness +- if pollfd.revents & libc::POLLHUP != 0 { +- let e = self.take_error()?.unwrap_or_else(|| { +- io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") +- }); +- return Err(e); +- } +- return Ok(()); +- } +- } +- } +- } +- +- pub fn local_addr(&self) -> io::Result { +- unsafe { +- let mut storage: libc::sockaddr_storage = mem::zeroed(); +- let mut len = mem::size_of_val(&storage) as libc::socklen_t; +- cvt(libc::getsockname( +- self.fd, +- &mut storage as *mut _ as *mut _, +- &mut len, +- ))?; +- Ok(SockAddr::from_raw_parts( +- &storage as *const _ as *const _, +- len, +- )) +- } +- } +- +- pub fn peer_addr(&self) -> io::Result { +- unsafe { +- let mut storage: libc::sockaddr_storage = mem::zeroed(); +- let mut len = mem::size_of_val(&storage) as libc::socklen_t; +- cvt(libc::getpeername( +- self.fd, +- &mut storage as *mut _ as *mut _, +- &mut len, +- ))?; +- Ok(SockAddr::from_raw_parts( +- &storage as *const _ as *const _, +- len, +- )) +- } +- } +- +- pub fn try_clone(&self) -> io::Result { +- // implementation lifted from libstd +- #[cfg(any(target_os = "android", target_os = "haiku"))] +- use libc::F_DUPFD as F_DUPFD_CLOEXEC; +- #[cfg(not(any(target_os = "android", target_os = "haiku")))] +- use libc::F_DUPFD_CLOEXEC; +- +- static CLOEXEC_FAILED: AtomicBool = AtomicBool::new(false); +- unsafe { +- if !CLOEXEC_FAILED.load(Ordering::Relaxed) { +- match cvt(libc::fcntl(self.fd, F_DUPFD_CLOEXEC, 0)) { +- Ok(fd) => { +- let fd = Socket::from_raw_fd(fd); +- if cfg!(target_os = "linux") { +- set_cloexec(fd.as_raw_fd())?; +- } +- return Ok(fd); +- } +- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { +- CLOEXEC_FAILED.store(true, Ordering::Relaxed); +- } +- Err(e) => return Err(e), +- } +- } +- let fd = cvt(libc::fcntl(self.fd, libc::F_DUPFD, 0))?; +- let fd = Socket::from_raw_fd(fd); +- set_cloexec(fd.as_raw_fd())?; +- Ok(fd) +- } +- } +- +- #[allow(unused_mut)] +- pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { +- let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; +- let mut len = mem::size_of_val(&storage) as socklen_t; +- +- let mut socket = None; +- #[cfg(target_os = "linux")] +- { +- let res = cvt_r(|| unsafe { +- libc::syscall( +- libc::SYS_accept4, +- self.fd as libc::c_long, +- &mut storage as *mut _ as libc::c_long, +- &mut len, +- libc::SOCK_CLOEXEC as libc::c_long, +- ) as libc::c_int +- }); +- match res { +- Ok(fd) => socket = Some(Socket { fd: fd }), +- Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} +- Err(e) => return Err(e), +- } +- } +- +- let socket = match socket { +- Some(socket) => socket, +- None => unsafe { +- let fd = +- cvt_r(|| libc::accept(self.fd, &mut storage as *mut _ as *mut _, &mut len))?; +- let fd = Socket::from_raw_fd(fd); +- set_cloexec(fd.as_raw_fd())?; +- fd +- }, +- }; +- let addr = unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, len) }; +- Ok((socket, addr)) +- } +- +- pub fn take_error(&self) -> io::Result> { +- unsafe { +- let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_ERROR)?; +- if raw == 0 { +- Ok(None) +- } else { +- Ok(Some(io::Error::from_raw_os_error(raw as i32))) +- } +- } +- } +- +- pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { +- unsafe { +- let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; +- let new = if nonblocking { +- previous | libc::O_NONBLOCK +- } else { +- previous & !libc::O_NONBLOCK +- }; +- if new != previous { +- cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; +- } +- Ok(()) +- } +- } +- +- pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { +- let how = match how { +- Shutdown::Write => libc::SHUT_WR, +- Shutdown::Read => libc::SHUT_RD, +- Shutdown::Both => libc::SHUT_RDWR, +- }; +- cvt(unsafe { libc::shutdown(self.fd, how) })?; +- Ok(()) +- } +- +- pub fn recv(&self, buf: &mut [u8]) -> io::Result { +- unsafe { +- let n = cvt({ +- libc::recv( +- self.fd, +- buf.as_mut_ptr() as *mut c_void, +- cmp::min(buf.len(), max_len()), +- 0, +- ) +- })?; +- Ok(n as usize) +- } +- } +- +- pub fn peek(&self, buf: &mut [u8]) -> io::Result { +- unsafe { +- let n = cvt({ +- libc::recv( +- self.fd, +- buf.as_mut_ptr() as *mut c_void, +- cmp::min(buf.len(), max_len()), +- libc::MSG_PEEK, +- ) +- })?; +- Ok(n as usize) +- } +- } +- +- pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { +- self.recvfrom(buf, 0) +- } +- +- pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { +- self.recvfrom(buf, libc::MSG_PEEK) +- } +- +- fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { +- unsafe { +- let mut storage: libc::sockaddr_storage = mem::zeroed(); +- let mut addrlen = mem::size_of_val(&storage) as socklen_t; +- +- let n = cvt({ +- libc::recvfrom( +- self.fd, +- buf.as_mut_ptr() as *mut c_void, +- cmp::min(buf.len(), max_len()), +- flags, +- &mut storage as *mut _ as *mut _, +- &mut addrlen, +- ) +- })?; +- let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen); +- Ok((n as usize, addr)) +- } +- } +- +- pub fn send(&self, buf: &[u8]) -> io::Result { +- unsafe { +- let n = cvt({ +- libc::send( +- self.fd, +- buf.as_ptr() as *const c_void, +- cmp::min(buf.len(), max_len()), +- MSG_NOSIGNAL, +- ) +- })?; +- Ok(n as usize) +- } +- } +- +- pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result { +- unsafe { +- let n = cvt({ +- libc::sendto( +- self.fd, +- buf.as_ptr() as *const c_void, +- cmp::min(buf.len(), max_len()), +- MSG_NOSIGNAL, +- addr.as_ptr(), +- addr.len(), +- ) +- })?; +- Ok(n as usize) +- } +- } +- +- // ================================================ +- +- pub fn ttl(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?; +- Ok(raw as u32) +- } +- } +- +- pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { +- unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) } +- } +- +- pub fn unicast_hops_v6(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?; +- Ok(raw as u32) +- } +- } +- +- pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> { +- unsafe { +- self.setsockopt( +- libc::IPPROTO_IPV6 as c_int, +- libc::IPV6_UNICAST_HOPS, +- hops as c_int, +- ) +- } +- } +- +- pub fn only_v6(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY)?; +- Ok(raw != 0) +- } +- } +- +- pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { +- unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, only_v6 as c_int) } +- } +- +- pub fn read_timeout(&self) -> io::Result> { +- unsafe { +- Ok(timeval2dur( +- self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO)?, +- )) +- } +- } +- +- pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { +- unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO, dur2timeval(dur)?) } +- } +- +- pub fn write_timeout(&self) -> io::Result> { +- unsafe { +- Ok(timeval2dur( +- self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO)?, +- )) +- } +- } +- +- pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { +- unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO, dur2timeval(dur)?) } +- } +- +- pub fn nodelay(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY)?; +- Ok(raw != 0) +- } +- } +- +- pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { +- unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } +- } +- +- pub fn broadcast(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST)?; +- Ok(raw != 0) +- } +- } +- +- pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { +- unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST, broadcast as c_int) } +- } +- +- pub fn multicast_loop_v4(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP)?; +- Ok(raw != 0) +- } +- } +- +- pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { +- unsafe { +- self.setsockopt( +- libc::IPPROTO_IP, +- libc::IP_MULTICAST_LOOP, +- multicast_loop_v4 as c_int, +- ) +- } +- } +- +- pub fn multicast_ttl_v4(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_TTL)?; +- Ok(raw as u32) +- } +- } +- +- pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { +- unsafe { +- self.setsockopt( +- libc::IPPROTO_IP, +- libc::IP_MULTICAST_TTL, +- multicast_ttl_v4 as c_int, +- ) +- } +- } +- +- pub fn multicast_hops_v6(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS)?; +- Ok(raw as u32) +- } +- } +- +- pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { +- unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS, hops as c_int) } +- } +- +- pub fn multicast_if_v4(&self) -> io::Result { +- unsafe { +- let imr_interface: libc::in_addr = +- self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF)?; +- Ok(from_s_addr(imr_interface.s_addr)) +- } +- } +- +- pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { +- let interface = to_s_addr(interface); +- let imr_interface = libc::in_addr { s_addr: interface }; +- +- unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF, imr_interface) } +- } +- +- pub fn multicast_if_v6(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_IF)?; +- Ok(raw as u32) +- } +- } +- +- pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { +- unsafe { +- self.setsockopt( +- libc::IPPROTO_IPV6, +- libc::IPV6_MULTICAST_IF, +- interface as c_int, +- ) +- } +- } +- +- pub fn multicast_loop_v6(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_LOOP)?; +- Ok(raw != 0) +- } +- } +- +- pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { +- unsafe { +- self.setsockopt( +- libc::IPPROTO_IPV6, +- libc::IPV6_MULTICAST_LOOP, +- multicast_loop_v6 as c_int, +- ) +- } +- } +- +- pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { +- let multiaddr = to_s_addr(multiaddr); +- let interface = to_s_addr(interface); +- let mreq = libc::ip_mreq { +- imr_multiaddr: libc::in_addr { s_addr: multiaddr }, +- imr_interface: libc::in_addr { s_addr: interface }, +- }; +- unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, mreq) } +- } +- +- pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { +- let multiaddr = to_in6_addr(multiaddr); +- let mreq = libc::ipv6_mreq { +- ipv6mr_multiaddr: multiaddr, +- ipv6mr_interface: to_ipv6mr_interface(interface), +- }; +- unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) } +- } +- +- pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { +- let multiaddr = to_s_addr(multiaddr); +- let interface = to_s_addr(interface); +- let mreq = libc::ip_mreq { +- imr_multiaddr: libc::in_addr { s_addr: multiaddr }, +- imr_interface: libc::in_addr { s_addr: interface }, +- }; +- unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, mreq) } +- } +- +- pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { +- let multiaddr = to_in6_addr(multiaddr); +- let mreq = libc::ipv6_mreq { +- ipv6mr_multiaddr: multiaddr, +- ipv6mr_interface: to_ipv6mr_interface(interface), +- }; +- unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) } +- } +- +- pub fn linger(&self) -> io::Result> { +- unsafe { +- Ok(linger2dur( +- self.getsockopt(libc::SOL_SOCKET, libc::SO_LINGER)?, +- )) +- } +- } +- +- pub fn set_linger(&self, dur: Option) -> io::Result<()> { +- unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_LINGER, dur2linger(dur)) } +- } +- +- pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { +- unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR, reuse as c_int) } +- } +- +- pub fn reuse_address(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR)?; +- Ok(raw != 0) +- } +- } +- +- pub fn recv_buffer_size(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF)?; +- Ok(raw as usize) +- } +- } +- +- pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { +- unsafe { +- // TODO: casting usize to a c_int should be a checked cast +- self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF, size as c_int) +- } +- } +- +- pub fn send_buffer_size(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF)?; +- Ok(raw as usize) +- } +- } +- +- pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { +- unsafe { +- // TODO: casting usize to a c_int should be a checked cast +- self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF, size as c_int) +- } +- } +- +- pub fn keepalive(&self) -> io::Result> { +- unsafe { +- let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_KEEPALIVE)?; +- if raw == 0 { +- return Ok(None); +- } +- let secs: c_int = self.getsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION)?; +- Ok(Some(Duration::new(secs as u64, 0))) +- } +- } +- +- pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { +- unsafe { +- self.setsockopt( +- libc::SOL_SOCKET, +- libc::SO_KEEPALIVE, +- keepalive.is_some() as c_int, +- )?; +- if let Some(dur) = keepalive { +- // TODO: checked cast here +- self.setsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION, dur.as_secs() as c_int)?; +- } +- Ok(()) +- } +- } +- +- #[cfg(all(unix, not(target_os = "solaris")))] +- pub fn reuse_port(&self) -> io::Result { +- unsafe { +- let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?; +- Ok(raw != 0) +- } +- } +- +- #[cfg(all(unix, not(target_os = "solaris")))] +- pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { +- unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) } +- } +- +- unsafe fn setsockopt(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> +- where +- T: Copy, +- { +- let payload = &payload as *const T as *const c_void; +- cvt(libc::setsockopt( +- self.fd, +- opt, +- val, +- payload, +- mem::size_of::() as libc::socklen_t, +- ))?; +- Ok(()) +- } +- +- unsafe fn getsockopt(&self, opt: c_int, val: c_int) -> io::Result { +- let mut slot: T = mem::zeroed(); +- let mut len = mem::size_of::() as libc::socklen_t; +- cvt(libc::getsockopt( +- self.fd, +- opt, +- val, +- &mut slot as *mut _ as *mut _, +- &mut len, +- ))?; +- assert_eq!(len as usize, mem::size_of::()); +- Ok(slot) +- } +-} +- +-impl Read for Socket { +- fn read(&mut self, buf: &mut [u8]) -> io::Result { +- <&Socket>::read(&mut &*self, buf) +- } +-} +- +-impl<'a> Read for &'a Socket { +- fn read(&mut self, buf: &mut [u8]) -> io::Result { +- unsafe { +- let n = cvt({ +- libc::read( +- self.fd, +- buf.as_mut_ptr() as *mut c_void, +- cmp::min(buf.len(), max_len()), +- ) +- })?; +- Ok(n as usize) +- } +- } +-} +- +-impl Write for Socket { +- fn write(&mut self, buf: &[u8]) -> io::Result { +- <&Socket>::write(&mut &*self, buf) +- } +- +- fn flush(&mut self) -> io::Result<()> { +- <&Socket>::flush(&mut &*self) +- } +-} +- +-impl<'a> Write for &'a Socket { +- fn write(&mut self, buf: &[u8]) -> io::Result { +- self.send(buf) +- } +- +- fn flush(&mut self) -> io::Result<()> { +- Ok(()) +- } +-} +- +-impl fmt::Debug for Socket { +- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +- let mut f = f.debug_struct("Socket"); +- f.field("fd", &self.fd); +- if let Ok(addr) = self.local_addr() { +- f.field("local_addr", &addr); +- } +- if let Ok(addr) = self.peer_addr() { +- f.field("peer_addr", &addr); +- } +- f.finish() +- } +-} +- +-impl AsRawFd for Socket { +- fn as_raw_fd(&self) -> c_int { +- self.fd +- } +-} +- +-impl IntoRawFd for Socket { +- fn into_raw_fd(self) -> c_int { +- let fd = self.fd; +- mem::forget(self); +- return fd; +- } +-} +- +-impl FromRawFd for Socket { +- unsafe fn from_raw_fd(fd: c_int) -> Socket { +- Socket { fd: fd } +- } +-} +- +-impl AsRawFd for crate::Socket { +- fn as_raw_fd(&self) -> c_int { +- self.inner.as_raw_fd() +- } +-} +- +-impl IntoRawFd for crate::Socket { +- fn into_raw_fd(self) -> c_int { +- self.inner.into_raw_fd() +- } +-} +- +-impl FromRawFd for crate::Socket { +- unsafe fn from_raw_fd(fd: c_int) -> crate::Socket { +- crate::Socket { +- inner: Socket::from_raw_fd(fd), +- } +- } +-} +- +-impl Drop for Socket { +- fn drop(&mut self) { +- unsafe { +- let _ = libc::close(self.fd); +- } +- } +-} +- +-impl From for net::TcpStream { +- fn from(socket: Socket) -> net::TcpStream { +- unsafe { net::TcpStream::from_raw_fd(socket.into_raw_fd()) } +- } +-} +- +-impl From for net::TcpListener { +- fn from(socket: Socket) -> net::TcpListener { +- unsafe { net::TcpListener::from_raw_fd(socket.into_raw_fd()) } +- } +-} +- +-impl From for net::UdpSocket { +- fn from(socket: Socket) -> net::UdpSocket { +- unsafe { net::UdpSocket::from_raw_fd(socket.into_raw_fd()) } +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for UnixStream { +- fn from(socket: Socket) -> UnixStream { +- unsafe { UnixStream::from_raw_fd(socket.into_raw_fd()) } +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for UnixListener { +- fn from(socket: Socket) -> UnixListener { +- unsafe { UnixListener::from_raw_fd(socket.into_raw_fd()) } +- } +-} +- +-#[cfg(all(unix, feature = "unix"))] +-impl From for UnixDatagram { +- fn from(socket: Socket) -> UnixDatagram { +- unsafe { UnixDatagram::from_raw_fd(socket.into_raw_fd()) } +- } +-} +- +-impl From for Socket { +- fn from(socket: net::TcpStream) -> Socket { +- unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } ++ /// Creates a pair of sockets which are connected to each other. ++ /// ++ /// This function corresponds to `socketpair(2)`. ++ pub fn pair( ++ domain: Domain, ++ type_: Type, ++ protocol: Option, ++ ) -> io::Result<(Socket, Socket)> { ++ let mut fds = [0, 0]; ++ let protocol = protocol.map(|p| p.0).unwrap_or(0); ++ syscall!(socketpair(domain.0, type_.0, protocol, fds.as_mut_ptr())) ++ .map(|_| (Socket { inner: fds[0] }, Socket { inner: fds[1] })) ++ } ++ ++ /// Accept a new incoming connection from this listener. ++ /// ++ /// This function directly corresponds to the `accept4(2)` function. ++ /// ++ /// # Notes ++ /// ++ /// This only available on Android, DragonFlyBSD, FreeBSD, Linux and ++ /// OpenBSD. Once https://github.com/rust-lang/libc/issues/1636 is fixed ++ /// NetBSD will also support it. ++ #[cfg(any( ++ target_os = "android", ++ target_os = "dragonfly", ++ target_os = "freebsd", ++ target_os = "linux", ++ // NetBSD 8.0 actually has `accept4(2)`, but libc doesn't expose it ++ // (yet). See https://github.com/rust-lang/libc/issues/1636. ++ //target_os = "netbsd", ++ target_os = "openbsd" ++ ))] ++ pub fn accept4(&self, flags: c_int) -> io::Result<(Socket, SockAddr)> { ++ let mut addr: MaybeUninit = MaybeUninit::uninit(); ++ let mut addrlen = size_of::() as libc::socklen_t; ++ syscall!(accept4( ++ self.inner, ++ addr.as_mut_ptr() as *mut _, ++ &mut addrlen, ++ flags ++ )) ++ .map(|stream_fd| { ++ // This is safe because `accept(2)` filled in the address for us. ++ let addr = unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) }; ++ (Socket { inner: stream_fd }, addr) ++ }) + } + } + +-impl From for Socket { +- fn from(socket: net::TcpListener) -> Socket { ++impl From for Socket { ++ fn from(socket: UnixStream) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } + } + +-impl From for Socket { +- fn from(socket: net::UdpSocket) -> Socket { +- unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } ++impl Into for Socket { ++ fn into(self) -> UnixStream { ++ unsafe { UnixStream::from_raw_fd(self.into_raw_fd()) } + } + } + +-#[cfg(all(unix, feature = "unix"))] +-impl From for Socket { +- fn from(socket: UnixStream) -> Socket { ++impl From for Socket { ++ fn from(socket: UnixListener) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } + } + +-#[cfg(all(unix, feature = "unix"))] +-impl From for Socket { +- fn from(socket: UnixListener) -> Socket { +- unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } ++impl Into for Socket { ++ fn into(self) -> UnixListener { ++ unsafe { UnixListener::from_raw_fd(self.into_raw_fd()) } + } + } + +-#[cfg(all(unix, feature = "unix"))] + impl From for Socket { + fn from(socket: UnixDatagram) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } + } + +-fn max_len() -> usize { +- // The maximum read limit on most posix-like systems is `SSIZE_MAX`, +- // with the man page quoting that if the count of bytes to read is +- // greater than `SSIZE_MAX` the result is "unspecified". +- // +- // On macOS, however, apparently the 64-bit libc is either buggy or +- // intentionally showing odd behavior by rejecting any read with a size +- // larger than or equal to INT_MAX. To handle both of these the read +- // size is capped on both platforms. +- if cfg!(target_os = "macos") { +- ::max_value() as usize - 1 +- } else { +- ::max_value() as usize +- } +-} +- +-fn cvt>(t: T) -> io::Result { +- let one: T = T::one(); +- if t == -one { +- Err(io::Error::last_os_error()) +- } else { +- Ok(t) ++impl Into for Socket { ++ fn into(self) -> UnixDatagram { ++ unsafe { UnixDatagram::from_raw_fd(self.into_raw_fd()) } + } + } + +-fn cvt_r(mut f: F) -> io::Result +-where +- F: FnMut() -> T, +- T: One + PartialEq + Neg, +-{ +- loop { +- match cvt(f()) { +- Err(ref e) if e.kind() == ErrorKind::Interrupted => {} +- other => return other, +- } +- } +-} +- +-fn set_cloexec(fd: c_int) -> io::Result<()> { +- unsafe { +- let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; +- let new = previous | libc::FD_CLOEXEC; +- if new != previous { +- cvt(libc::fcntl(fd, libc::F_SETFD, new))?; +- } +- Ok(()) +- } +-} +- +-fn dur2timeval(dur: Option) -> io::Result { +- match dur { +- Some(dur) => { +- if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { +- return Err(io::Error::new( +- io::ErrorKind::InvalidInput, +- "cannot set a 0 duration timeout", +- )); +- } +- +- let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { +- libc::time_t::max_value() +- } else { +- dur.as_secs() as libc::time_t +- }; +- let mut timeout = libc::timeval { +- tv_sec: secs, +- tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, +- }; +- if timeout.tv_sec == 0 && timeout.tv_usec == 0 { +- timeout.tv_usec = 1; +- } +- Ok(timeout) +- } +- None => Ok(libc::timeval { +- tv_sec: 0, +- tv_usec: 0, +- }), ++impl FromRawFd for Socket { ++ unsafe fn from_raw_fd(fd: RawFd) -> Socket { ++ Socket { inner: fd } + } + } + +-fn timeval2dur(raw: libc::timeval) -> Option { +- if raw.tv_sec == 0 && raw.tv_usec == 0 { +- None +- } else { +- let sec = raw.tv_sec as u64; +- let nsec = (raw.tv_usec as u32) * 1000; +- Some(Duration::new(sec, nsec)) ++impl AsRawFd for Socket { ++ fn as_raw_fd(&self) -> RawFd { ++ self.inner + } + } + +-fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { +- let octets = addr.octets(); +- crate::hton( +- ((octets[0] as libc::in_addr_t) << 24) +- | ((octets[1] as libc::in_addr_t) << 16) +- | ((octets[2] as libc::in_addr_t) << 8) +- | ((octets[3] as libc::in_addr_t) << 0), +- ) +-} +- +-fn from_s_addr(in_addr: libc::in_addr_t) -> Ipv4Addr { +- let h_addr = crate::ntoh(in_addr); +- +- let a: u8 = (h_addr >> 24) as u8; +- let b: u8 = (h_addr >> 16) as u8; +- let c: u8 = (h_addr >> 8) as u8; +- let d: u8 = (h_addr >> 0) as u8; +- +- Ipv4Addr::new(a, b, c, d) +-} +- +-fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr { +- let mut ret: libc::in6_addr = unsafe { mem::zeroed() }; +- ret.s6_addr = addr.octets(); +- return ret; +-} +- +-#[cfg(target_os = "android")] +-fn to_ipv6mr_interface(value: u32) -> c_int { +- value as c_int +-} +- +-#[cfg(not(target_os = "android"))] +-fn to_ipv6mr_interface(value: u32) -> libc::c_uint { +- value as libc::c_uint +-} +- +-fn linger2dur(linger_opt: libc::linger) -> Option { +- if linger_opt.l_onoff == 0 { +- None +- } else { +- Some(Duration::from_secs(linger_opt.l_linger as u64)) ++impl IntoRawFd for Socket { ++ fn into_raw_fd(self) -> RawFd { ++ let fd = self.inner; ++ mem::forget(self); ++ fd + } + } + +-fn dur2linger(dur: Option) -> libc::linger { +- match dur { +- Some(d) => libc::linger { +- l_onoff: 1, +- l_linger: d.as_secs() as c_int, +- }, +- None => libc::linger { +- l_onoff: 0, +- l_linger: 0, +- }, ++impl Drop for Socket { ++ fn drop(&mut self) { ++ // Can't handle the error here, nor can we do much with it. ++ let _ = unsafe { libc::close(self.inner) }; + } + } +- +-#[test] +-fn test_ip() { +- let ip = Ipv4Addr::new(127, 0, 0, 1); +- assert_eq!(ip, from_s_addr(to_s_addr(&ip))); +-} +diff --git a/tests/socket.rs b/tests/socket.rs +new file mode 100644 +index 0000000..66058e1 +--- /dev/null ++++ b/tests/socket.rs +@@ -0,0 +1,122 @@ ++use std::net::{TcpListener, TcpStream, UdpSocket}; ++ ++use socket2::{Domain, Socket, Type}; ++ ++mod util; ++use util::any_local_ipv4_addr; ++ ++#[test] ++fn from_std_tcp_stream() { ++ let listener = TcpListener::bind(any_local_ipv4_addr()).unwrap(); ++ let tcp_socket = TcpStream::connect(listener.local_addr().unwrap()).unwrap(); ++ let socket: Socket = tcp_socket.into(); ++ drop(socket); ++} ++ ++#[test] ++fn from_std_tcp_listener() { ++ let tcp_socket = TcpListener::bind(any_local_ipv4_addr()).unwrap(); ++ let socket: Socket = tcp_socket.into(); ++ drop(socket); ++} ++ ++#[test] ++fn from_std_udp_socket() { ++ let udp_socket = UdpSocket::bind(any_local_ipv4_addr()).unwrap(); ++ let socket: Socket = udp_socket.into(); ++ drop(socket); ++} ++ ++#[test] ++fn into_std_tcp_stream() { ++ let socket: Socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); ++ let tcp_socket: TcpStream = socket.into(); ++ drop(tcp_socket); ++} ++ ++#[test] ++fn into_std_tcp_listener() { ++ let socket: Socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); ++ let tcp_socket: TcpListener = socket.into(); ++ drop(tcp_socket); ++} ++ ++#[test] ++fn into_std_udp_socket() { ++ let socket: Socket = Socket::new(Domain::ipv4(), Type::dgram(), None).unwrap(); ++ let udp_socket: UdpSocket = socket.into(); ++ drop(udp_socket); ++} ++ ++#[test] ++fn socket_connect_tcp() { ++ let listener = TcpListener::bind(any_local_ipv4_addr()).unwrap(); ++ let addr = listener.local_addr().unwrap(); ++ ++ let socket: TcpStream = Socket::new(Domain::ipv4(), Type::stream(), None) ++ .and_then(|socket| socket.connect(&addr.into()).map(|()| socket.into())) ++ .unwrap(); ++ assert_eq!(socket.peer_addr().unwrap(), addr); ++ ++ let (stream, peer_addr) = listener.accept().unwrap(); ++ let socket_local_addr = socket.local_addr().unwrap(); ++ assert_eq!(peer_addr, socket_local_addr); ++ assert_eq!(stream.peer_addr().unwrap(), socket_local_addr); ++} ++ ++#[test] ++fn socket_bind_tcp() { ++ let socket: TcpListener = Socket::new(Domain::ipv4(), Type::stream(), None) ++ .and_then(|socket| { ++ socket ++ .bind(&any_local_ipv4_addr().into()) ++ .map(|()| socket.into()) ++ }) ++ .unwrap(); ++ ++ assert!(socket.local_addr().unwrap().ip().is_loopback()) ++} ++ ++#[test] ++fn socket_listen_tcp() { ++ let socket: TcpListener = Socket::new(Domain::ipv4(), Type::stream(), None) ++ .and_then(|socket| { ++ socket.bind(&any_local_ipv4_addr().into())?; ++ socket.listen(1024)?; ++ Ok(socket.into()) ++ }) ++ .unwrap(); ++ let addr = socket.local_addr().unwrap(); ++ ++ let stream = TcpStream::connect(addr).unwrap(); ++ let stream_addr = stream.local_addr().unwrap(); ++ ++ let (accepted_stream, peer_addr) = socket.accept().unwrap(); ++ assert_eq!(peer_addr, stream_addr); ++ assert_eq!(accepted_stream.peer_addr().unwrap(), stream_addr); ++} ++ ++// Also tests `local_addr` and `peer_addr`. ++#[test] ++fn socket_accept_tcp() { ++ let socket: Socket = Socket::new(Domain::ipv4(), Type::stream(), None) ++ .and_then(|socket| { ++ socket.bind(&any_local_ipv4_addr().into())?; ++ socket.listen(1024)?; ++ Ok(socket.into()) ++ }) ++ .unwrap(); ++ let addr = socket.local_addr().unwrap(); ++ let addr = addr.as_std().unwrap(); ++ ++ let stream = TcpStream::connect(addr).unwrap(); ++ let stream_addr = stream.local_addr().unwrap(); ++ ++ let (accepted_socket, peer_addr) = socket.accept().unwrap(); ++ let peer_addr = peer_addr.as_std().unwrap(); ++ assert_eq!(peer_addr, stream_addr); ++ assert_eq!( ++ accepted_socket.peer_addr().unwrap().as_std().unwrap(), ++ stream_addr ++ ); ++} +diff --git a/tests/unix.rs b/tests/unix.rs +new file mode 100644 +index 0000000..3af40f6 +--- /dev/null ++++ b/tests/unix.rs +@@ -0,0 +1,60 @@ ++//! Tests for Unix only API. ++ ++#![cfg(unix)] ++ ++use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; ++ ++use socket2::{Domain, Socket, Type}; ++ ++mod util; ++use util::temp_file; ++ ++#[test] ++fn from_std_unix_stream() { ++ let path = temp_file("from_std_unix_stream"); ++ let listener = UnixListener::bind(&path).unwrap(); ++ let stream = UnixStream::connect(&path).unwrap(); ++ let socket: Socket = stream.into(); ++ drop(socket); ++ drop(listener); ++} ++ ++#[test] ++fn from_std_unix_listener() { ++ let path = temp_file("from_std_unix_listener"); ++ let listener = UnixListener::bind(&path).unwrap(); ++ let socket: Socket = listener.into(); ++ drop(socket); ++} ++ ++#[test] ++fn from_std_unix_socket() { ++ let path = temp_file("from_std_unix_socket"); ++ let datagram = UnixDatagram::bind(&path).unwrap(); ++ let socket: Socket = datagram.into(); ++ drop(socket); ++} ++ ++#[test] ++fn into_std_unix_stream() { ++ let socket: Socket = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); ++ let unix_socket: UnixStream = socket.into(); ++ drop(unix_socket); ++} ++ ++#[test] ++fn into_std_tcp_listener() { ++ let socket: Socket = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); ++ let unix_socket: UnixListener = socket.into(); ++ drop(unix_socket); ++} ++ ++#[test] ++fn into_std_udp_socket() { ++ let socket: Socket = Socket::new(Domain::unix(), Type::dgram(), None).unwrap(); ++ let unix_socket: UnixDatagram = socket.into(); ++ drop(unix_socket); ++} ++ ++// TODO: test accept4. ++// TODO: test pair. +diff --git a/tests/util/mod.rs b/tests/util/mod.rs +new file mode 100644 +index 0000000..1744e40 +--- /dev/null ++++ b/tests/util/mod.rs +@@ -0,0 +1,49 @@ ++// Not all tests use all functions. ++#![allow(dead_code)] ++ ++use std::net::SocketAddr; ++use std::path::PathBuf; ++use std::sync::Once; ++use std::{env, fs}; ++ ++/// Bind to any port on localhost. ++pub fn any_local_ipv4_addr() -> SocketAddr { ++ "127.0.0.1:0".parse().unwrap() ++} ++ ++/* TODO: needed? ++/// Bind to any port on localhost, using a IPv6 address. ++pub fn any_local_ipv6_addr() -> SocketAddr { ++ "[::1]:0".parse().unwrap() ++} ++*/ ++ ++/// Returns a path to a temporary file using `name` as filename. ++pub fn temp_file(name: &'static str) -> PathBuf { ++ init(); ++ let mut path = temp_dir(); ++ path.push(name); ++ path ++} ++ ++pub fn init() { ++ static INIT: Once = Once::new(); ++ ++ INIT.call_once(|| { ++ // Remove all temporary files from previous test runs. ++ let dir = temp_dir(); ++ let _ = fs::remove_dir_all(&dir); ++ fs::create_dir_all(&dir).expect("unable to create temporary directory"); ++ }) ++} ++ ++/// Returns the temporary directory for test files. ++/// ++/// # Notes ++/// ++/// `init` must be called before this. ++fn temp_dir() -> PathBuf { ++ let mut path = env::temp_dir(); ++ path.push("socket_tests"); ++ path ++} diff --git a/vendor/socket2/Cargo.toml b/vendor/socket2/Cargo.toml index 76428698fb..4d674a5b3d 100644 --- a/vendor/socket2/Cargo.toml +++ b/vendor/socket2/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "socket2" -version = "0.3.12" +version = "0.3.16" authors = ["Alex Crichton "] description = "Utilities for handling networking sockets with a maximal amount of configuration\npossible intended.\n" homepage = "https://github.com/alexcrichton/socket2-rs" @@ -34,6 +34,7 @@ version = "0.1.6" [target."cfg(any(unix, target_os = \"redox\"))".dependencies.libc] version = "0.2.66" +features = ["align"] [target."cfg(target_os = \"redox\")".dependencies.redox_syscall] version = "0.1.38" [target."cfg(windows)".dependencies.winapi] diff --git a/vendor/socket2/TODO b/vendor/socket2/TODO new file mode 100644 index 0000000000..dc211e0707 --- /dev/null +++ b/vendor/socket2/TODO @@ -0,0 +1,337 @@ +# TODO + + +impl_debug macro: + + // Same as above, but the flags are bit OR-ed. + ( + $type: path, + ORed: + $( + $(#[$target: meta])* + $libc: ident :: $flag: ident + ),+ $(,)* + ) => { + impl std::fmt::Debug for $type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut written_one = false; + $( + $(#[$target])* + #[allow(clippy::bad_bit_mask)] // Apparently some flags are zero. + { + if (self.0 & $libc :: $flag) == $libc :: $flag { + if !written_one { + write!(f, "{}", stringify!($flag))?; + written_one = true; + } else { + write!(f, "|{}", stringify!($flag))?; + } + } + } + )+ + if !written_one { + write!(f, "{}", self.0) + } else { + Ok(()) + } + } + } + }; + + + + + + +getsockopt/setsockopt +https://docs.microsoft.com/en-us/windows/win32/winsock/socket-options + + +# IP_PROTO +IP_ADD_SOURCE_MEMBERSHIP +IP_BLOCK_SOURCE +IP_DONTFRAGMENT +IP_DROP_SOURCE_MEMBERSHIP +IP_HDRINCL +IP_OPTIONS +IP_ORIGINAL_ARRIVAL_IF +IP_PKTINFO +IP_RECEIVE_BROADCAST +IP_RECVIF +IP_RECVTTL +IP_TOS +IP_UNBLOCK_SOURCE +IP_UNICAST_IF +IP_WFP_REDIRECT_CONTEXT +IP_WFP_REDIRECT_RECORDS + +# IPPROTO_IPV6 +IP_ORIGINAL_ARRIVAL_IF +IPV6_HDRINCL +IPV6_HOPLIMIT +IPV6_PKTINFO +IPV6_PROTECTION_LEVEL +IPV6_RECVIF +IPV6_UNICAST_HOPS +IPV6_UNICAST_IF + +# IPPROTO_TCP +TCP_BSDURGENT +TCP_EXPEDITED_1122 +TCP_KEEPCNT +TCP_MAXRT +TCP_NODELAY +TCP_TIMESTAMPS +TCP_FASTOPEN + +# SOL_SOCKET +PVD_CONFIG +SO_ACCEPTCONN +SO_BROADCAST +SO_BSP_STATE +SO_CONDITIONAL_ACCEPT +SO_CONNDATA +SO_CONNDATALEN +SO_CONNECT_TIME +SO_CONNOPT +SO_CONNOPTLEN +SO_DISCDATA +SO_DISCDATALEN +SO_DISCOPT +SO_DISCOPTLEN +SO_DEBUG +SO_DONTLINGER +SO_DONTROUTE +SO_ERROR +SO_EXCLUSIVEADDRUSE +SO_GROUP_ID +SO_GROUP_PRIORITY +SO_KEEPALIVE +SO_LINGER +SO_MAX_MSG_SIZE +SO_MAXDG +SO_MAXPATHDG +SO_OOBINLINE +SO_OPENTYPE +SO_PORT_SCALABILITY +SO_PROTECT +SO_PROTOCOL_INFO +SO_PROTOCOL_INFOA +SO_PROTOCOL_INFOW +SO_RCVBUF +SO_RCVLOWAT +SO_RCVTIMEO +SO_RANDOMIZE_PORT +SO_REUSEADDR +SO_REUSE_UNICASTPORT +SO_REUSE_MULTICASTPORT +SO_SNDBUF +SO_SNDLOWAT +SO_SNDTIMEO +SO_TYPE +SO_UPDATE_ACCEPT_CONTEXT +SO_UPDATE_CONNECT_CONTEXT +SO_USELOOPBACK + + + + + + + +## SockAddr + +/// Unix only API. +impl SockAddr { + /// Returns this address as a `SocketAddr` if it is in the `AF_UNIX` family. + #[cfg(feature = "all")] + pub fn as_unix(&self) -> Option { + if self.storage.ss_family as libc::c_int == libc::AF_UNIX { + todo!() + } else { + None + } + } +} + +/// Unix only API. +#[cfg(feature = "all")] +impl From for SockAddr { + fn from(addr: SocketAddr) -> SockAddr { + todo!() + } +} + + + +## Other + + + +* Add to src/lib.rs: + +* Windows impl. + +* Expand tests. Anything after shutdown. +// TODO: test: +// * take_error +// * shutdown +// +// Raw: +// * setsockopt +// * getsockopt +// * fcntl + + +* Add Domain::for methods: + fn Domain::for_socket_addr(addr: &std::net::SocketAddr) -> Domain. + + + +SockAddr from UDS SocketAddr: + +/// Unix only API. +impl SockAddr { + /// Returns the contents of this address if it is a pathname address. + /// + /// Only possible if the address is of type `AF_UNIX` and the address it not + /// unnamed. + pub fn as_pathname(&self) -> Option<&Path> { + // AF_UNIX + todo!() + } +} + +// TODO: I don't like this. +impl From for SockAddr { + fn from(addr: SocketAddr) -> SockAddr { + // Same layout as that in the standard library. + struct StdSocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, + } + + unsafe { + let addr = mem::transmute::(addr); + SockAddr::from_raw_parts(*(&addr.addr as *const _ as *const _), addr.len) + } + } +} + + + + + +/* TODO: OLD TESTS. +#[cfg(test)] +mod test { + use std::net::SocketAddr; + + use super::*; + + #[test] + fn connect_timeout_unrouteable() { + // this IP is unroutable, so connections should always time out + let addr = "10.255.255.1:80".parse::().unwrap().into(); + + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + match socket.connect_timeout(&addr, Duration::from_millis(250)) { + Ok(_) => panic!("unexpected success"), + Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {} + Err(e) => panic!("unexpected error {}", e), + } + } + + #[test] + fn connect_timeout_unbound() { + // bind and drop a socket to track down a "probably unassigned" port + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + let addr = "127.0.0.1:0".parse::().unwrap().into(); + socket.bind(&addr).unwrap(); + let addr = socket.local_addr().unwrap(); + drop(socket); + + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + match socket.connect_timeout(&addr, Duration::from_millis(250)) { + Ok(_) => panic!("unexpected success"), + Err(ref e) + if e.kind() == io::ErrorKind::ConnectionRefused + || e.kind() == io::ErrorKind::TimedOut => {} + Err(e) => panic!("unexpected error {}", e), + } + } + + #[test] + fn connect_timeout_valid() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + socket + .bind(&"127.0.0.1:0".parse::().unwrap().into()) + .unwrap(); + socket.listen(128).unwrap(); + + let addr = socket.local_addr().unwrap(); + + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + socket + .connect_timeout(&addr, Duration::from_millis(250)) + .unwrap(); + } + + #[test] + #[cfg(all(unix, feature = "pair", feature = "unix"))] + fn pair() { + let (mut a, mut b) = Socket::pair(Domain::unix(), Type::stream(), None).unwrap(); + a.write_all(b"hello world").unwrap(); + let mut buf = [0; 11]; + b.read_exact(&mut buf).unwrap(); + assert_eq!(buf, &b"hello world"[..]); + } + + #[test] + #[cfg(all(unix, feature = "unix"))] + fn unix() { + use tempdir::TempDir; + + let dir = TempDir::new("unix").unwrap(); + let addr = SockAddr::unix(dir.path().join("sock")).unwrap(); + + let listener = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); + listener.bind(&addr).unwrap(); + listener.listen(10).unwrap(); + + let mut a = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); + a.connect(&addr).unwrap(); + + let mut b = listener.accept().unwrap().0; + + a.write_all(b"hello world").unwrap(); + let mut buf = [0; 11]; + b.read_exact(&mut buf).unwrap(); + assert_eq!(buf, &b"hello world"[..]); + } + + #[test] + fn keepalive() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + socket.set_keepalive(Some(Duration::from_secs(7))).unwrap(); + // socket.keepalive() doesn't work on Windows #24 + #[cfg(unix)] + assert_eq!(socket.keepalive().unwrap(), Some(Duration::from_secs(7))); + socket.set_keepalive(None).unwrap(); + #[cfg(unix)] + assert_eq!(socket.keepalive().unwrap(), None); + } + + #[test] + fn nodelay() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + + assert!(socket.set_nodelay(true).is_ok()); + + let result = socket.nodelay(); + + assert!(result.is_ok()); + assert!(result.unwrap()); + } +} +*/ diff --git a/vendor/socket2/TODO.refactor b/vendor/socket2/TODO.refactor new file mode 100644 index 0000000000..c72f10bab0 --- /dev/null +++ b/vendor/socket2/TODO.refactor @@ -0,0 +1,7 @@ +# Refactor + +* [ ] Move all the function of `sys::Socket` as stand-alone functions. +* [ ] Remove `sys::Socket`. +* [ ] Rename `sys::SysSocket` to `sys::Socket`. +* [ ] Look at `SockAddr`. + * [ ] Add docs about its size. diff --git a/vendor/socket2/check_targets.bash b/vendor/socket2/check_targets.bash new file mode 100755 index 0000000000..343b42a25f --- /dev/null +++ b/vendor/socket2/check_targets.bash @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -eu + +declare -a targets=( + "x86_64-apple-darwin" + "x86_64-unknown-freebsd" + "x86_64-unknown-linux-gnu" + "x86_64-pc-windows-gnu" +) + +for target in "${targets[@]}"; do + cargo check --target "$target" --all-targets --examples --bins --tests --no-default-features + cargo check --target "$target" --all-targets --examples --bins --tests --all-features +done diff --git a/vendor/socket2/socket_type.diff b/vendor/socket2/socket_type.diff new file mode 100644 index 0000000000..7eff81d912 --- /dev/null +++ b/vendor/socket2/socket_type.diff @@ -0,0 +1,39 @@ +diff --git a/src/socket.rs b/src/socket.rs +index f4c04bb..3bbaf0e 100644 +--- a/src/socket.rs ++++ b/src/socket.rs +@@ -62,7 +62,7 @@ use crate::{Domain, Protocol, SockAddr, Type}; + /// ``` + pub struct Socket { + // The `sys` module most have access to the socket. +- pub(crate) inner: sys::Socket, ++ pub(crate) inner: sys::socket_t, + } + + impl Socket { +diff --git a/src/sys/unix.rs b/src/sys/unix.rs +index baec76f..598d75d 100644 +--- a/src/sys/unix.rs ++++ b/src/sys/unix.rs +@@ -26,6 +26,8 @@ use crate::{Domain, Type}; + + pub use libc::c_int; + ++// Used in `Socket`. ++pub(crate) use libc::c_int as socket_t; + // Used in `Domain`. + pub(crate) use libc::{AF_INET, AF_INET6}; + // Used in `Type`. +diff --git a/src/sys/windows.rs b/src/sys/windows.rs +index 72466ec..9598aca 100644 +--- a/src/sys/windows.rs ++++ b/src/sys/windows.rs +@@ -44,6 +44,8 @@ const WSA_FLAG_OVERLAPPED: DWORD = 0x01; + + pub use winapi::ctypes::c_int; + ++// Used in `Socket`. ++pub(crate) use sock::SOCKET as socket_t; + // Used in `Domain`. + pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6}; + // Used in `Type`. diff --git a/vendor/socket2/src/sockaddr.rs b/vendor/socket2/src/sockaddr.rs index 7bdf38ca2e..434163fecd 100644 --- a/vendor/socket2/src/sockaddr.rs +++ b/vendor/socket2/src/sockaddr.rs @@ -1,20 +1,24 @@ use std::fmt; use std::mem::{self, MaybeUninit}; -use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::ptr; #[cfg(any(unix, target_os = "redox"))] use libc::{ - sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, - AF_INET6, + in6_addr, in_addr, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, + socklen_t, AF_INET, AF_INET6, }; #[cfg(windows)] +use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR as in6_addr}; +#[cfg(windows)] +use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR as in_addr}; +#[cfg(windows)] use winapi::shared::ws2def::{ ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage, }; #[cfg(windows)] -use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; +use winapi::shared::ws2ipdef::{SOCKADDR_IN6_LH_u, SOCKADDR_IN6_LH as sockaddr_in6}; #[cfg(windows)] use winapi::um::ws2tcpip::socklen_t; @@ -43,17 +47,17 @@ impl fmt::Debug for SockAddr { impl SockAddr { /// Constructs a `SockAddr` from its raw components. pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr { - let mut storage = MaybeUninit::::uninit(); + let mut storage = MaybeUninit::::zeroed(); ptr::copy_nonoverlapping( addr as *const _ as *const u8, - &mut storage as *mut _ as *mut u8, + storage.as_mut_ptr() as *mut u8, len as usize, ); SockAddr { // This is safe as we written the address to `storage` above. storage: storage.assume_init(), - len: len, + len, } } @@ -120,33 +124,60 @@ impl SockAddr { } } - unsafe fn as_(&self, family: sa_family_t) -> Option { - if self.storage.ss_family != family { - return None; - } - - Some(mem::transmute_copy(&self.storage)) - } - /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET` /// family. pub fn as_inet(&self) -> Option { - unsafe { self.as_(AF_INET as sa_family_t) } + match self.as_std() { + Some(SocketAddr::V4(addr)) => Some(addr), + _ => None, + } } /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6` /// family. pub fn as_inet6(&self) -> Option { - unsafe { self.as_(AF_INET6 as sa_family_t) } + match self.as_std() { + Some(SocketAddr::V6(addr)) => Some(addr), + _ => None, + } } /// Returns this address as a `SocketAddr` if it is in the `AF_INET` /// or `AF_INET6` family, otherwise returns `None`. pub fn as_std(&self) -> Option { - if let Some(addr) = self.as_inet() { - Some(SocketAddr::V4(addr)) - } else if let Some(addr) = self.as_inet6() { - Some(SocketAddr::V6(addr)) + if self.storage.ss_family == AF_INET as sa_family_t { + // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in. + let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) }; + + #[cfg(unix)] + let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()); + #[cfg(windows)] + let ip = { + let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() }; + Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]) + }; + let port = u16::from_be(addr.sin_port); + Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) + } else if self.storage.ss_family == AF_INET6 as sa_family_t { + // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6. + let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) }; + + #[cfg(unix)] + let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr); + #[cfg(windows)] + let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() }); + let port = u16::from_be(addr.sin6_port); + Some(SocketAddr::V6(SocketAddrV6::new( + ip, + port, + addr.sin6_flowinfo, + #[cfg(unix)] + addr.sin6_scope_id, + #[cfg(windows)] + unsafe { + *addr.u.sin6_scope_id() + }, + ))) } else { None } @@ -168,34 +199,90 @@ impl SockAddr { } } -// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6 - -// check to make sure that the sizes at least match up -fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) { - unsafe { - mem::transmute::(v4); - mem::transmute::(v6); - } -} - impl From for SockAddr { fn from(addr: SocketAddrV4) -> SockAddr { - unsafe { - SockAddr::from_raw_parts( - &addr as *const _ as *const _, - mem::size_of::() as socklen_t, - ) + #[cfg(unix)] + let sin_addr = in_addr { + s_addr: u32::from_ne_bytes(addr.ip().octets()), + }; + #[cfg(windows)] + let sin_addr = unsafe { + let mut s_un = mem::zeroed::(); + *s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets()); + in_addr { S_un: s_un } + }; + + let sockaddr_in = sockaddr_in { + sin_family: AF_INET as sa_family_t, + sin_port: addr.port().to_be(), + sin_addr, + sin_zero: [0; 8], + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin_len: 0, + }; + let mut storage = MaybeUninit::::zeroed(); + // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage` + unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) }; + SockAddr { + storage: unsafe { storage.assume_init() }, + len: mem::size_of::() as socklen_t, } } } impl From for SockAddr { fn from(addr: SocketAddrV6) -> SockAddr { - unsafe { - SockAddr::from_raw_parts( - &addr as *const _ as *const _, - mem::size_of::() as socklen_t, - ) + #[cfg(unix)] + let sin6_addr = in6_addr { + s6_addr: addr.ip().octets(), + }; + #[cfg(windows)] + let sin6_addr = unsafe { + let mut u = mem::zeroed::(); + *u.Byte_mut() = addr.ip().octets(); + in6_addr { u } + }; + #[cfg(windows)] + let u = unsafe { + let mut u = mem::zeroed::(); + *u.sin6_scope_id_mut() = addr.scope_id(); + u + }; + + let sockaddr_in6 = sockaddr_in6 { + sin6_family: AF_INET6 as sa_family_t, + sin6_port: addr.port().to_be(), + sin6_addr, + sin6_flowinfo: addr.flowinfo(), + #[cfg(unix)] + sin6_scope_id: addr.scope_id(), + #[cfg(windows)] + u, + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin6_len: 0, + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + __sin6_src_id: 0, + }; + let mut storage = MaybeUninit::::zeroed(); + // Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage` + unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) }; + SockAddr { + storage: unsafe { storage.assume_init() }, + len: mem::size_of::() as socklen_t, } } } diff --git a/vendor/socket2/src/socket.rs b/vendor/socket2/src/socket.rs index 4b7905d3e6..95eb31d6b8 100644 --- a/vendor/socket2/src/socket.rs +++ b/vendor/socket2/src/socket.rs @@ -285,8 +285,12 @@ impl Socket { /// `recvfrom` call. /// /// [`recv_from`]: #method.recv_from - pub fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { - self.inner.recv(buf, flags) + pub fn recv_from_with_flags( + &self, + buf: &mut [u8], + flags: i32, + ) -> io::Result<(usize, SockAddr)> { + self.inner.recv_from(buf, flags) } /// Receives data from the socket, without removing it from the queue. @@ -314,7 +318,7 @@ impl Socket { /// `send` call. /// /// [`send`]: #method.send - pub fn send_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { + pub fn send_with_flags(&self, buf: &[u8], flags: i32) -> io::Result { self.inner.send(buf, flags) } @@ -325,7 +329,7 @@ impl Socket { /// /// [`send`]: #method.send /// [`out_of_band_inline`]: #method.out_of_band_inline - pub fn send_out_of_band(&self, buf: &mut [u8]) -> io::Result { + pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result { self.inner.send(buf, MSG_OOB) } @@ -342,8 +346,8 @@ impl Socket { /// `sendto` call. /// /// [`send_to`]: #method.send_to - pub fn send_to_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { - self.inner.recv(buf, flags) + pub fn send_to_with_flags(&self, buf: &[u8], addr: &SockAddr, flags: i32) -> io::Result { + self.inner.send_to(buf, flags, addr) } // ================================================ diff --git a/vendor/socket2/src/sys/unix.rs b/vendor/socket2/src/sys/unix.rs index b330fe1eea..5e55fa81f0 100644 --- a/vendor/socket2/src/sys/unix.rs +++ b/vendor/socket2/src/sys/unix.rs @@ -132,6 +132,7 @@ impl_debug!( libc::SOCK_STREAM, libc::SOCK_DGRAM, libc::SOCK_RAW, + #[cfg(not(target_os = "haiku"))] libc::SOCK_RDM, libc::SOCK_SEQPACKET, /* TODO: add these optional bit OR-ed flags: @@ -188,7 +189,7 @@ impl Socket { let fd = cvt(libc::socket(family, ty, protocol))?; let fd = Socket::from_raw_fd(fd); set_cloexec(fd.as_raw_fd())?; - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] { fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; } @@ -203,7 +204,7 @@ impl Socket { let fds = (Socket::from_raw_fd(fds[0]), Socket::from_raw_fd(fds[1])); set_cloexec(fds.0.as_raw_fd())?; set_cloexec(fds.1.as_raw_fd())?; - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] { fds.0 .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; diff --git a/vendor/syn/.cargo-checksum.json b/vendor/syn/.cargo-checksum.json index b504db1a5a..714d4e8c89 100644 --- a/vendor/syn/.cargo-checksum.json +++ b/vendor/syn/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"893d2ca34638518ddc4354585b182690773220c0bcd5fa73eb4b429c235652a8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"03f3b53cf858536a0883aa5b5882ee61dcd0f1e71c0930c9106fcfa1d6aad2df","benches/file.rs":"b4724fc7c0f48b8f488e2632a1064f6c0bf16ded3969680fc3f4a2369536269b","benches/rust.rs":"ea6291ef2d2a83d94a3312fe179d48259f8ec0b04c961993ddd181d0a4ab740e","build.rs":"aeca2312f05aec658eaa66980a0ef3d578837db107a55702b39419ea0422eb4a","src/attr.rs":"37d3decf5c8dd37f32b69e71c6030519e9ce4e945b81f9a7809cf1434ce77f71","src/await.rs":"18f0b2ecb319991f891e300011424985e3cf33d166ea9f29f22d575fc8c83a76","src/bigint.rs":"efc7f64959980653d73fe4f8bc2a3a2904dc05f45b02c6dc15cd316fa3d7c338","src/buffer.rs":"a5d6692938c2ec6ec140f70ec89fa93659fa227b52e8d381e9da7dd440f0249e","src/custom_keyword.rs":"8f711cf1ed6963f7dd398b746dbd9033e3181a24a738f29ac57fe65e92fce9b6","src/custom_punctuation.rs":"cdf0a3b8dbab85c9b5185694cf2a189f71c7f351f68251aae3b3226324bc88dc","src/data.rs":"7371b54195283995edf5d0625e9d616b894578699f676b3180ae785a32d88cb5","src/derive.rs":"25ff3aa4165d38a00849ae5c54e9c925699c979d60dfab668a251eb319ad48e5","src/discouraged.rs":"a1f3d85e20dedf50b1b7b4571d970a3a6e9b2de4afde7dd0c986fe240df2ba46","src/error.rs":"65ece7917ab5fb3af847a49303df2195e8c443edca780fb545e10e2e8ecd5649","src/export.rs":"dcae67456278c0339acfbcbb4737b8d37cfba5a150ae789f31f4be79abf7e726","src/expr.rs":"c15db333901ce2b91a441169d9247cc17b5d3440361168dbe94046bfaebee619","src/ext.rs":"1f648cff1d705a1cea64b32b77482b97a82d2fe0aaf63b40cade91e5c02dc969","src/file.rs":"77652fa0dc3340f02eb457660b873d4e5ce98ca7503a68e89239c3af2e19ab3f","src/gen/clone.rs":"0845c1bf8624c3f235cd247b4eb748e7e16b4c240097cb0ff16751f688c079ae","src/gen/debug.rs":"d24fe37f4ce1dd74f2dc54136e893782d3c4d0908323c036c97599551a56960c","src/gen/eq.rs":"1e6ef09b17ca7f36861ef23ce2a6991b231ed5f087f046469b5f23da40f5b419","src/gen/fold.rs":"3f59e59ed8ad2ab5dd347bfbe41bbc785c2aabd8ae902087a584a6daed597182","src/gen/hash.rs":"e5b2a52587173076777233a9e57e2b3c8e0dd6d6f41d16fa7c9fde68b05c2bfc","src/gen/visit.rs":"23008c170d4dd3975232876a0a654921d9b6af57372cb9fcc133ca740588d666","src/gen/visit_mut.rs":"42886c3ee02ded72d9c3eec006e20431eaee0c6b90ddefc1a36ec7bf50c6a24a","src/gen_helper.rs":"ea6c66388365971db6a2fc86cbb208f7eacde77e245bc8623f27a3642a3d7741","src/generics.rs":"419cbd548427813e9b0ffd82522f811e0d75d101cc3e326e9a441e8ce2ddf408","src/group.rs":"b2e7aef7fa182959081fb024c425b58f1d7a86faaff1fb56e38efe5e1af8602b","src/ident.rs":"503156ce51a7ef0420892e8dbf2ecf8fe51f42a84d52cc2c05654e1a83020cbf","src/item.rs":"046d5045261015e961530e5bef0a7d5f3c20eb4671eef64bb9956433cd6fe043","src/lib.rs":"851c2e0b8168c9c41bf6a8a9212314ab0c858eb29f0ed4ffeb3bd0dbda9b42b5","src/lifetime.rs":"af278d1ce7af01aa76823ba990855f1c9112a41aa33fc52bd27a37a1ea571103","src/lit.rs":"76d1c68ab17b3f5338d010ca165d5be8390b567df449c4012ce5d2239f737dfa","src/lookahead.rs":"92ee63b48de02d3f6f1b09121f0fbac41d55cebc5771c8320e27df8482906152","src/mac.rs":"5343a19b55870c9a081613e1da6b3cd89822e395b74a8aa19b6bb7ef50ca9fc4","src/macros.rs":"2ce05b553f14da4ee550bb681cb0733b7186ad94719cd36f96d53e15fd02cf2b","src/op.rs":"7a4936d6c36479d2604708dede934caae5835b8ce32bd081cb2beb7710adbee8","src/parse.rs":"b3bb998601034eb88862bccfe9e9f7d5ab87106c17972c31546f604e9b0b5bd7","src/parse_macro_input.rs":"4dc86dec2cfd1dd6616500199ed85959377be32acb12fe5b914222748bd62ab1","src/parse_quote.rs":"5ab8dfe938b42de5b0ef996e3a3a98aaba7ff53e30c158272f035f6f90b0204e","src/pat.rs":"6d3001d1778bc6ce91ac0c7ea40b8c9f63946e25b6d66f4e214360e29fb123c3","src/path.rs":"35b286369435513a6c10d38c4aa8aab27ef7aca710cf1a5bb339523dc6dcdbec","src/print.rs":"da6529c1d9d21aaf6c835f66b4e67eacb7cf91a10eb5e9a2143b49bf99b3b5e1","src/punctuated.rs":"212f5a601d6c2eb8b8fa679be1167b455b595bee964d2775b0101ebb16c3eaa5","src/reserved.rs":"3625eb2a64589a4992ab79a1674e9679f465bea613ab139a671df5337e88cee6","src/sealed.rs":"896a495a5340eec898527f18bd4ddca408ea03ea0ee3af30074ff48deace778d","src/span.rs":"748c51c6feb223c26d3b1701f5bb98aee823666c775c98106cfa24fe29d8cec1","src/spanned.rs":"7d77714d585e6f42397091ffb3a799fd7b20c05c5442c737683c429ea7d409a5","src/stmt.rs":"000dff59fcf8ce00f961dc0f974bd364f42a180519f5b6d6a812334c1e5b3aef","src/thread.rs":"815eca6bd64f4eef7c447f0809e84108f5428ff50225224b373efd8fbb696874","src/token.rs":"0948bd913d0aee913100894ec8989384bc76ef98d68d508954ecacb9db849031","src/tt.rs":"32402645b6e82ef1e882945721b59b5fb7b0ee337d1972876362ecacef643d0f","src/ty.rs":"885c21d8edb8fb108fa1c9283117d85611664d1870f257cff03c5e12d24a29fc","src/verbatim.rs":"802a97df997432f18cac6e6200ff6ea29fb2474986005e0fcdbc2b65197f87f7","src/whitespace.rs":"e63dd0aa3d34029f17766a8b09c1a6e4479e36c552c8b7023d710a399333aace","tests/.gitignore":"22e782449a3c216db3f7215d5fb8882e316768e40beeec3833aae419ad8941db","tests/common/eq.rs":"02a3057e72f20de1a9460d504404e3a03fa08d9cd8f9e181d9816276f6918e20","tests/common/mod.rs":"25ef6d7daa09bad3198a0e9e91b2812425f92db7c585c1e34a03a84d7362ccd8","tests/common/parse.rs":"81580f23583723f7a2a337c4d13ebc021057cd825562fb4e474caa7cc641fed9","tests/debug/gen.rs":"d6e2abf2a7bb58a7895a60c2f094a98a4f85c9189d02011d0dcef6ef053f26e3","tests/debug/mod.rs":"868763d0ef1609a3ad5e05e9f1bfa0f813e91e7e9a36653414a188bb2fdaa425","tests/macros/mod.rs":"a93136b172377ffebe8b68fd596a86d6625f64ed6c3d5e7f5d6ad859e25d5623","tests/repo/mod.rs":"9e316b88d57ae213e81950c35e45443078ec90e702798353bc3528cb8a2810b6","tests/repo/progress.rs":"c08d0314a7f3ecf760d471f27da3cd2a500aeb9f1c8331bffb2aa648f9fabf3f","tests/test_asyncness.rs":"cff01db49d28ab23b0b258bc6c0a5cc4071be4fe7248eef344a5d79d2fb649b7","tests/test_attribute.rs":"0ffd99384e1a52ae17d9fed5c4053e411e8f9018decef07ffa621d1faa7329d8","tests/test_derive_input.rs":"610444351e3bf99366976bbf1da109c334a70ac9500caef366bcf9b68819829f","tests/test_expr.rs":"0ee83f6f6de950018c043efcc3e85776b4227dae3068309998a8d9709f2fc66c","tests/test_generics.rs":"9d713f90a79d6145efc89fb6f946029ca03486c632219950889da39940152ba0","tests/test_grouping.rs":"6276c3c73bba649dec5c97904ad2492879f918bc887a2c425d095c654ca0d925","tests/test_ident.rs":"9eb53d1e21edf23e7c9e14dc74dcc2b2538e9221e19dbcc0a44e3acc2e90f3f6","tests/test_item.rs":"461ed0c8648afffcea3217f52c9a88298182b4d39d73a11803b1281d99c98c25","tests/test_iterators.rs":"53ed6078d37550bd6765d2411e3660be401aef8a31a407350cc064a7d08c7c33","tests/test_lit.rs":"30d58d8edbff335d01e2ab2ca984733934af435269be14b631780d2d9627dc73","tests/test_meta.rs":"1fc98af3279cadc3d8db3c7e8d4d7f9e9dbd4d17548cf6a2f6f4536ed65367f6","tests/test_parse_buffer.rs":"8bbe2d24ca8a3788f72c6908fc96c26d546f11c69687bf8d72727f851d5e2d27","tests/test_parse_stream.rs":"2f449a2c41a3dee6fd14bee24e1666a453cb808eda17332fd91afd127fcdd2a6","tests/test_pat.rs":"134091ba20e86c982dadbae668aebe66b1edd9619a01dedee989d1c7efde6b80","tests/test_path.rs":"13ae78e958f0d7334d11f32519f593968e5503d46e29ec345feede025f16113d","tests/test_precedence.rs":"65c2e308a03662af4b492d73c4d421d5f46ad6f6301624f70370361ae2770daa","tests/test_receiver.rs":"084eca59984b9a18651da52f2c4407355da3de1335916a12477652999e2d01cc","tests/test_round_trip.rs":"ab7a969b5acdb030d34981caf16f0098329a7e177b202f95423a15c24fe8ac6b","tests/test_shebang.rs":"f5772cadad5b56e3112cb16308b779f92bce1c3a48091fc9933deb2276a69331","tests/test_should_parse.rs":"1d3535698a446e2755bfc360676bdb161841a1f454cdef6e7556c6d06a95c89d","tests/test_size.rs":"5fae772bab66809d6708232f35cfb4a287882486763b0f763feec2ad79fbb68b","tests/test_stmt.rs":"17e4355843ee2982b51faba2721a18966f8c2b9422e16b052a123b8ee8b80752","tests/test_token_trees.rs":"43e56a701817e3c3bfd0cae54a457dd7a38ccb3ca19da41e2b995fdf20e6ed18","tests/test_ty.rs":"5b7c0bfc4963d41920dd0b39fdea419e34f00409ba86ad4211d6c3c7e8bbe1c0","tests/test_visibility.rs":"3f958e2b3b5908005e756a80eea326a91eac97cc4ab60599bebde8d4b942d65c","tests/zzz_stable.rs":"2a862e59cb446235ed99aec0e6ada8e16d3ecc30229b29d825b7c0bbc2602989"},"package":"e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd"} \ No newline at end of file +{"files":{"Cargo.toml":"44af7f58c4f6415232d11b9796837deb0312756001bc46e427d4500ac6bd9dba","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"03f3b53cf858536a0883aa5b5882ee61dcd0f1e71c0930c9106fcfa1d6aad2df","benches/file.rs":"b4724fc7c0f48b8f488e2632a1064f6c0bf16ded3969680fc3f4a2369536269b","benches/rust.rs":"ea6291ef2d2a83d94a3312fe179d48259f8ec0b04c961993ddd181d0a4ab740e","build.rs":"aeca2312f05aec658eaa66980a0ef3d578837db107a55702b39419ea0422eb4a","src/attr.rs":"b3ea67fdaee11341a6645ab58387851627ddc9ed7a81a2b7559272bef25e8d99","src/await.rs":"8aa22e3c201cb2bdb6b4817fa00901f308ab06817607aa7b884c58c957705969","src/bigint.rs":"efc7f64959980653d73fe4f8bc2a3a2904dc05f45b02c6dc15cd316fa3d7c338","src/buffer.rs":"a5d6692938c2ec6ec140f70ec89fa93659fa227b52e8d381e9da7dd440f0249e","src/custom_keyword.rs":"8f711cf1ed6963f7dd398b746dbd9033e3181a24a738f29ac57fe65e92fce9b6","src/custom_punctuation.rs":"cdf0a3b8dbab85c9b5185694cf2a189f71c7f351f68251aae3b3226324bc88dc","src/data.rs":"7371b54195283995edf5d0625e9d616b894578699f676b3180ae785a32d88cb5","src/derive.rs":"25ff3aa4165d38a00849ae5c54e9c925699c979d60dfab668a251eb319ad48e5","src/discouraged.rs":"a1f3d85e20dedf50b1b7b4571d970a3a6e9b2de4afde7dd0c986fe240df2ba46","src/error.rs":"65ece7917ab5fb3af847a49303df2195e8c443edca780fb545e10e2e8ecd5649","src/export.rs":"dcae67456278c0339acfbcbb4737b8d37cfba5a150ae789f31f4be79abf7e726","src/expr.rs":"c15db333901ce2b91a441169d9247cc17b5d3440361168dbe94046bfaebee619","src/ext.rs":"1f648cff1d705a1cea64b32b77482b97a82d2fe0aaf63b40cade91e5c02dc969","src/file.rs":"77652fa0dc3340f02eb457660b873d4e5ce98ca7503a68e89239c3af2e19ab3f","src/gen/clone.rs":"0845c1bf8624c3f235cd247b4eb748e7e16b4c240097cb0ff16751f688c079ae","src/gen/debug.rs":"d24fe37f4ce1dd74f2dc54136e893782d3c4d0908323c036c97599551a56960c","src/gen/eq.rs":"1e6ef09b17ca7f36861ef23ce2a6991b231ed5f087f046469b5f23da40f5b419","src/gen/fold.rs":"3f59e59ed8ad2ab5dd347bfbe41bbc785c2aabd8ae902087a584a6daed597182","src/gen/hash.rs":"e5b2a52587173076777233a9e57e2b3c8e0dd6d6f41d16fa7c9fde68b05c2bfc","src/gen/visit.rs":"23008c170d4dd3975232876a0a654921d9b6af57372cb9fcc133ca740588d666","src/gen/visit_mut.rs":"42886c3ee02ded72d9c3eec006e20431eaee0c6b90ddefc1a36ec7bf50c6a24a","src/gen_helper.rs":"ea6c66388365971db6a2fc86cbb208f7eacde77e245bc8623f27a3642a3d7741","src/generics.rs":"419cbd548427813e9b0ffd82522f811e0d75d101cc3e326e9a441e8ce2ddf408","src/group.rs":"b2e7aef7fa182959081fb024c425b58f1d7a86faaff1fb56e38efe5e1af8602b","src/ident.rs":"503156ce51a7ef0420892e8dbf2ecf8fe51f42a84d52cc2c05654e1a83020cbf","src/item.rs":"046d5045261015e961530e5bef0a7d5f3c20eb4671eef64bb9956433cd6fe043","src/lib.rs":"2077a49c16026c1603b8cac143567c91d5435af615b54d9dbbfd2f465a2c80ee","src/lifetime.rs":"af278d1ce7af01aa76823ba990855f1c9112a41aa33fc52bd27a37a1ea571103","src/lit.rs":"c448a000e277c46bbbd071aca88d3f0a55cef7d96aee0a52aded007c5c17c2f7","src/lookahead.rs":"92ee63b48de02d3f6f1b09121f0fbac41d55cebc5771c8320e27df8482906152","src/mac.rs":"5343a19b55870c9a081613e1da6b3cd89822e395b74a8aa19b6bb7ef50ca9fc4","src/macros.rs":"2ce05b553f14da4ee550bb681cb0733b7186ad94719cd36f96d53e15fd02cf2b","src/op.rs":"7a4936d6c36479d2604708dede934caae5835b8ce32bd081cb2beb7710adbee8","src/parse.rs":"b3bb998601034eb88862bccfe9e9f7d5ab87106c17972c31546f604e9b0b5bd7","src/parse_macro_input.rs":"4dc86dec2cfd1dd6616500199ed85959377be32acb12fe5b914222748bd62ab1","src/parse_quote.rs":"5ab8dfe938b42de5b0ef996e3a3a98aaba7ff53e30c158272f035f6f90b0204e","src/pat.rs":"6d3001d1778bc6ce91ac0c7ea40b8c9f63946e25b6d66f4e214360e29fb123c3","src/path.rs":"35b286369435513a6c10d38c4aa8aab27ef7aca710cf1a5bb339523dc6dcdbec","src/print.rs":"da6529c1d9d21aaf6c835f66b4e67eacb7cf91a10eb5e9a2143b49bf99b3b5e1","src/punctuated.rs":"212f5a601d6c2eb8b8fa679be1167b455b595bee964d2775b0101ebb16c3eaa5","src/reserved.rs":"3625eb2a64589a4992ab79a1674e9679f465bea613ab139a671df5337e88cee6","src/sealed.rs":"896a495a5340eec898527f18bd4ddca408ea03ea0ee3af30074ff48deace778d","src/span.rs":"748c51c6feb223c26d3b1701f5bb98aee823666c775c98106cfa24fe29d8cec1","src/spanned.rs":"7d77714d585e6f42397091ffb3a799fd7b20c05c5442c737683c429ea7d409a5","src/stmt.rs":"000dff59fcf8ce00f961dc0f974bd364f42a180519f5b6d6a812334c1e5b3aef","src/thread.rs":"815eca6bd64f4eef7c447f0809e84108f5428ff50225224b373efd8fbb696874","src/token.rs":"466580000ef78876a08fe54e6c9600406154e5ab07cf465b0e0d6248a96ece58","src/tt.rs":"32402645b6e82ef1e882945721b59b5fb7b0ee337d1972876362ecacef643d0f","src/ty.rs":"885c21d8edb8fb108fa1c9283117d85611664d1870f257cff03c5e12d24a29fc","src/verbatim.rs":"802a97df997432f18cac6e6200ff6ea29fb2474986005e0fcdbc2b65197f87f7","src/whitespace.rs":"e63dd0aa3d34029f17766a8b09c1a6e4479e36c552c8b7023d710a399333aace","tests/.gitignore":"22e782449a3c216db3f7215d5fb8882e316768e40beeec3833aae419ad8941db","tests/common/eq.rs":"e6b8c44d6164525e4d07b9971c521a9f1ca6e80185ae280454d92e0e2109564d","tests/common/mod.rs":"25ef6d7daa09bad3198a0e9e91b2812425f92db7c585c1e34a03a84d7362ccd8","tests/common/parse.rs":"81580f23583723f7a2a337c4d13ebc021057cd825562fb4e474caa7cc641fed9","tests/debug/gen.rs":"d6e2abf2a7bb58a7895a60c2f094a98a4f85c9189d02011d0dcef6ef053f26e3","tests/debug/mod.rs":"868763d0ef1609a3ad5e05e9f1bfa0f813e91e7e9a36653414a188bb2fdaa425","tests/macros/mod.rs":"a93136b172377ffebe8b68fd596a86d6625f64ed6c3d5e7f5d6ad859e25d5623","tests/repo/mod.rs":"9e316b88d57ae213e81950c35e45443078ec90e702798353bc3528cb8a2810b6","tests/repo/progress.rs":"c08d0314a7f3ecf760d471f27da3cd2a500aeb9f1c8331bffb2aa648f9fabf3f","tests/test_asyncness.rs":"cff01db49d28ab23b0b258bc6c0a5cc4071be4fe7248eef344a5d79d2fb649b7","tests/test_attribute.rs":"0ffd99384e1a52ae17d9fed5c4053e411e8f9018decef07ffa621d1faa7329d8","tests/test_derive_input.rs":"610444351e3bf99366976bbf1da109c334a70ac9500caef366bcf9b68819829f","tests/test_expr.rs":"0ee83f6f6de950018c043efcc3e85776b4227dae3068309998a8d9709f2fc66c","tests/test_generics.rs":"9d713f90a79d6145efc89fb6f946029ca03486c632219950889da39940152ba0","tests/test_grouping.rs":"6276c3c73bba649dec5c97904ad2492879f918bc887a2c425d095c654ca0d925","tests/test_ident.rs":"9eb53d1e21edf23e7c9e14dc74dcc2b2538e9221e19dbcc0a44e3acc2e90f3f6","tests/test_item.rs":"461ed0c8648afffcea3217f52c9a88298182b4d39d73a11803b1281d99c98c25","tests/test_iterators.rs":"53ed6078d37550bd6765d2411e3660be401aef8a31a407350cc064a7d08c7c33","tests/test_lit.rs":"ef3f39da6ed67ba73b05eab3dda299887a455bac8e97701a90a94b636681588f","tests/test_meta.rs":"bd6910ec0eba05e814dad27dda0ea65e1f8b483e64d943213066ffd114a82b45","tests/test_parse_buffer.rs":"8bbe2d24ca8a3788f72c6908fc96c26d546f11c69687bf8d72727f851d5e2d27","tests/test_parse_stream.rs":"2f449a2c41a3dee6fd14bee24e1666a453cb808eda17332fd91afd127fcdd2a6","tests/test_pat.rs":"134091ba20e86c982dadbae668aebe66b1edd9619a01dedee989d1c7efde6b80","tests/test_path.rs":"13ae78e958f0d7334d11f32519f593968e5503d46e29ec345feede025f16113d","tests/test_precedence.rs":"65c2e308a03662af4b492d73c4d421d5f46ad6f6301624f70370361ae2770daa","tests/test_receiver.rs":"084eca59984b9a18651da52f2c4407355da3de1335916a12477652999e2d01cc","tests/test_round_trip.rs":"ab7a969b5acdb030d34981caf16f0098329a7e177b202f95423a15c24fe8ac6b","tests/test_shebang.rs":"f5772cadad5b56e3112cb16308b779f92bce1c3a48091fc9933deb2276a69331","tests/test_should_parse.rs":"1d3535698a446e2755bfc360676bdb161841a1f454cdef6e7556c6d06a95c89d","tests/test_size.rs":"5fae772bab66809d6708232f35cfb4a287882486763b0f763feec2ad79fbb68b","tests/test_stmt.rs":"17e4355843ee2982b51faba2721a18966f8c2b9422e16b052a123b8ee8b80752","tests/test_token_trees.rs":"43e56a701817e3c3bfd0cae54a457dd7a38ccb3ca19da41e2b995fdf20e6ed18","tests/test_ty.rs":"5b7c0bfc4963d41920dd0b39fdea419e34f00409ba86ad4211d6c3c7e8bbe1c0","tests/test_visibility.rs":"3f958e2b3b5908005e756a80eea326a91eac97cc4ab60599bebde8d4b942d65c","tests/zzz_stable.rs":"2a862e59cb446235ed99aec0e6ada8e16d3ecc30229b29d825b7c0bbc2602989"},"package":"cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"} \ No newline at end of file diff --git a/vendor/syn/Cargo.toml b/vendor/syn/Cargo.toml index 58c70be166..d5df32755e 100644 --- a/vendor/syn/Cargo.toml +++ b/vendor/syn/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "syn" -version = "1.0.44" +version = "1.0.48" authors = ["David Tolnay "] include = ["/benches/**", "/build.rs", "/Cargo.toml", "/LICENSE-APACHE", "/LICENSE-MIT", "/README.md", "/src/**", "/tests/**"] description = "Parser for Rust source code" diff --git a/vendor/syn/src/attr.rs b/vendor/syn/src/attr.rs index 95eaf2d59b..ea6ab09d1b 100644 --- a/vendor/syn/src/attr.rs +++ b/vendor/syn/src/attr.rs @@ -578,7 +578,9 @@ pub mod parsing { fn parse(input: ParseStream) -> Result { if input.peek(Lit) && !(input.peek(LitBool) && input.peek2(Token![=])) { input.parse().map(NestedMeta::Lit) - } else if input.peek(Ident::peek_any) { + } else if input.peek(Ident::peek_any) + || input.peek(Token![::]) && input.peek3(Ident::peek_any) + { input.parse().map(NestedMeta::Meta) } else { Err(input.error("expected identifier or literal")) diff --git a/vendor/syn/src/await.rs b/vendor/syn/src/await.rs index a8e24fd4e5..038c6a5d12 100644 --- a/vendor/syn/src/await.rs +++ b/vendor/syn/src/await.rs @@ -1,2 +1,2 @@ // See include!("await.rs") in token.rs. -export_token_macro![(await)]; +export_token_macro! {[await]} diff --git a/vendor/syn/src/lib.rs b/vendor/syn/src/lib.rs index 9c3fa977c7..3a34eaa626 100644 --- a/vendor/syn/src/lib.rs +++ b/vendor/syn/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.44")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.48")] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints. #![allow( diff --git a/vendor/syn/src/lit.rs b/vendor/syn/src/lit.rs index 9f02fb5b66..e45b81ba1b 100644 --- a/vendor/syn/src/lit.rs +++ b/vendor/syn/src/lit.rs @@ -759,8 +759,8 @@ pub mod parsing { impl Parse for LitStr { fn parse(input: ParseStream) -> Result { let head = input.fork(); - match input.parse()? { - Lit::Str(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Str(lit)) => Ok(lit), _ => Err(head.error("expected string literal")), } } @@ -769,8 +769,8 @@ pub mod parsing { impl Parse for LitByteStr { fn parse(input: ParseStream) -> Result { let head = input.fork(); - match input.parse()? { - Lit::ByteStr(lit) => Ok(lit), + match input.parse() { + Ok(Lit::ByteStr(lit)) => Ok(lit), _ => Err(head.error("expected byte string literal")), } } @@ -779,8 +779,8 @@ pub mod parsing { impl Parse for LitByte { fn parse(input: ParseStream) -> Result { let head = input.fork(); - match input.parse()? { - Lit::Byte(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Byte(lit)) => Ok(lit), _ => Err(head.error("expected byte literal")), } } @@ -789,8 +789,8 @@ pub mod parsing { impl Parse for LitChar { fn parse(input: ParseStream) -> Result { let head = input.fork(); - match input.parse()? { - Lit::Char(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Char(lit)) => Ok(lit), _ => Err(head.error("expected character literal")), } } @@ -799,8 +799,8 @@ pub mod parsing { impl Parse for LitInt { fn parse(input: ParseStream) -> Result { let head = input.fork(); - match input.parse()? { - Lit::Int(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Int(lit)) => Ok(lit), _ => Err(head.error("expected integer literal")), } } @@ -809,8 +809,8 @@ pub mod parsing { impl Parse for LitFloat { fn parse(input: ParseStream) -> Result { let head = input.fork(); - match input.parse()? { - Lit::Float(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Float(lit)) => Ok(lit), _ => Err(head.error("expected floating point literal")), } } @@ -819,8 +819,8 @@ pub mod parsing { impl Parse for LitBool { fn parse(input: ParseStream) -> Result { let head = input.fork(); - match input.parse()? { - Lit::Bool(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Bool(lit)) => Ok(lit), _ => Err(head.error("expected boolean literal")), } } diff --git a/vendor/syn/src/token.rs b/vendor/syn/src/token.rs index 54c30e1dcd..e5c6d1f840 100644 --- a/vendor/syn/src/token.rs +++ b/vendor/syn/src/token.rs @@ -748,105 +748,105 @@ macro_rules! export_token_macro { // https://github.com/rust-lang/rust/issues/45939 #[macro_export] macro_rules! Token { - (abstract) => { $crate::token::Abstract }; - (as) => { $crate::token::As }; - (async) => { $crate::token::Async }; - (auto) => { $crate::token::Auto }; + [abstract] => { $crate::token::Abstract }; + [as] => { $crate::token::As }; + [async] => { $crate::token::Async }; + [auto] => { $crate::token::Auto }; $($await_rule => { $crate::token::Await };)* - (become) => { $crate::token::Become }; - (box) => { $crate::token::Box }; - (break) => { $crate::token::Break }; - (const) => { $crate::token::Const }; - (continue) => { $crate::token::Continue }; - (crate) => { $crate::token::Crate }; - (default) => { $crate::token::Default }; - (do) => { $crate::token::Do }; - (dyn) => { $crate::token::Dyn }; - (else) => { $crate::token::Else }; - (enum) => { $crate::token::Enum }; - (extern) => { $crate::token::Extern }; - (final) => { $crate::token::Final }; - (fn) => { $crate::token::Fn }; - (for) => { $crate::token::For }; - (if) => { $crate::token::If }; - (impl) => { $crate::token::Impl }; - (in) => { $crate::token::In }; - (let) => { $crate::token::Let }; - (loop) => { $crate::token::Loop }; - (macro) => { $crate::token::Macro }; - (match) => { $crate::token::Match }; - (mod) => { $crate::token::Mod }; - (move) => { $crate::token::Move }; - (mut) => { $crate::token::Mut }; - (override) => { $crate::token::Override }; - (priv) => { $crate::token::Priv }; - (pub) => { $crate::token::Pub }; - (ref) => { $crate::token::Ref }; - (return) => { $crate::token::Return }; - (Self) => { $crate::token::SelfType }; - (self) => { $crate::token::SelfValue }; - (static) => { $crate::token::Static }; - (struct) => { $crate::token::Struct }; - (super) => { $crate::token::Super }; - (trait) => { $crate::token::Trait }; - (try) => { $crate::token::Try }; - (type) => { $crate::token::Type }; - (typeof) => { $crate::token::Typeof }; - (union) => { $crate::token::Union }; - (unsafe) => { $crate::token::Unsafe }; - (unsized) => { $crate::token::Unsized }; - (use) => { $crate::token::Use }; - (virtual) => { $crate::token::Virtual }; - (where) => { $crate::token::Where }; - (while) => { $crate::token::While }; - (yield) => { $crate::token::Yield }; - (+) => { $crate::token::Add }; - (+=) => { $crate::token::AddEq }; - (&) => { $crate::token::And }; - (&&) => { $crate::token::AndAnd }; - (&=) => { $crate::token::AndEq }; - (@) => { $crate::token::At }; - (!) => { $crate::token::Bang }; - (^) => { $crate::token::Caret }; - (^=) => { $crate::token::CaretEq }; - (:) => { $crate::token::Colon }; - (::) => { $crate::token::Colon2 }; - (,) => { $crate::token::Comma }; - (/) => { $crate::token::Div }; - (/=) => { $crate::token::DivEq }; - ($) => { $crate::token::Dollar }; - (.) => { $crate::token::Dot }; - (..) => { $crate::token::Dot2 }; - (...) => { $crate::token::Dot3 }; - (..=) => { $crate::token::DotDotEq }; - (=) => { $crate::token::Eq }; - (==) => { $crate::token::EqEq }; - (>=) => { $crate::token::Ge }; - (>) => { $crate::token::Gt }; - (<=) => { $crate::token::Le }; - (<) => { $crate::token::Lt }; - (*=) => { $crate::token::MulEq }; - (!=) => { $crate::token::Ne }; - (|) => { $crate::token::Or }; - (|=) => { $crate::token::OrEq }; - (||) => { $crate::token::OrOr }; - (#) => { $crate::token::Pound }; - (?) => { $crate::token::Question }; - (->) => { $crate::token::RArrow }; - (<-) => { $crate::token::LArrow }; - (%) => { $crate::token::Rem }; - (%=) => { $crate::token::RemEq }; - (=>) => { $crate::token::FatArrow }; - (;) => { $crate::token::Semi }; - (<<) => { $crate::token::Shl }; - (<<=) => { $crate::token::ShlEq }; - (>>) => { $crate::token::Shr }; - (>>=) => { $crate::token::ShrEq }; - (*) => { $crate::token::Star }; - (-) => { $crate::token::Sub }; - (-=) => { $crate::token::SubEq }; - (~) => { $crate::token::Tilde }; - (_) => { $crate::token::Underscore }; + [become] => { $crate::token::Become }; + [box] => { $crate::token::Box }; + [break] => { $crate::token::Break }; + [const] => { $crate::token::Const }; + [continue] => { $crate::token::Continue }; + [crate] => { $crate::token::Crate }; + [default] => { $crate::token::Default }; + [do] => { $crate::token::Do }; + [dyn] => { $crate::token::Dyn }; + [else] => { $crate::token::Else }; + [enum] => { $crate::token::Enum }; + [extern] => { $crate::token::Extern }; + [final] => { $crate::token::Final }; + [fn] => { $crate::token::Fn }; + [for] => { $crate::token::For }; + [if] => { $crate::token::If }; + [impl] => { $crate::token::Impl }; + [in] => { $crate::token::In }; + [let] => { $crate::token::Let }; + [loop] => { $crate::token::Loop }; + [macro] => { $crate::token::Macro }; + [match] => { $crate::token::Match }; + [mod] => { $crate::token::Mod }; + [move] => { $crate::token::Move }; + [mut] => { $crate::token::Mut }; + [override] => { $crate::token::Override }; + [priv] => { $crate::token::Priv }; + [pub] => { $crate::token::Pub }; + [ref] => { $crate::token::Ref }; + [return] => { $crate::token::Return }; + [Self] => { $crate::token::SelfType }; + [self] => { $crate::token::SelfValue }; + [static] => { $crate::token::Static }; + [struct] => { $crate::token::Struct }; + [super] => { $crate::token::Super }; + [trait] => { $crate::token::Trait }; + [try] => { $crate::token::Try }; + [type] => { $crate::token::Type }; + [typeof] => { $crate::token::Typeof }; + [union] => { $crate::token::Union }; + [unsafe] => { $crate::token::Unsafe }; + [unsized] => { $crate::token::Unsized }; + [use] => { $crate::token::Use }; + [virtual] => { $crate::token::Virtual }; + [where] => { $crate::token::Where }; + [while] => { $crate::token::While }; + [yield] => { $crate::token::Yield }; + [+] => { $crate::token::Add }; + [+=] => { $crate::token::AddEq }; + [&] => { $crate::token::And }; + [&&] => { $crate::token::AndAnd }; + [&=] => { $crate::token::AndEq }; + [@] => { $crate::token::At }; + [!] => { $crate::token::Bang }; + [^] => { $crate::token::Caret }; + [^=] => { $crate::token::CaretEq }; + [:] => { $crate::token::Colon }; + [::] => { $crate::token::Colon2 }; + [,] => { $crate::token::Comma }; + [/] => { $crate::token::Div }; + [/=] => { $crate::token::DivEq }; + [$] => { $crate::token::Dollar }; + [.] => { $crate::token::Dot }; + [..] => { $crate::token::Dot2 }; + [...] => { $crate::token::Dot3 }; + [..=] => { $crate::token::DotDotEq }; + [=] => { $crate::token::Eq }; + [==] => { $crate::token::EqEq }; + [>=] => { $crate::token::Ge }; + [>] => { $crate::token::Gt }; + [<=] => { $crate::token::Le }; + [<] => { $crate::token::Lt }; + [*=] => { $crate::token::MulEq }; + [!=] => { $crate::token::Ne }; + [|] => { $crate::token::Or }; + [|=] => { $crate::token::OrEq }; + [||] => { $crate::token::OrOr }; + [#] => { $crate::token::Pound }; + [?] => { $crate::token::Question }; + [->] => { $crate::token::RArrow }; + [<-] => { $crate::token::LArrow }; + [%] => { $crate::token::Rem }; + [%=] => { $crate::token::RemEq }; + [=>] => { $crate::token::FatArrow }; + [;] => { $crate::token::Semi }; + [<<] => { $crate::token::Shl }; + [<<=] => { $crate::token::ShlEq }; + [>>] => { $crate::token::Shr }; + [>>=] => { $crate::token::ShrEq }; + [*] => { $crate::token::Star }; + [-] => { $crate::token::Sub }; + [-=] => { $crate::token::SubEq }; + [~] => { $crate::token::Tilde }; + [_] => { $crate::token::Underscore }; } }; } @@ -855,9 +855,9 @@ macro_rules! export_token_macro { // https://github.com/rust-lang/rust/issues/57919 // We put the Token![await] rule in a place that is not lexed by old rustc. #[cfg(not(syn_omit_await_from_token_macro))] -include!("await.rs"); // export_token_macro![(await)]; +include!("await.rs"); // export_token_macro! {[await]} #[cfg(syn_omit_await_from_token_macro)] -export_token_macro![]; +export_token_macro! {} // Not public API. #[doc(hidden)] diff --git a/vendor/syn/tests/common/eq.rs b/vendor/syn/tests/common/eq.rs index 77035b9334..4ec910b596 100644 --- a/vendor/syn/tests/common/eq.rs +++ b/vendor/syn/tests/common/eq.rs @@ -22,7 +22,7 @@ use rustc_ast::ast::{ }; use rustc_ast::ptr::P; use rustc_ast::token::{self, CommentKind, DelimToken, Token, TokenKind}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::thin_vec::ThinVec; use rustc_span::source_map::Spanned; @@ -364,13 +364,13 @@ spanless_eq_enum!(UseTreeKind; Simple(0 1 2) Nested(0) Glob); spanless_eq_enum!(VariantData; Struct(0 1) Tuple(0 1) Unit(0)); spanless_eq_enum!(VisibilityKind; Public Crate(0) Restricted(path id) Inherited); spanless_eq_enum!(WherePredicate; BoundPredicate(0) RegionPredicate(0) EqPredicate(0)); -spanless_eq_enum!(ExprKind; Box(0) Array(0) Call(0 1) MethodCall(0 1 2) Tup(0) - Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1) Let(0 1) If(0 1 2) - While(0 1 2) ForLoop(0 1 2 3) Loop(0 1) Match(0 1) Closure(0 1 2 3 4 5) - Block(0 1) Async(0 1 2) Await(0) TryBlock(0) Assign(0 1 2) AssignOp(0 1 2) - Field(0 1) Index(0 1) Range(0 1 2) Path(0 1) AddrOf(0 1 2) Break(0 1) - Continue(0) Ret(0) InlineAsm(0) LlvmInlineAsm(0) MacCall(0) Struct(0 1 2) - Repeat(0 1) Paren(0) Try(0) Yield(0) Err); +spanless_eq_enum!(ExprKind; Box(0) Array(0) ConstBlock(0) Call(0 1) + MethodCall(0 1 2) Tup(0) Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1) + Let(0 1) If(0 1 2) While(0 1 2) ForLoop(0 1 2 3) Loop(0 1) Match(0 1) + Closure(0 1 2 3 4 5) Block(0 1) Async(0 1 2) Await(0) TryBlock(0) + Assign(0 1 2) AssignOp(0 1 2) Field(0 1) Index(0 1) Range(0 1 2) Path(0 1) + AddrOf(0 1 2) Break(0 1) Continue(0) Ret(0) InlineAsm(0) LlvmInlineAsm(0) + MacCall(0) Struct(0 1 2) Repeat(0 1) Paren(0) Try(0) Yield(0) Err); spanless_eq_enum!(InlineAsmOperand; In(reg expr) Out(reg late expr) InOut(reg late expr) SplitInOut(reg late in_expr out_expr) Const(expr) Sym(expr)); @@ -442,3 +442,11 @@ impl SpanlessEq for TokenStream { } } } + +impl SpanlessEq for LazyTokenStream { + fn eq(&self, other: &Self) -> bool { + let this = self.into_token_stream(); + let other = other.into_token_stream(); + SpanlessEq::eq(&this, &other) + } +} diff --git a/vendor/syn/tests/test_lit.rs b/vendor/syn/tests/test_lit.rs index e4562b9aee..099daf10ab 100644 --- a/vendor/syn/tests/test_lit.rs +++ b/vendor/syn/tests/test_lit.rs @@ -5,7 +5,7 @@ use proc_macro2::{Delimiter, Group, Literal, Span, TokenStream, TokenTree}; use quote::ToTokens; use std::iter::FromIterator; use std::str::FromStr; -use syn::{Lit, LitFloat, LitInt}; +use syn::{Lit, LitFloat, LitInt, LitStr}; fn lit(s: &str) -> Lit { match TokenStream::from_str(s) @@ -260,3 +260,12 @@ fn test_deep_group_empty() { snapshot!(tokens as Lit, @r#""hi""# ); } + +#[test] +fn test_error() { + let err = syn::parse_str::("...").unwrap_err(); + assert_eq!("expected string literal", err.to_string()); + + let err = syn::parse_str::("5").unwrap_err(); + assert_eq!("expected string literal", err.to_string()); +} diff --git a/vendor/syn/tests/test_meta.rs b/vendor/syn/tests/test_meta.rs index d37dda948a..de6cc4da8c 100644 --- a/vendor/syn/tests/test_meta.rs +++ b/vendor/syn/tests/test_meta.rs @@ -337,3 +337,40 @@ fn test_parse_nested_meta() { }) "###); } + +#[test] +fn test_parse_path() { + let input = "::serde::Serialize"; + snapshot!(input as Meta, @r###" + Path(Path { + leading_colon: Some, + segments: [ + PathSegment { + ident: "serde", + arguments: None, + }, + PathSegment { + ident: "Serialize", + arguments: None, + }, + ], + }) + "###); + + let input = "::serde::Serialize"; + snapshot!(input as NestedMeta, @r###" + Meta(Path(Path { + leading_colon: Some, + segments: [ + PathSegment { + ident: "serde", + arguments: None, + }, + PathSegment { + ident: "Serialize", + arguments: None, + }, + ], + })) + "###); +} diff --git a/version b/version index 3a2b292f37..2a83c08909 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.49.0 (e1884a8e3 2020-12-29) \ No newline at end of file +1.50.0 (cb75ad5db 2021-02-10) \ No newline at end of file -- 2.39.2

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.iter.find(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Rev +where + I: ExactSizeIterator + DoubleEndedIterator, +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Rev where I: TrustedLen + DoubleEndedIterator {} diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs new file mode 100644 index 0000000000..0214899295 --- /dev/null +++ b/library/core/src/iter/adapters/scan.rs @@ -0,0 +1,111 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator to maintain state while iterating another iterator. +/// +/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`scan`]: Iterator::scan +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Scan { + iter: I, + f: F, + state: St, +} + +impl Scan { + pub(in crate::iter) fn new(iter: I, state: St, f: F) -> Scan { + Scan { iter, state, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Scan { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Scan").field("iter", &self.iter).field("state", &self.state).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Scan +where + I: Iterator, + F: FnMut(&mut St, I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + let a = self.iter.next()?; + (self.f)(&mut self.state, a) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the scan function + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn scan<'a, T, St, B, Acc, R: Try>( + state: &'a mut St, + f: &'a mut impl FnMut(&mut St, T) -> Option, + mut fold: impl FnMut(Acc, B) -> R + 'a, + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { + move |acc, x| match f(state, x) { + None => ControlFlow::Break(try { acc }), + Some(x) => ControlFlow::from_try(fold(acc, x)), + } + } + + let state = &mut self.state; + let f = &mut self.f; + self.iter.try_fold(init, scan(state, f, fold)).into_try() + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Scan +where + I: SourceIter, + F: FnMut(&mut St, I::Item) -> Option, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Scan where + F: FnMut(&mut St, I::Item) -> Option +{ +} diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs new file mode 100644 index 0000000000..dd5325660c --- /dev/null +++ b/library/core/src/iter/adapters/skip.rs @@ -0,0 +1,199 @@ +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that skips over `n` elements of `iter`. +/// +/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip`]: Iterator::skip +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Skip { + iter: I, + n: usize, +} + +impl Skip { + pub(in crate::iter) fn new(iter: I, n: usize) -> Skip { + Skip { iter, n } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Skip +where + I: Iterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.n == 0 { + self.iter.next() + } else { + let old_n = self.n; + self.n = 0; + self.iter.nth(old_n) + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + // Can't just add n + self.n due to overflow. + if self.n > 0 { + let to_skip = self.n; + self.n = 0; + // nth(n) skips n+1 + self.iter.nth(to_skip - 1)?; + } + self.iter.nth(n) + } + + #[inline] + fn count(mut self) -> usize { + if self.n > 0 { + // nth(n) skips n+1 + if self.iter.nth(self.n - 1).is_none() { + return 0; + } + } + self.iter.count() + } + + #[inline] + fn last(mut self) -> Option { + if self.n > 0 { + // nth(n) skips n+1 + self.iter.nth(self.n - 1)?; + } + self.iter.last() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.iter.size_hint(); + + let lower = lower.saturating_sub(self.n); + let upper = match upper { + Some(x) => Some(x.saturating_sub(self.n)), + None => None, + }; + + (lower, upper) + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + let n = self.n; + self.n = 0; + if n > 0 { + // nth(n) skips n+1 + if self.iter.nth(n - 1).is_none() { + return try { init }; + } + } + self.iter.try_fold(init, fold) + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.n > 0 { + // nth(n) skips n+1 + if self.iter.nth(self.n - 1).is_none() { + return init; + } + } + self.iter.fold(init, fold) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Skip where I: ExactSizeIterator {} + +#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")] +impl DoubleEndedIterator for Skip +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + fn next_back(&mut self) -> Option { + if self.len() > 0 { self.iter.next_back() } else { None } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n < len { + self.iter.nth_back(n) + } else { + if len > 0 { + // consume the original iterator + self.iter.nth_back(len - 1); + } + None + } + } + + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn check>( + mut n: usize, + mut fold: impl FnMut(Acc, T) -> R, + ) -> impl FnMut(Acc, T) -> ControlFlow { + move |acc, x| { + n -= 1; + let r = fold(acc, x); + if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } + } + } + + let n = self.len(); + if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() } + } + + fn rfold(mut self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_rfold(init, ok(fold)).unwrap() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Skip where I: FusedIterator {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Skip +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Skip {} diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs new file mode 100644 index 0000000000..efcb469fc9 --- /dev/null +++ b/library/core/src/iter/adapters/skip_while.rs @@ -0,0 +1,126 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::Try; + +/// An iterator that rejects elements while `predicate` returns `true`. +/// +/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip_while`]: Iterator::skip_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct SkipWhile { + iter: I, + flag: bool, + predicate: P, +} + +impl SkipWhile { + pub(in crate::iter) fn new(iter: I, predicate: P) -> SkipWhile { + SkipWhile { iter, flag: false, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SkipWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SkipWhile").field("iter", &self.iter).field("flag", &self.flag).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for SkipWhile +where + P: FnMut(&I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + fn check<'a, T>( + flag: &'a mut bool, + pred: &'a mut impl FnMut(&T) -> bool, + ) -> impl FnMut(&T) -> bool + 'a { + move |x| { + if *flag || !pred(x) { + *flag = true; + true + } else { + false + } + } + } + + let flag = &mut self.flag; + let pred = &mut self.predicate; + self.iter.find(check(flag, pred)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + if !self.flag { + match self.next() { + Some(v) => init = fold(init, v)?, + None => return try { init }, + } + } + self.iter.try_fold(init, fold) + } + + #[inline] + fn fold(mut self, mut init: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + if !self.flag { + match self.next() { + Some(v) => init = fold(init, v), + None => return init, + } + } + self.iter.fold(init, fold) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SkipWhile +where + I: FusedIterator, + P: FnMut(&I::Item) -> bool, +{ +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for SkipWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for SkipWhile where + F: FnMut(&I::Item) -> bool +{ +} diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs new file mode 100644 index 0000000000..2ba56eeccb --- /dev/null +++ b/library/core/src/iter/adapters/step_by.rs @@ -0,0 +1,235 @@ +use crate::{intrinsics, iter::from_fn, ops::Try}; + +/// An iterator for stepping iterators by a custom amount. +/// +/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See +/// its documentation for more. +/// +/// [`step_by`]: Iterator::step_by +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "iterator_step_by", since = "1.28.0")] +#[derive(Clone, Debug)] +pub struct StepBy { + iter: I, + step: usize, + first_take: bool, +} + +impl StepBy { + pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy { + assert!(step != 0); + StepBy { iter, step: step - 1, first_take: true } + } +} + +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl Iterator for StepBy +where + I: Iterator, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.first_take { + self.first_take = false; + self.iter.next() + } else { + self.iter.nth(self.step) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + #[inline] + fn first_size(step: usize) -> impl Fn(usize) -> usize { + move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } + } + + #[inline] + fn other_size(step: usize) -> impl Fn(usize) -> usize { + move |n| n / (step + 1) + } + + let (low, high) = self.iter.size_hint(); + + if self.first_take { + let f = first_size(self.step); + (f(low), high.map(f)) + } else { + let f = other_size(self.step); + (f(low), high.map(f)) + } + } + + #[inline] + fn nth(&mut self, mut n: usize) -> Option { + if self.first_take { + self.first_take = false; + let first = self.iter.next(); + if n == 0 { + return first; + } + n -= 1; + } + // n and self.step are indices, we need to add 1 to get the amount of elements + // When calling `.nth`, we need to subtract 1 again to convert back to an index + // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` + let mut step = self.step + 1; + // n + 1 could overflow + // thus, if n is usize::MAX, instead of adding one, we call .nth(step) + if n == usize::MAX { + self.iter.nth(step - 1); + } else { + n += 1; + } + + // overflow handling + loop { + let mul = n.checked_mul(step); + { + if intrinsics::likely(mul.is_some()) { + return self.iter.nth(mul.unwrap() - 1); + } + } + let div_n = usize::MAX / n; + let div_step = usize::MAX / step; + let nth_n = div_n * n; + let nth_step = div_step * step; + let nth = if nth_n > nth_step { + step -= div_n; + nth_n + } else { + n -= div_step; + nth_step + }; + self.iter.nth(nth - 1); + } + } + + fn try_fold(&mut self, mut acc: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { + move || iter.nth(step) + } + + if self.first_take { + self.first_take = false; + match self.iter.next() { + None => return try { acc }, + Some(x) => acc = f(acc, x)?, + } + } + from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) + } + + fn fold(mut self, mut acc: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn nth(iter: &mut I, step: usize) -> impl FnMut() -> Option + '_ { + move || iter.nth(step) + } + + if self.first_take { + self.first_take = false; + match self.iter.next() { + None => return acc, + Some(x) => acc = f(acc, x), + } + } + from_fn(nth(&mut self.iter, self.step)).fold(acc, f) + } +} + +impl StepBy +where + I: ExactSizeIterator, +{ + // The zero-based index starting from the end of the iterator of the + // last element. Used in the `DoubleEndedIterator` implementation. + fn next_back_index(&self) -> usize { + let rem = self.iter.len() % (self.step + 1); + if self.first_take { + if rem == 0 { self.step } else { rem - 1 } + } else { + rem + } + } +} + +#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] +impl DoubleEndedIterator for StepBy +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.iter.nth_back(self.next_back_index()) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + // `self.iter.nth_back(usize::MAX)` does the right thing here when `n` + // is out of bounds because the length of `self.iter` does not exceed + // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is + // zero-indexed + let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index()); + self.iter.nth_back(n) + } + + fn try_rfold(&mut self, init: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try, + { + #[inline] + fn nth_back( + iter: &mut I, + step: usize, + ) -> impl FnMut() -> Option + '_ { + move || iter.nth_back(step) + } + + match self.next_back() { + None => try { init }, + Some(x) => { + let acc = f(init, x)?; + from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) + } + } + } + + #[inline] + fn rfold(mut self, init: Acc, mut f: F) -> Acc + where + Self: Sized, + F: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn nth_back( + iter: &mut I, + step: usize, + ) -> impl FnMut() -> Option + '_ { + move || iter.nth_back(step) + } + + match self.next_back() { + None => init, + Some(x) => { + let acc = f(init, x); + from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f) + } + } + } +} + +// StepBy can only make the iterator shorter, so the len will still fit. +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs new file mode 100644 index 0000000000..9efc7a480a --- /dev/null +++ b/library/core/src/iter/adapters/take.rs @@ -0,0 +1,209 @@ +use crate::cmp; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that only iterates over the first `n` iterations of `iter`. +/// +/// This `struct` is created by the [`take`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take`]: Iterator::take +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Take { + iter: I, + n: usize, +} + +impl Take { + pub(in crate::iter) fn new(iter: I, n: usize) -> Take { + Take { iter, n } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Take +where + I: Iterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + if self.n != 0 { + self.n -= 1; + self.iter.next() + } else { + None + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + if self.n > n { + self.n -= n + 1; + self.iter.nth(n) + } else { + if self.n > 0 { + self.iter.nth(self.n - 1); + self.n = 0; + } + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.n == 0 { + return (0, Some(0)); + } + + let (lower, upper) = self.iter.size_hint(); + + let lower = cmp::min(lower, self.n); + + let upper = match upper { + Some(x) if x < self.n => Some(x), + _ => Some(self.n), + }; + + (lower, upper) + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn check<'a, T, Acc, R: Try>( + n: &'a mut usize, + mut fold: impl FnMut(Acc, T) -> R + 'a, + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { + move |acc, x| { + *n -= 1; + let r = fold(acc, x); + if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } + } + } + + if self.n == 0 { + try { init } + } else { + let n = &mut self.n; + self.iter.try_fold(init, check(n, fold)).into_try() + } + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Take +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Take {} + +#[stable(feature = "double_ended_take_iterator", since = "1.38.0")] +impl DoubleEndedIterator for Take +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + if self.n == 0 { + None + } else { + let n = self.n; + self.n -= 1; + self.iter.nth_back(self.iter.len().saturating_sub(n)) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.iter.len(); + if self.n > n { + let m = len.saturating_sub(self.n) + n; + self.n -= n + 1; + self.iter.nth_back(m) + } else { + if len > 0 { + self.iter.nth_back(len - 1); + } + None + } + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + if self.n == 0 { + try { init } + } else { + let len = self.iter.len(); + if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { + try { init } + } else { + self.iter.try_rfold(init, fold) + } + } + } + + #[inline] + fn rfold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.n == 0 { + init + } else { + let len = self.iter.len(); + if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { + init + } else { + self.iter.rfold(init, fold) + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Take where I: ExactSizeIterator {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Take where I: FusedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Take {} diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs new file mode 100644 index 0000000000..746eb41f4c --- /dev/null +++ b/library/core/src/iter/adapters/take_while.rs @@ -0,0 +1,139 @@ +use crate::fmt; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::ops::{ControlFlow, Try}; + +/// An iterator that only accepts elements while `predicate` returns `true`. +/// +/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take_while`]: Iterator::take_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct TakeWhile { + iter: I, + flag: bool, + predicate: P, +} + +impl TakeWhile { + pub(in crate::iter) fn new(iter: I, predicate: P) -> TakeWhile { + TakeWhile { iter, flag: false, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for TakeWhile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TakeWhile").field("iter", &self.iter).field("flag", &self.flag).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for TakeWhile +where + P: FnMut(&I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.flag { + None + } else { + let x = self.iter.next()?; + if (self.predicate)(&x) { + Some(x) + } else { + self.flag = true; + None + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.flag { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> R, + R: Try, + { + fn check<'a, T, Acc, R: Try>( + flag: &'a mut bool, + p: &'a mut impl FnMut(&T) -> bool, + mut fold: impl FnMut(Acc, T) -> R + 'a, + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { + move |acc, x| { + if p(&x) { + ControlFlow::from_try(fold(acc, x)) + } else { + *flag = true; + ControlFlow::Break(try { acc }) + } + } + } + + if self.flag { + try { init } + } else { + let flag = &mut self.flag; + let p = &mut self.predicate; + self.iter.try_fold(init, check(flag, p, fold)).into_try() + } + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + #[inline] + fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { + move |acc, x| Ok(f(acc, x)) + } + + self.try_fold(init, ok(fold)).unwrap() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for TakeWhile +where + I: FusedIterator, + P: FnMut(&I::Item) -> bool, +{ +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for TakeWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for TakeWhile where + F: FnMut(&I::Item) -> bool +{ +} diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 78712988ea..8cd4c77523 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,10 +1,7 @@ use crate::cmp; use crate::fmt::{self, Debug}; - -use super::super::{ - DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, SourceIter, - TrustedLen, -}; +use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; +use crate::iter::{InPlaceIterable, SourceIter, TrustedLen}; /// An iterator that iterates two other iterators simultaneously. /// @@ -21,7 +18,7 @@ pub struct Zip { len: usize, } impl Zip { - pub(in super::super) fn new(a: A, b: B) -> Zip { + pub(in crate::iter) fn new(a: A, b: B) -> Zip { ZipImpl::new(a, b) } fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> { diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 59f333e888..3e74637b49 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -206,6 +206,51 @@ //! 2. If you're creating a collection, implementing [`IntoIterator`] for it //! will allow your collection to be used with the `for` loop. //! +//! # Iterating by reference +//! +//! Since [`into_iter()`] takes `self` by value, using a `for` loop to iterate +//! over a collection consumes that collection. Often, you may want to iterate +//! over a collection without consuming it. Many collections offer methods that +//! provide iterators over references, conventionally called `iter()` and +//! `iter_mut()` respectively: +//! +//! ``` +//! let mut values = vec![41]; +//! for x in values.iter_mut() { +//! *x += 1; +//! } +//! for x in values.iter() { +//! assert_eq!(*x, 42); +//! } +//! assert_eq!(values.len(), 1); // `values` is still owned by this function. +//! ``` +//! +//! If a collection type `C` provides `iter()`, it usually also implements +//! `IntoIterator` for `&C`, with an implementation that just calls `iter()`. +//! Likewise, a collection `C` that provides `iter_mut()` generally implements +//! `IntoIterator` for `&mut C` by delegating to `iter_mut()`. This enables a +//! convenient shorthand: +//! +//! ``` +//! let mut values = vec![41]; +//! for x in &mut values { // same as `values.iter_mut()` +//! *x += 1; +//! } +//! for x in &values { // same as `values.iter()` +//! assert_eq!(*x, 42); +//! } +//! assert_eq!(values.len(), 1); +//! ``` +//! +//! While many collections offer `iter()`, not all offer `iter_mut()`. For +//! example, mutating the keys of a [`HashSet`] or [`HashMap`] could +//! put the collection into an inconsistent state if the key hashes change, so +//! these collections only offer `iter()`. +//! +//! [`into_iter()`]: IntoIterator::into_iter +//! [`HashSet`]: ../../std/collections/struct.HashSet.html +//! [`HashMap`]: ../../std/collections/struct.HashMap.html +//! //! # Adapters //! //! Functions which take an [`Iterator`] and return another [`Iterator`] are @@ -335,15 +380,14 @@ pub use self::sources::{successors, Successors}; #[stable(feature = "fused", since = "1.26.0")] pub use self::traits::FusedIterator; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::traits::InPlaceIterable; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::traits::{DoubleEndedIterator, Extend, FromIterator, IntoIterator}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::traits::{ExactSizeIterator, Product, Sum}; - -#[unstable(issue = "none", feature = "inplace_iteration")] -pub use self::traits::InPlaceIterable; +pub use self::traits::{ + DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, +}; #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::adapters::Cloned; @@ -351,21 +395,19 @@ pub use self::adapters::Cloned; pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; - #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::adapters::MapWhile; -#[unstable(issue = "none", feature = "inplace_iteration")] +#[unstable(feature = "inplace_iteration", issue = "none")] pub use self::adapters::SourceIter; #[stable(feature = "iterator_step_by", since = "1.28.0")] pub use self::adapters::StepBy; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccess; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::adapters::{Chain, Cycle, Enumerate, Filter, FilterMap, Map, Rev, Zip}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::adapters::{FlatMap, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::adapters::{Fuse, Inspect}; +pub use self::adapters::{ + Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, + Skip, SkipWhile, Take, TakeWhile, Zip, +}; pub(crate) use self::adapters::process_results; diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 44da8f4715..de0663141e 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -1,625 +1,27 @@ -use crate::fmt; -use crate::marker; +mod empty; +mod from_fn; +mod once; +mod once_with; +mod repeat; +mod repeat_with; +mod successors; -use super::{FusedIterator, TrustedLen}; +pub use self::repeat::{repeat, Repeat}; -/// An iterator that repeats an element endlessly. -/// -/// This `struct` is created by the [`repeat()`] function. See its documentation for more. -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Repeat { - element: A, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Repeat { - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - Some(self.element.clone()) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Repeat { - #[inline] - fn next_back(&mut self) -> Option { - Some(self.element.clone()) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Repeat {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Repeat {} - -/// Creates a new iterator that endlessly repeats a single element. -/// -/// The `repeat()` function repeats a single value over and over again. -/// -/// Infinite iterators like `repeat()` are often used with adapters like -/// [`Iterator::take()`], in order to make them finite. -/// -/// If the element type of the iterator you need does not implement `Clone`, -/// or if you do not want to keep the repeated element in memory, you can -/// instead use the [`repeat_with()`] function. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // the number four 4ever: -/// let mut fours = iter::repeat(4); -/// -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// assert_eq!(Some(4), fours.next()); -/// -/// // yup, still four -/// assert_eq!(Some(4), fours.next()); -/// ``` -/// -/// Going finite with [`Iterator::take()`]: -/// -/// ``` -/// use std::iter; -/// -/// // that last example was too many fours. Let's only have four fours. -/// let mut four_fours = iter::repeat(4).take(4); -/// -/// assert_eq!(Some(4), four_fours.next()); -/// assert_eq!(Some(4), four_fours.next()); -/// assert_eq!(Some(4), four_fours.next()); -/// assert_eq!(Some(4), four_fours.next()); -/// -/// // ... and now we're done -/// assert_eq!(None, four_fours.next()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn repeat(elt: T) -> Repeat { - Repeat { element: elt } -} - -/// An iterator that repeats elements of type `A` endlessly by -/// applying the provided closure `F: FnMut() -> A`. -/// -/// This `struct` is created by the [`repeat_with()`] function. -/// See its documentation for more. -#[derive(Copy, Clone, Debug)] -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -pub struct RepeatWith { - repeater: F, -} - -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -impl A> Iterator for RepeatWith { - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - Some((self.repeater)()) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -impl A> FusedIterator for RepeatWith {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl A> TrustedLen for RepeatWith {} - -/// Creates a new iterator that repeats elements of type `A` endlessly by -/// applying the provided closure, the repeater, `F: FnMut() -> A`. -/// -/// The `repeat_with()` function calls the repeater over and over again. -/// -/// Infinite iterators like `repeat_with()` are often used with adapters like -/// [`Iterator::take()`], in order to make them finite. -/// -/// If the element type of the iterator you need implements [`Clone`], and -/// it is OK to keep the source element in memory, you should instead use -/// the [`repeat()`] function. -/// -/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`]. -/// If you need `repeat_with()` to return a [`DoubleEndedIterator`], -/// please open a GitHub issue explaining your use case. -/// -/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // let's assume we have some value of a type that is not `Clone` -/// // or which don't want to have in memory just yet because it is expensive: -/// #[derive(PartialEq, Debug)] -/// struct Expensive; -/// -/// // a particular value forever: -/// let mut things = iter::repeat_with(|| Expensive); -/// -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// assert_eq!(Some(Expensive), things.next()); -/// ``` -/// -/// Using mutation and going finite: -/// -/// ```rust -/// use std::iter; -/// -/// // From the zeroth to the third power of two: -/// let mut curr = 1; -/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) -/// .take(4); -/// -/// assert_eq!(Some(1), pow2.next()); -/// assert_eq!(Some(2), pow2.next()); -/// assert_eq!(Some(4), pow2.next()); -/// assert_eq!(Some(8), pow2.next()); -/// -/// // ... and now we're done -/// assert_eq!(None, pow2.next()); -/// ``` -#[inline] -#[stable(feature = "iterator_repeat_with", since = "1.28.0")] -pub fn repeat_with A>(repeater: F) -> RepeatWith { - RepeatWith { repeater } -} - -/// An iterator that yields nothing. -/// -/// This `struct` is created by the [`empty()`] function. See its documentation for more. #[stable(feature = "iter_empty", since = "1.2.0")] -pub struct Empty(marker::PhantomData); - -#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] -unsafe impl Send for Empty {} -#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] -unsafe impl Sync for Empty {} +pub use self::empty::{empty, Empty}; -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Empty { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Empty") - } -} - -#[stable(feature = "iter_empty", since = "1.2.0")] -impl Iterator for Empty { - type Item = T; - - fn next(&mut self) -> Option { - None - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) - } -} - -#[stable(feature = "iter_empty", since = "1.2.0")] -impl DoubleEndedIterator for Empty { - fn next_back(&mut self) -> Option { - None - } -} - -#[stable(feature = "iter_empty", since = "1.2.0")] -impl ExactSizeIterator for Empty { - fn len(&self) -> usize { - 0 - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Empty {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Empty {} - -// not #[derive] because that adds a Clone bound on T, -// which isn't necessary. -#[stable(feature = "iter_empty", since = "1.2.0")] -impl Clone for Empty { - fn clone(&self) -> Empty { - Empty(marker::PhantomData) - } -} - -// not #[derive] because that adds a Default bound on T, -// which isn't necessary. -#[stable(feature = "iter_empty", since = "1.2.0")] -impl Default for Empty { - fn default() -> Empty { - Empty(marker::PhantomData) - } -} - -/// Creates an iterator that yields nothing. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // this could have been an iterator over i32, but alas, it's just not. -/// let mut nope = iter::empty::(); -/// -/// assert_eq!(None, nope.next()); -/// ``` -#[stable(feature = "iter_empty", since = "1.2.0")] -#[rustc_const_stable(feature = "const_iter_empty", since = "1.32.0")] -pub const fn empty() -> Empty { - Empty(marker::PhantomData) -} - -/// An iterator that yields an element exactly once. -/// -/// This `struct` is created by the [`once()`] function. See its documentation for more. -#[derive(Clone, Debug)] #[stable(feature = "iter_once", since = "1.2.0")] -pub struct Once { - inner: crate::option::IntoIter, -} +pub use self::once::{once, Once}; -#[stable(feature = "iter_once", since = "1.2.0")] -impl Iterator for Once { - type Item = T; - - fn next(&mut self) -> Option { - self.inner.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "iter_once", since = "1.2.0")] -impl DoubleEndedIterator for Once { - fn next_back(&mut self) -> Option { - self.inner.next_back() - } -} - -#[stable(feature = "iter_once", since = "1.2.0")] -impl ExactSizeIterator for Once { - fn len(&self) -> usize { - self.inner.len() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Once {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Once {} - -/// Creates an iterator that yields an element exactly once. -/// -/// This is commonly used to adapt a single value into a [`chain()`] of other -/// kinds of iteration. Maybe you have an iterator that covers almost -/// everything, but you need an extra special case. Maybe you have a function -/// which works on iterators, but you only need to process one value. -/// -/// [`chain()`]: Iterator::chain -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // one is the loneliest number -/// let mut one = iter::once(1); -/// -/// assert_eq!(Some(1), one.next()); -/// -/// // just one, that's all we get -/// assert_eq!(None, one.next()); -/// ``` -/// -/// Chaining together with another iterator. Let's say that we want to iterate -/// over each file of the `.foo` directory, but also a configuration file, -/// `.foorc`: -/// -/// ```no_run -/// use std::iter; -/// use std::fs; -/// use std::path::PathBuf; -/// -/// let dirs = fs::read_dir(".foo").unwrap(); -/// -/// // we need to convert from an iterator of DirEntry-s to an iterator of -/// // PathBufs, so we use map -/// let dirs = dirs.map(|file| file.unwrap().path()); -/// -/// // now, our iterator just for our config file -/// let config = iter::once(PathBuf::from(".foorc")); -/// -/// // chain the two iterators together into one big iterator -/// let files = dirs.chain(config); -/// -/// // this will give us all of the files in .foo as well as .foorc -/// for f in files { -/// println!("{:?}", f); -/// } -/// ``` -#[stable(feature = "iter_once", since = "1.2.0")] -pub fn once(value: T) -> Once { - Once { inner: Some(value).into_iter() } -} - -/// An iterator that yields a single element of type `A` by -/// applying the provided closure `F: FnOnce() -> A`. -/// -/// This `struct` is created by the [`once_with()`] function. -/// See its documentation for more. -#[derive(Clone, Debug)] -#[stable(feature = "iter_once_with", since = "1.43.0")] -pub struct OnceWith { - gen: Option, -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> Iterator for OnceWith { - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - let f = self.gen.take()?; - Some(f()) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.gen.iter().size_hint() - } -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> DoubleEndedIterator for OnceWith { - fn next_back(&mut self) -> Option { - self.next() - } -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> ExactSizeIterator for OnceWith { - fn len(&self) -> usize { - self.gen.iter().len() - } -} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -impl A> FusedIterator for OnceWith {} - -#[stable(feature = "iter_once_with", since = "1.43.0")] -unsafe impl A> TrustedLen for OnceWith {} - -/// Creates an iterator that lazily generates a value exactly once by invoking -/// the provided closure. -/// -/// This is commonly used to adapt a single value generator into a [`chain()`] of -/// other kinds of iteration. Maybe you have an iterator that covers almost -/// everything, but you need an extra special case. Maybe you have a function -/// which works on iterators, but you only need to process one value. -/// -/// Unlike [`once()`], this function will lazily generate the value on request. -/// -/// [`chain()`]: Iterator::chain -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter; -/// -/// // one is the loneliest number -/// let mut one = iter::once_with(|| 1); -/// -/// assert_eq!(Some(1), one.next()); -/// -/// // just one, that's all we get -/// assert_eq!(None, one.next()); -/// ``` -/// -/// Chaining together with another iterator. Let's say that we want to iterate -/// over each file of the `.foo` directory, but also a configuration file, -/// `.foorc`: -/// -/// ```no_run -/// use std::iter; -/// use std::fs; -/// use std::path::PathBuf; -/// -/// let dirs = fs::read_dir(".foo").unwrap(); -/// -/// // we need to convert from an iterator of DirEntry-s to an iterator of -/// // PathBufs, so we use map -/// let dirs = dirs.map(|file| file.unwrap().path()); -/// -/// // now, our iterator just for our config file -/// let config = iter::once_with(|| PathBuf::from(".foorc")); -/// -/// // chain the two iterators together into one big iterator -/// let files = dirs.chain(config); -/// -/// // this will give us all of the files in .foo as well as .foorc -/// for f in files { -/// println!("{:?}", f); -/// } -/// ``` -#[inline] -#[stable(feature = "iter_once_with", since = "1.43.0")] -pub fn once_with A>(gen: F) -> OnceWith { - OnceWith { gen: Some(gen) } -} - -/// Creates a new iterator where each iteration calls the provided closure -/// `F: FnMut() -> Option`. -/// -/// This allows creating a custom iterator with any behavior -/// without using the more verbose syntax of creating a dedicated type -/// and implementing the [`Iterator`] trait for it. -/// -/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, -/// and therefore conservatively does not implement [`FusedIterator`], -/// or override [`Iterator::size_hint()`] from its default `(0, None)`. -/// -/// The closure can use captures and its environment to track state across iterations. Depending on -/// how the iterator is used, this may require specifying the [`move`] keyword on the closure. -/// -/// [`move`]: ../../std/keyword.move.html -/// -/// # Examples -/// -/// Let’s re-implement the counter iterator from the [module-level documentation]: -/// -/// [module-level documentation]: super -/// -/// ``` -/// let mut count = 0; -/// let counter = std::iter::from_fn(move || { -/// // Increment our count. This is why we started at zero. -/// count += 1; -/// -/// // Check to see if we've finished counting or not. -/// if count < 6 { -/// Some(count) -/// } else { -/// None -/// } -/// }); -/// assert_eq!(counter.collect::>(), &[1, 2, 3, 4, 5]); -/// ``` -#[inline] -#[stable(feature = "iter_from_fn", since = "1.34.0")] -pub fn from_fn(f: F) -> FromFn -where - F: FnMut() -> Option, -{ - FromFn(f) -} - -/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. -/// -/// This `struct` is created by the [`iter::from_fn()`] function. -/// See its documentation for more. -/// -/// [`iter::from_fn()`]: from_fn -#[derive(Clone)] -#[stable(feature = "iter_from_fn", since = "1.34.0")] -pub struct FromFn(F); - -#[stable(feature = "iter_from_fn", since = "1.34.0")] -impl Iterator for FromFn -where - F: FnMut() -> Option, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - (self.0)() - } -} +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +pub use self::repeat_with::{repeat_with, RepeatWith}; #[stable(feature = "iter_from_fn", since = "1.34.0")] -impl fmt::Debug for FromFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FromFn").finish() - } -} +pub use self::from_fn::{from_fn, FromFn}; -/// Creates a new iterator where each successive item is computed based on the preceding one. -/// -/// The iterator starts with the given first item (if any) -/// and calls the given `FnMut(&T) -> Option` closure to compute each item’s successor. -/// -/// ``` -/// use std::iter::successors; -/// -/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); -/// assert_eq!(powers_of_10.collect::>(), &[1, 10, 100, 1_000, 10_000]); -/// ``` #[stable(feature = "iter_successors", since = "1.34.0")] -pub fn successors(first: Option, succ: F) -> Successors -where - F: FnMut(&T) -> Option, -{ - // If this function returned `impl Iterator` - // it could be based on `unfold` and not need a dedicated type. - // However having a named `Successors` type allows it to be `Clone` when `T` and `F` are. - Successors { next: first, succ } -} +pub use self::successors::{successors, Successors}; -/// An new iterator where each successive item is computed based on the preceding one. -/// -/// This `struct` is created by the [`iter::successors()`] function. -/// See its documentation for more. -/// -/// [`iter::successors()`]: successors -#[derive(Clone)] -#[stable(feature = "iter_successors", since = "1.34.0")] -pub struct Successors { - next: Option, - succ: F, -} - -#[stable(feature = "iter_successors", since = "1.34.0")] -impl Iterator for Successors -where - F: FnMut(&T) -> Option, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - let item = self.next.take()?; - self.next = (self.succ)(&item); - Some(item) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.next.is_some() { (1, None) } else { (0, Some(0)) } - } -} - -#[stable(feature = "iter_successors", since = "1.34.0")] -impl FusedIterator for Successors where F: FnMut(&T) -> Option {} - -#[stable(feature = "iter_successors", since = "1.34.0")] -impl fmt::Debug for Successors { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Successors").field("next", &self.next).finish() - } -} +#[stable(feature = "iter_once_with", since = "1.43.0")] +pub use self::once_with::{once_with, OnceWith}; diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs new file mode 100644 index 0000000000..5d4a9fe8c6 --- /dev/null +++ b/library/core/src/iter/sources/empty.rs @@ -0,0 +1,92 @@ +use crate::fmt; +use crate::iter::{FusedIterator, TrustedLen}; +use crate::marker; + +/// Creates an iterator that yields nothing. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // this could have been an iterator over i32, but alas, it's just not. +/// let mut nope = iter::empty::(); +/// +/// assert_eq!(None, nope.next()); +/// ``` +#[stable(feature = "iter_empty", since = "1.2.0")] +#[rustc_const_stable(feature = "const_iter_empty", since = "1.32.0")] +pub const fn empty() -> Empty { + Empty(marker::PhantomData) +} + +/// An iterator that yields nothing. +/// +/// This `struct` is created by the [`empty()`] function. See its documentation for more. +#[stable(feature = "iter_empty", since = "1.2.0")] +pub struct Empty(marker::PhantomData); + +#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] +unsafe impl Send for Empty {} +#[stable(feature = "iter_empty_send_sync", since = "1.42.0")] +unsafe impl Sync for Empty {} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Empty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Empty") + } +} + +#[stable(feature = "iter_empty", since = "1.2.0")] +impl Iterator for Empty { + type Item = T; + + fn next(&mut self) -> Option { + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +#[stable(feature = "iter_empty", since = "1.2.0")] +impl DoubleEndedIterator for Empty { + fn next_back(&mut self) -> Option { + None + } +} + +#[stable(feature = "iter_empty", since = "1.2.0")] +impl ExactSizeIterator for Empty { + fn len(&self) -> usize { + 0 + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Empty {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Empty {} + +// not #[derive] because that adds a Clone bound on T, +// which isn't necessary. +#[stable(feature = "iter_empty", since = "1.2.0")] +impl Clone for Empty { + fn clone(&self) -> Empty { + Empty(marker::PhantomData) + } +} + +// not #[derive] because that adds a Default bound on T, +// which isn't necessary. +#[stable(feature = "iter_empty", since = "1.2.0")] +impl Default for Empty { + fn default() -> Empty { + Empty(marker::PhantomData) + } +} diff --git a/library/core/src/iter/sources/from_fn.rs b/library/core/src/iter/sources/from_fn.rs new file mode 100644 index 0000000000..3cd3830471 --- /dev/null +++ b/library/core/src/iter/sources/from_fn.rs @@ -0,0 +1,78 @@ +use crate::fmt; + +/// Creates a new iterator where each iteration calls the provided closure +/// `F: FnMut() -> Option`. +/// +/// This allows creating a custom iterator with any behavior +/// without using the more verbose syntax of creating a dedicated type +/// and implementing the [`Iterator`] trait for it. +/// +/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, +/// and therefore conservatively does not implement [`FusedIterator`], +/// or override [`Iterator::size_hint()`] from its default `(0, None)`. +/// +/// The closure can use captures and its environment to track state across iterations. Depending on +/// how the iterator is used, this may require specifying the [`move`] keyword on the closure. +/// +/// [`move`]: ../../std/keyword.move.html +/// [`FusedIterator`]: crate::iter::FusedIterator +/// +/// # Examples +/// +/// Let’s re-implement the counter iterator from [module-level documentation]: +/// +/// [module-level documentation]: crate::iter +/// +/// ``` +/// let mut count = 0; +/// let counter = std::iter::from_fn(move || { +/// // Increment our count. This is why we started at zero. +/// count += 1; +/// +/// // Check to see if we've finished counting or not. +/// if count < 6 { +/// Some(count) +/// } else { +/// None +/// } +/// }); +/// assert_eq!(counter.collect::>(), &[1, 2, 3, 4, 5]); +/// ``` +#[inline] +#[stable(feature = "iter_from_fn", since = "1.34.0")] +pub fn from_fn(f: F) -> FromFn +where + F: FnMut() -> Option, +{ + FromFn(f) +} + +/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. +/// +/// This `struct` is created by the [`iter::from_fn()`] function. +/// See its documentation for more. +/// +/// [`iter::from_fn()`]: from_fn +#[derive(Clone)] +#[stable(feature = "iter_from_fn", since = "1.34.0")] +pub struct FromFn(F); + +#[stable(feature = "iter_from_fn", since = "1.34.0")] +impl Iterator for FromFn +where + F: FnMut() -> Option, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + (self.0)() + } +} + +#[stable(feature = "iter_from_fn", since = "1.34.0")] +impl fmt::Debug for FromFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FromFn").finish() + } +} diff --git a/library/core/src/iter/sources/once.rs b/library/core/src/iter/sources/once.rs new file mode 100644 index 0000000000..27bc3dcfd7 --- /dev/null +++ b/library/core/src/iter/sources/once.rs @@ -0,0 +1,99 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates an iterator that yields an element exactly once. +/// +/// This is commonly used to adapt a single value into a [`chain()`] of other +/// kinds of iteration. Maybe you have an iterator that covers almost +/// everything, but you need an extra special case. Maybe you have a function +/// which works on iterators, but you only need to process one value. +/// +/// [`chain()`]: Iterator::chain +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // one is the loneliest number +/// let mut one = iter::once(1); +/// +/// assert_eq!(Some(1), one.next()); +/// +/// // just one, that's all we get +/// assert_eq!(None, one.next()); +/// ``` +/// +/// Chaining together with another iterator. Let's say that we want to iterate +/// over each file of the `.foo` directory, but also a configuration file, +/// `.foorc`: +/// +/// ```no_run +/// use std::iter; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// let dirs = fs::read_dir(".foo").unwrap(); +/// +/// // we need to convert from an iterator of DirEntry-s to an iterator of +/// // PathBufs, so we use map +/// let dirs = dirs.map(|file| file.unwrap().path()); +/// +/// // now, our iterator just for our config file +/// let config = iter::once(PathBuf::from(".foorc")); +/// +/// // chain the two iterators together into one big iterator +/// let files = dirs.chain(config); +/// +/// // this will give us all of the files in .foo as well as .foorc +/// for f in files { +/// println!("{:?}", f); +/// } +/// ``` +#[stable(feature = "iter_once", since = "1.2.0")] +pub fn once(value: T) -> Once { + Once { inner: Some(value).into_iter() } +} + +/// An iterator that yields an element exactly once. +/// +/// This `struct` is created by the [`once()`] function. See its documentation for more. +#[derive(Clone, Debug)] +#[stable(feature = "iter_once", since = "1.2.0")] +pub struct Once { + inner: crate::option::IntoIter, +} + +#[stable(feature = "iter_once", since = "1.2.0")] +impl Iterator for Once { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "iter_once", since = "1.2.0")] +impl DoubleEndedIterator for Once { + fn next_back(&mut self) -> Option { + self.inner.next_back() + } +} + +#[stable(feature = "iter_once", since = "1.2.0")] +impl ExactSizeIterator for Once { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Once {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Once {} diff --git a/library/core/src/iter/sources/once_with.rs b/library/core/src/iter/sources/once_with.rs new file mode 100644 index 0000000000..cf6a3c1152 --- /dev/null +++ b/library/core/src/iter/sources/once_with.rs @@ -0,0 +1,109 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates an iterator that lazily generates a value exactly once by invoking +/// the provided closure. +/// +/// This is commonly used to adapt a single value generator into a [`chain()`] of +/// other kinds of iteration. Maybe you have an iterator that covers almost +/// everything, but you need an extra special case. Maybe you have a function +/// which works on iterators, but you only need to process one value. +/// +/// Unlike [`once()`], this function will lazily generate the value on request. +/// +/// [`chain()`]: Iterator::chain +/// [`once()`]: crate::iter::once +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // one is the loneliest number +/// let mut one = iter::once_with(|| 1); +/// +/// assert_eq!(Some(1), one.next()); +/// +/// // just one, that's all we get +/// assert_eq!(None, one.next()); +/// ``` +/// +/// Chaining together with another iterator. Let's say that we want to iterate +/// over each file of the `.foo` directory, but also a configuration file, +/// `.foorc`: +/// +/// ```no_run +/// use std::iter; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// let dirs = fs::read_dir(".foo").unwrap(); +/// +/// // we need to convert from an iterator of DirEntry-s to an iterator of +/// // PathBufs, so we use map +/// let dirs = dirs.map(|file| file.unwrap().path()); +/// +/// // now, our iterator just for our config file +/// let config = iter::once_with(|| PathBuf::from(".foorc")); +/// +/// // chain the two iterators together into one big iterator +/// let files = dirs.chain(config); +/// +/// // this will give us all of the files in .foo as well as .foorc +/// for f in files { +/// println!("{:?}", f); +/// } +/// ``` +#[inline] +#[stable(feature = "iter_once_with", since = "1.43.0")] +pub fn once_with A>(gen: F) -> OnceWith { + OnceWith { gen: Some(gen) } +} + +/// An iterator that yields a single element of type `A` by +/// applying the provided closure `F: FnOnce() -> A`. +/// +/// This `struct` is created by the [`once_with()`] function. +/// See its documentation for more. +#[derive(Clone, Debug)] +#[stable(feature = "iter_once_with", since = "1.43.0")] +pub struct OnceWith { + gen: Option, +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> Iterator for OnceWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + let f = self.gen.take()?; + Some(f()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.gen.iter().size_hint() + } +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> DoubleEndedIterator for OnceWith { + fn next_back(&mut self) -> Option { + self.next() + } +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> ExactSizeIterator for OnceWith { + fn len(&self) -> usize { + self.gen.iter().len() + } +} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +impl A> FusedIterator for OnceWith {} + +#[stable(feature = "iter_once_with", since = "1.43.0")] +unsafe impl A> TrustedLen for OnceWith {} diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs new file mode 100644 index 0000000000..d1f2879235 --- /dev/null +++ b/library/core/src/iter/sources/repeat.rs @@ -0,0 +1,93 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates a new iterator that endlessly repeats a single element. +/// +/// The `repeat()` function repeats a single value over and over again. +/// +/// Infinite iterators like `repeat()` are often used with adapters like +/// [`Iterator::take()`], in order to make them finite. +/// +/// If the element type of the iterator you need does not implement `Clone`, +/// or if you do not want to keep the repeated element in memory, you can +/// instead use the [`repeat_with()`] function. +/// +/// [`repeat_with()`]: crate::iter::repeat_with +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // the number four 4ever: +/// let mut fours = iter::repeat(4); +/// +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// assert_eq!(Some(4), fours.next()); +/// +/// // yup, still four +/// assert_eq!(Some(4), fours.next()); +/// ``` +/// +/// Going finite with [`Iterator::take()`]: +/// +/// ``` +/// use std::iter; +/// +/// // that last example was too many fours. Let's only have four fours. +/// let mut four_fours = iter::repeat(4).take(4); +/// +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// assert_eq!(Some(4), four_fours.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, four_fours.next()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn repeat(elt: T) -> Repeat { + Repeat { element: elt } +} + +/// An iterator that repeats an element endlessly. +/// +/// This `struct` is created by the [`repeat()`] function. See its documentation for more. +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Repeat { + element: A, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Repeat { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + Some(self.element.clone()) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Repeat { + #[inline] + fn next_back(&mut self) -> Option { + Some(self.element.clone()) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Repeat {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Repeat {} diff --git a/library/core/src/iter/sources/repeat_with.rs b/library/core/src/iter/sources/repeat_with.rs new file mode 100644 index 0000000000..44bc6890c5 --- /dev/null +++ b/library/core/src/iter/sources/repeat_with.rs @@ -0,0 +1,98 @@ +use crate::iter::{FusedIterator, TrustedLen}; + +/// Creates a new iterator that repeats elements of type `A` endlessly by +/// applying the provided closure, the repeater, `F: FnMut() -> A`. +/// +/// The `repeat_with()` function calls the repeater over and over again. +/// +/// Infinite iterators like `repeat_with()` are often used with adapters like +/// [`Iterator::take()`], in order to make them finite. +/// +/// If the element type of the iterator you need implements [`Clone`], and +/// it is OK to keep the source element in memory, you should instead use +/// the [`repeat()`] function. +/// +/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`]. +/// If you need `repeat_with()` to return a [`DoubleEndedIterator`], +/// please open a GitHub issue explaining your use case. +/// +/// [`repeat()`]: crate::iter::repeat +/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // let's assume we have some value of a type that is not `Clone` +/// // or which don't want to have in memory just yet because it is expensive: +/// #[derive(PartialEq, Debug)] +/// struct Expensive; +/// +/// // a particular value forever: +/// let mut things = iter::repeat_with(|| Expensive); +/// +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// ``` +/// +/// Using mutation and going finite: +/// +/// ```rust +/// use std::iter; +/// +/// // From the zeroth to the third power of two: +/// let mut curr = 1; +/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) +/// .take(4); +/// +/// assert_eq!(Some(1), pow2.next()); +/// assert_eq!(Some(2), pow2.next()); +/// assert_eq!(Some(4), pow2.next()); +/// assert_eq!(Some(8), pow2.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, pow2.next()); +/// ``` +#[inline] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +pub fn repeat_with A>(repeater: F) -> RepeatWith { + RepeatWith { repeater } +} + +/// An iterator that repeats elements of type `A` endlessly by +/// applying the provided closure `F: FnMut() -> A`. +/// +/// This `struct` is created by the [`repeat_with()`] function. +/// See its documentation for more. +#[derive(Copy, Clone, Debug)] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +pub struct RepeatWith { + repeater: F, +} + +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +impl A> Iterator for RepeatWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + Some((self.repeater)()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} + +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] +impl A> FusedIterator for RepeatWith {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl A> TrustedLen for RepeatWith {} diff --git a/library/core/src/iter/sources/successors.rs b/library/core/src/iter/sources/successors.rs new file mode 100644 index 0000000000..99f058a901 --- /dev/null +++ b/library/core/src/iter/sources/successors.rs @@ -0,0 +1,66 @@ +use crate::{fmt, iter::FusedIterator}; + +/// Creates a new iterator where each successive item is computed based on the preceding one. +/// +/// The iterator starts with the given first item (if any) +/// and calls the given `FnMut(&T) -> Option` closure to compute each item’s successor. +/// +/// ``` +/// use std::iter::successors; +/// +/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); +/// assert_eq!(powers_of_10.collect::>(), &[1, 10, 100, 1_000, 10_000]); +/// ``` +#[stable(feature = "iter_successors", since = "1.34.0")] +pub fn successors(first: Option, succ: F) -> Successors +where + F: FnMut(&T) -> Option, +{ + // If this function returned `impl Iterator` + // it could be based on `unfold` and not need a dedicated type. + // However having a named `Successors` type allows it to be `Clone` when `T` and `F` are. + Successors { next: first, succ } +} + +/// An new iterator where each successive item is computed based on the preceding one. +/// +/// This `struct` is created by the [`iter::successors()`] function. +/// See its documentation for more. +/// +/// [`iter::successors()`]: successors +#[derive(Clone)] +#[stable(feature = "iter_successors", since = "1.34.0")] +pub struct Successors { + next: Option, + succ: F, +} + +#[stable(feature = "iter_successors", since = "1.34.0")] +impl Iterator for Successors +where + F: FnMut(&T) -> Option, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + let item = self.next.take()?; + self.next = (self.succ)(&item); + Some(item) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.next.is_some() { (1, None) } else { (0, Some(0)) } + } +} + +#[stable(feature = "iter_successors", since = "1.34.0")] +impl FusedIterator for Successors where F: FnMut(&T) -> Option {} + +#[stable(feature = "iter_successors", since = "1.34.0")] +impl fmt::Debug for Successors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Successors").field("next", &self.next).finish() + } +} diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 19484bfd04..7ba16f8928 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1332,7 +1332,7 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// - /// Flattening once only removes one level of nesting: + /// Flattening only removes one level of nesting at a time: /// /// ``` /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]; @@ -1346,7 +1346,7 @@ pub trait Iterator { /// /// Here we see that `flatten()` does not perform a "deep" flatten. /// Instead, only one level of nesting is removed. That is, if you - /// `flatten()` a three-dimensional array the result will be + /// `flatten()` a three-dimensional array, the result will be /// two-dimensional and not one-dimensional. To get a one-dimensional /// structure, you have to `flatten()` again. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 4120254656..5b19bf6b80 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -63,12 +63,14 @@ #![warn(missing_debug_implementations)] #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] -#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] +#![feature(rustc_allow_const_fn_unstable)] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(asm)] #![feature(cfg_target_has_atomic)] +#![cfg_attr(not(bootstrap), feature(const_heap))] #![feature(const_alloc_layout)] +#![feature(const_assert_type)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] #![feature(const_checked_int_methods)] @@ -78,13 +80,12 @@ #![feature(const_overflowing_int_methods)] #![feature(const_int_unchecked_arith)] #![feature(const_mut_refs)] -#![feature(const_int_pow)] -#![feature(constctlz)] +#![feature(const_cttz)] #![feature(const_panic)] #![feature(const_pin)] #![feature(const_fn)] #![feature(const_fn_union)] -#![cfg_attr(not(bootstrap), feature(const_impl_trait))] +#![feature(const_impl_trait)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] #![feature(const_generics)] @@ -93,6 +94,7 @@ #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_raw_ptr_comparison)] +#![feature(const_raw_ptr_deref)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_size_of_val)] @@ -101,6 +103,8 @@ #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] +#![feature(const_maybe_uninit_assume_init)] +#![feature(const_maybe_uninit_as_ptr)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] @@ -118,7 +122,8 @@ #![feature(nll)] #![feature(exhaustive_patterns)] #![feature(no_core)] -#![feature(optin_builtin_traits)] +#![cfg_attr(bootstrap, feature(optin_builtin_traits))] +#![cfg_attr(not(bootstrap), feature(auto_traits))] #![feature(or_patterns)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] @@ -133,9 +138,7 @@ #![feature(transparent_unions)] #![feature(try_blocks)] #![feature(unboxed_closures)] -#![cfg_attr(not(bootstrap), feature(unsized_fn_params))] -#![cfg_attr(bootstrap, feature(unsized_locals))] -#![cfg_attr(bootstrap, feature(untagged_unions))] +#![feature(unsized_fn_params)] #![feature(unwind_attributes)] #![feature(variant_count)] #![feature(tbm_target_feature)] @@ -289,7 +292,7 @@ pub mod primitive; unused_imports, unsafe_op_in_unsafe_fn )] -#[cfg_attr(not(bootstrap), allow(non_autolinks))] +#[allow(non_autolinks)] // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. #[allow(clashing_extern_declarations)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index fe3eff04b4..0699c9eab1 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -2,6 +2,7 @@ #[macro_export] #[allow_internal_unstable(core_panic, const_caller_location)] #[stable(feature = "core", since = "1.6.0")] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "core_panic_macro")] macro_rules! panic { () => ( $crate::panic!("explicit panic") @@ -44,7 +45,7 @@ macro_rules! assert_eq { // The reborrows below are intentional. Without them, the stack slot for the // borrow is initialized even before the values are compared, leading to a // noticeable slow down. - panic!(r#"assertion failed: `(left == right)` + $crate::panic!(r#"assertion failed: `(left == right)` left: `{:?}`, right: `{:?}`"#, &*left_val, &*right_val) } @@ -58,7 +59,7 @@ macro_rules! assert_eq { // The reborrows below are intentional. Without them, the stack slot for the // borrow is initialized even before the values are compared, leading to a // noticeable slow down. - panic!(r#"assertion failed: `(left == right)` + $crate::panic!(r#"assertion failed: `(left == right)` left: `{:?}`, right: `{:?}`: {}"#, &*left_val, &*right_val, $crate::format_args!($($arg)+)) @@ -95,7 +96,7 @@ macro_rules! assert_ne { // The reborrows below are intentional. Without them, the stack slot for the // borrow is initialized even before the values are compared, leading to a // noticeable slow down. - panic!(r#"assertion failed: `(left != right)` + $crate::panic!(r#"assertion failed: `(left != right)` left: `{:?}`, right: `{:?}`"#, &*left_val, &*right_val) } @@ -109,7 +110,7 @@ macro_rules! assert_ne { // The reborrows below are intentional. Without them, the stack slot for the // borrow is initialized even before the values are compared, leading to a // noticeable slow down. - panic!(r#"assertion failed: `(left != right)` + $crate::panic!(r#"assertion failed: `(left != right)` left: `{:?}`, right: `{:?}`: {}"#, &*left_val, &*right_val, $crate::format_args!($($arg)+)) @@ -162,6 +163,7 @@ macro_rules! assert_ne { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "debug_assert_macro")] macro_rules! debug_assert { ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert!($($arg)*); }) } @@ -466,7 +468,7 @@ macro_rules! writeln { /// /// # Panics /// -/// This will always [`panic!`] +/// This will always [`panic!`]. /// /// # Examples /// @@ -500,13 +502,13 @@ macro_rules! writeln { #[stable(feature = "rust1", since = "1.0.0")] macro_rules! unreachable { () => ({ - panic!("internal error: entered unreachable code") + $crate::panic!("internal error: entered unreachable code") }); ($msg:expr $(,)?) => ({ $crate::unreachable!("{}", $msg) }); ($fmt:expr, $($arg:tt)*) => ({ - panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) + $crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) }); } @@ -515,15 +517,15 @@ macro_rules! unreachable { /// This allows your code to type-check, which is useful if you are prototyping or /// implementing a trait that requires multiple methods which you don't plan of using all of. /// -/// The difference between `unimplemented!` and [`todo!`](macro.todo.html) is that while `todo!` +/// The difference between `unimplemented!` and [`todo!`] is that while `todo!` /// conveys an intent of implementing the functionality later and the message is "not yet /// implemented", `unimplemented!` makes no such claims. Its message is "not implemented". /// Also some IDEs will mark `todo!`s. /// /// # Panics /// -/// This will always [panic!](macro.panic.html) because `unimplemented!` is just a -/// shorthand for `panic!` with a fixed, specific message. +/// This will always [`panic!`] because `unimplemented!` is just a shorthand for `panic!` with a +/// fixed, specific message. /// /// Like `panic!`, this macro has a second form for displaying custom values. /// @@ -584,8 +586,8 @@ macro_rules! unreachable { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! unimplemented { - () => (panic!("not implemented")); - ($($arg:tt)+) => (panic!("not implemented: {}", $crate::format_args!($($arg)+))); + () => ($crate::panic!("not implemented")); + ($($arg:tt)+) => ($crate::panic!("not implemented: {}", $crate::format_args!($($arg)+))); } /// Indicates unfinished code. @@ -600,7 +602,7 @@ macro_rules! unimplemented { /// /// # Panics /// -/// This will always [panic!](macro.panic.html) +/// This will always [`panic!`]. /// /// # Examples /// @@ -645,8 +647,8 @@ macro_rules! unimplemented { #[macro_export] #[stable(feature = "todo_macro", since = "1.40.0")] macro_rules! todo { - () => (panic!("not yet implemented")); - ($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+))); + () => ($crate::panic!("not yet implemented")); + ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+))); } /// Definitions of built-in macros. @@ -1215,6 +1217,8 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] + #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "assert_macro")] + #[allow_internal_unstable(core_panic)] macro_rules! assert { ($cond:expr $(,)?) => {{ /* compiler built-in */ }}; ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }}; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index cdf742057b..85e0e72008 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -156,18 +156,18 @@ pub trait StructuralPartialEq { /// Required trait for constants used in pattern matches. /// /// Any type that derives `Eq` automatically implements this trait, *regardless* -/// of whether its type-parameters implement `Eq`. +/// of whether its type parameters implement `Eq`. /// -/// This is a hack to workaround a limitation in our type-system. +/// This is a hack to work around a limitation in our type system. /// -/// Background: +/// # Background /// /// We want to require that types of consts used in pattern matches /// have the attribute `#[derive(PartialEq, Eq)]`. /// /// In a more ideal world, we could check that requirement by just checking that -/// the given type implements both (1.) the `StructuralPartialEq` trait *and* -/// (2.) the `Eq` trait. However, you can have ADTs that *do* `derive(PartialEq, Eq)`, +/// the given type implements both the `StructuralPartialEq` trait *and* +/// the `Eq` trait. However, you can have ADTs that *do* `derive(PartialEq, Eq)`, /// and be a case that we want the compiler to accept, and yet the constant's /// type fails to implement `Eq`. /// @@ -176,8 +176,11 @@ pub trait StructuralPartialEq { /// ```rust /// #[derive(PartialEq, Eq)] /// struct Wrap(X); +/// /// fn higher_order(_: &()) { } +/// /// const CFN: Wrap = Wrap(higher_order); +/// /// fn main() { /// match CFN { /// CFN => {} @@ -772,7 +775,7 @@ pub auto trait Unpin {} /// /// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default. #[stable(feature = "pin", since = "1.33.0")] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct PhantomPinned; #[stable(feature = "pin", since = "1.33.0")] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 660b7db70b..57e0bb1499 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -314,8 +314,9 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] + #[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")] #[inline(always)] - pub fn uninit_array() -> [Self; LEN] { + pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } } @@ -348,7 +349,7 @@ impl MaybeUninit { /// ```rust,no_run /// use std::mem::MaybeUninit; /// - /// enum NotZero { One = 1, Two = 2 }; + /// enum NotZero { One = 1, Two = 2 } /// /// let x = MaybeUninit::<(u8, NotZero)>::zeroed(); /// let x = unsafe { x.assume_init() }; @@ -372,8 +373,9 @@ impl MaybeUninit { /// skip running the destructor. For your convenience, this also returns a mutable /// reference to the (now safely initialized) contents of `self`. #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub fn write(&mut self, val: T) -> &mut T { + pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); // SAFETY: We just initialized this value. unsafe { self.assume_init_mut() } @@ -392,7 +394,7 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); } /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. /// let x_vec = unsafe { &*x.as_ptr() }; /// assert_eq!(x_vec.len(), 3); @@ -429,7 +431,7 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); } /// // Create a reference into the `MaybeUninit>`. /// // This is okay because we initialized it. /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; @@ -503,9 +505,10 @@ impl MaybeUninit { /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] #[rustc_diagnostic_item = "assume_init"] - pub unsafe fn assume_init(self) -> T { + pub const unsafe fn assume_init(self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { @@ -565,7 +568,7 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>>::uninit(); - /// x.write(Some(vec![0,1,2])); + /// x.write(Some(vec![0, 1, 2])); /// let x1 = unsafe { x.assume_init_read() }; /// let x2 = unsafe { x.assume_init_read() }; /// // We now created two copies of the same vector, leading to a double-free ⚠️ when @@ -666,13 +669,14 @@ impl MaybeUninit { /// } /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_ref(&self) -> &T { + pub const unsafe fn assume_init_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &*self.value + &*self.as_ptr() } } @@ -788,13 +792,14 @@ impl MaybeUninit { // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_mut(&mut self) -> &mut T { + pub const unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &mut *self.value + &mut *self.as_mut_ptr() } } @@ -810,8 +815,9 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { + pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that // `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`. // The pointer obtained is valid since it refers to memory owned by `slice` which is a @@ -831,8 +837,9 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { + pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a // mutable reference which is also guaranteed to be valid for writes. unsafe { &mut *(slice as *mut [Self] as *mut [T]) } @@ -840,15 +847,167 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } + + /// Copies the elements from `src` to `this`, returning a mutable reference to the now initalized contents of `this`. + /// + /// If `T` does not implement `Copy`, use [`write_slice_cloned`] + /// + /// This is similar to [`slice::copy_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// use std::mem::MaybeUninit; + /// + /// let mut dst = [MaybeUninit::uninit(); 32]; + /// let src = [0; 32]; + /// + /// let init = MaybeUninit::write_slice(&mut dst, &src); + /// + /// assert_eq!(init, src); + /// ``` + /// + /// ``` + /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)] + /// use std::mem::MaybeUninit; + /// + /// let mut vec = Vec::with_capacity(32); + /// let src = [0; 16]; + /// + /// MaybeUninit::write_slice(&mut vec.spare_capacity_mut()[..src.len()], &src); + /// + /// // SAFETY: we have just copied all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); + /// } + /// + /// assert_eq!(vec, src); + /// ``` + /// + /// [`write_slice_cloned`]: MaybeUninit::write_slice_cloned + /// [`slice::copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub fn write_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] + where + T: Copy, + { + // SAFETY: &[T] and &[MaybeUninit] have the same layout + let uninit_src: &[MaybeUninit] = unsafe { super::transmute(src) }; + + this.copy_from_slice(uninit_src); + + // SAFETY: Valid elements have just been copied into `this` so it is initalized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } + + /// Clones the elements from `src` to `this`, returning a mutable reference to the now initalized contents of `this`. + /// Any already initalized elements will not be dropped. + /// + /// If `T` implements `Copy`, use [`write_slice`] + /// + /// This is similar to [`slice::clone_from_slice`] but does not drop existing elements. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics. + /// + /// If there is a panic, the already cloned elements will be dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// use std::mem::MaybeUninit; + /// + /// let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + /// let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()]; + /// + /// let init = MaybeUninit::write_slice_cloned(&mut dst, &src); + /// + /// assert_eq!(init, src); + /// ``` + /// + /// ``` + /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)] + /// use std::mem::MaybeUninit; + /// + /// let mut vec = Vec::with_capacity(32); + /// let src = ["rust", "is", "a", "pretty", "cool", "language"]; + /// + /// MaybeUninit::write_slice_cloned(&mut vec.spare_capacity_mut()[..src.len()], &src); + /// + /// // SAFETY: we have just cloned all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); + /// } + /// + /// assert_eq!(vec, src); + /// ``` + /// + /// [`write_slice`]: MaybeUninit::write_slice + /// [`slice::clone_from_slice`]: ../../std/primitive.slice.html#method.clone_from_slice + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub fn write_slice_cloned<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] + where + T: Clone, + { + // unlike copy_from_slice this does not call clone_from_slice on the slice + // this is because `MaybeUninit` does not implement Clone. + + struct Guard<'a, T> { + slice: &'a mut [MaybeUninit], + initialized: usize, + } + + impl<'a, T> Drop for Guard<'a, T> { + fn drop(&mut self) { + let initialized_part = &mut self.slice[..self.initialized]; + // SAFETY: this raw slice will contain only initialized objects + // that's why, it is allowed to drop it. + unsafe { + crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); + } + } + } + + assert_eq!(this.len(), src.len(), "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // for bounds checking to be elided, and the optimizer will + // generate memcpy for simple cases (for example T = u8). + let len = this.len(); + let src = &src[..len]; + + // guard is needed b/c panic might happen during a clone + let mut guard = Guard { slice: this, initialized: 0 }; + + for i in 0..len { + guard.slice[i].write(src[i].clone()); + guard.initialized += 1; + } + + super::forget(guard); + + // SAFETY: Valid elements have just been written into `this` so it is initalized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 86e6352d13..4d876fd8c3 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -441,6 +441,32 @@ impl f32 { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(is_subnormal)] + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0_f32; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f32::NAN.is_subnormal()); + /// assert!(!f32::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[unstable(feature = "is_subnormal", issue = "79288")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[inline] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + /// Returns `true` if the number is neither zero, infinite, /// [subnormal], or `NaN`. /// @@ -935,4 +961,39 @@ impl f32 { left.cmp(&right) } + + /// Restrict a value to a certain interval unless it is NaN. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// # Panics + /// + /// Panics if `min > max`, `min` is NaN, or `max` is NaN. + /// + /// # Examples + /// + /// ``` + /// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0); + /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); + /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); + /// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "clamp", since = "1.50.0")] + #[inline] + pub fn clamp(self, min: f32, max: f32) -> f32 { + assert!(min <= max); + let mut x = self; + if x < min { + x = min; + } + if x > max { + x = max; + } + x + } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 9b1405b479..3323b7d677 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -440,6 +440,32 @@ impl f64 { self.abs_private() < Self::INFINITY } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// #![feature(is_subnormal)] + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0_f64; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f64::NAN.is_subnormal()); + /// assert!(!f64::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[unstable(feature = "is_subnormal", issue = "79288")] + #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[inline] + pub const fn is_subnormal(self) -> bool { + matches!(self.classify(), FpCategory::Subnormal) + } + /// Returns `true` if the number is neither zero, infinite, /// [subnormal], or `NaN`. /// @@ -949,4 +975,39 @@ impl f64 { left.cmp(&right) } + + /// Restrict a value to a certain interval unless it is NaN. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// # Panics + /// + /// Panics if `min > max`, `min` is NaN, or `max` is NaN. + /// + /// # Examples + /// + /// ``` + /// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0); + /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); + /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); + /// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[stable(feature = "clamp", since = "1.50.0")] + #[inline] + pub fn clamp(self, min: f64, max: f64) -> f64 { + assert!(min <= max); + let mut x = self; + if x < min { + x = min; + } + if x > max { + x = max; + } + x + } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 728381b658..2cde5d9995 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -92,6 +92,8 @@ $EndFeature, " "), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[inline] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } @@ -791,7 +793,7 @@ $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -974,7 +976,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1211,7 +1213,7 @@ any high-order bits of `rhs` that would cause the shift to exceed the bitwidth o Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. -The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, +The primitive integer types all implement a [`rotate_left`](#method.rotate_left) function, which may be what you want instead. # Examples @@ -1340,7 +1342,7 @@ assert_eq!(3i8.wrapping_pow(6), -39);", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1707,7 +1709,7 @@ assert_eq!(3i8.overflowing_pow(5), (-13, true));", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1757,7 +1759,7 @@ assert_eq!(x.pow(5), 32);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2047,8 +2049,7 @@ assert_eq!( #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -2196,8 +2197,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5a9fd902c9..716b4a90e5 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -6,6 +6,7 @@ use crate::str::FromStr; use super::from_str_radix; use super::{IntErrorKind, ParseIntError}; +use crate::intrinsics; macro_rules! doc_comment { ($x:expr, $($tt:tt)*) => { @@ -189,3 +190,76 @@ macro_rules! from_str_radix_nzint_impl { from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } + +macro_rules! nonzero_leading_trailing_zeros { + ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => { + $( + impl $Ty { + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided. + +# Examples + +Basic usage: + +``` +#![feature(nonzero_leading_trailing_zeros)] +let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap(); + +assert_eq!(n.leading_zeros(), 0); +```"), + #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero + unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 } + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided. + +# Examples + +Basic usage: + +``` +#![feature(nonzero_leading_trailing_zeros)] +let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap(); + +assert_eq!(n.trailing_zeros(), 3); +```"), + #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero + unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 } + } + } + + } + )+ + } +} + +nonzero_leading_trailing_zeros! { + NonZeroU8(u8), u8::MAX; + NonZeroU16(u16), u16::MAX; + NonZeroU32(u32), u32::MAX; + NonZeroU64(u64), u64::MAX; + NonZeroU128(u128), u128::MAX; + NonZeroUsize(usize), usize::MAX; + NonZeroI8(u8), -1i8; + NonZeroI16(u16), -1i16; + NonZeroI32(u32), -1i32; + NonZeroI64(u64), -1i64; + NonZeroI128(u128), -1i128; + NonZeroIsize(usize), -1isize; +} diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index adcbbf9143..ae8fc18a83 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -90,6 +90,8 @@ assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[inline] pub const fn count_ones(self) -> u32 { intrinsics::ctpop(self as $ActualT) as u32 @@ -749,7 +751,7 @@ Basic usage: assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -865,7 +867,7 @@ assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1159,7 +1161,7 @@ Basic usage: assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1484,7 +1486,7 @@ Basic usage: assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " ```"), #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1532,7 +1534,7 @@ Basic usage: ", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1648,7 +1650,7 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " // overflow cases it instead ends up returning the maximum value // of the type, and can return 0 for 0. #[inline] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] const fn one_less_than_next_power_of_two(self) -> Self { if self <= 1 { return 0; } @@ -1677,7 +1679,7 @@ Basic usage: assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[inline] #[rustc_inherit_overflow_checks] pub const fn next_power_of_two(self) -> Self { @@ -1703,7 +1705,7 @@ $EndFeature, " ```"), #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] pub const fn checked_next_power_of_two(self) -> Option { self.one_less_than_next_power_of_two().checked_add(1) } @@ -1728,7 +1730,7 @@ $EndFeature, " ```"), #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", reason = "needs decision on wrapping behaviour")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] pub const fn wrapping_next_power_of_two(self) -> Self { self.one_less_than_next_power_of_two().wrapping_add(1) } @@ -1805,8 +1807,7 @@ assert_eq!( #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -1954,8 +1955,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 5324dfdedd..77c9a93008 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -453,6 +453,8 @@ let n = Wrapping(0b01001100", stringify!($t), "); assert_eq!(n.count_ones(), 3); ```"), #[inline] + #[doc(alias = "popcount")] + #[doc(alias = "popcnt")] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub const fn count_ones(self) -> u32 { self.0.count_ones() diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 5ede1ba8e2..4834ca74b8 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -56,6 +56,20 @@ impl ControlFlow { ControlFlow::Break(x) => Some(x), } } + + /// Maps `ControlFlow` to `ControlFlow` by applying a function + /// to the break value in case it exists. + #[inline] + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub fn map_break(self, f: F) -> ControlFlow + where + F: FnOnce(B) -> T, + { + match self { + ControlFlow::Continue(x) => ControlFlow::Continue(x), + ControlFlow::Break(x) => ControlFlow::Break(f(x)), + } + } } impl ControlFlow { diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 3c2ada5761..a8dea4e9b4 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -79,7 +79,7 @@ pub trait Index { /// each can be indexed mutably and immutably. /// /// ``` -/// use std::ops::{Index,IndexMut}; +/// use std::ops::{Index, IndexMut}; /// /// #[derive(Debug)] /// enum Side { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 3daf26208b..1afa30f584 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1695,7 +1695,9 @@ impl Option> { /// Converts from `Option>` to `Option` /// /// # Examples + /// /// Basic usage: + /// /// ``` /// let x: Option> = Some(Some(6)); /// assert_eq!(Some(6), x.flatten()); @@ -1706,7 +1708,9 @@ impl Option> { /// let x: Option> = None; /// assert_eq!(None, x.flatten()); /// ``` - /// Flattening once only removes one level of nesting: + /// + /// Flattening only removes one level of nesting at a time: + /// /// ``` /// let x: Option>> = Some(Some(Some(6))); /// assert_eq!(Some(Some(6)), x.flatten()); diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 34a974b827..03bb849509 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -189,7 +189,7 @@ impl<'a> Location<'a> { /// # Examples /// /// ``` - /// use core::panic::Location; + /// use std::panic::Location; /// /// /// Returns the [`Location`] at which it is called. /// #[track_caller] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 09dd19b8f5..2565150251 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -52,7 +52,7 @@ pub fn panic(expr: &'static str) -> ! { #[inline] #[track_caller] -#[cfg_attr(not(bootstrap), lang = "panic_str")] // needed for const-evaluated panics +#[lang = "panic_str"] // needed for const-evaluated panics pub fn panic_str(expr: &str) -> ! { panic_fmt(format_args!("{}", expr)); } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index d09cdb44e0..8fd9ff768c 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -723,7 +723,7 @@ impl *const T { /// /// See [`ptr::read`] for safety concerns and examples. /// - /// [`ptr::read`]: ./ptr/fn.read.html + /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read(self) -> T @@ -743,7 +743,7 @@ impl *const T { /// /// See [`ptr::read_volatile`] for safety concerns and examples. /// - /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html + /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_volatile(self) -> T @@ -761,7 +761,7 @@ impl *const T { /// /// See [`ptr::read_unaligned`] for safety concerns and examples. /// - /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html + /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_unaligned(self) -> T @@ -779,7 +779,7 @@ impl *const T { /// /// See [`ptr::copy`] for safety concerns and examples. /// - /// [`ptr::copy`]: ./ptr/fn.copy.html + /// [`ptr::copy`]: crate::ptr::copy() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to(self, dest: *mut T, count: usize) @@ -797,7 +797,7 @@ impl *const T { /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 9de2758767..27d49529a5 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -16,12 +16,16 @@ //! provided at this point are very minimal: //! //! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst]. -//! * All pointers (except for the null pointer) are valid for all operations of -//! [size zero][zst]. //! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer //! be *dereferenceable*: the memory range of the given size starting at the pointer must all be //! within the bounds of a single allocated object. Note that in Rust, //! every (stack-allocated) variable is considered a separate allocated object. +//! * Even for operations of [size zero][zst], the pointer must not be pointing to deallocated +//! memory, i.e., deallocation makes pointers invalid even for zero-sized operations. However, +//! casting any non-zero integer *literal* to a pointer is valid for zero-sized accesses, even if +//! some memory happens to exist at that address and gets deallocated. This corresponds to writing +//! your own allocator: allocating zero-sized objects is not very hard. The canonical way to +//! obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`]. //! * All accesses performed by functions in this module are *non-atomic* in the sense //! of [atomic operations] used to synchronize between threads. This means it is //! undefined behavior to perform two concurrent accesses to the same location from different diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 537aa20bf1..5f94c2393a 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -830,7 +830,7 @@ impl *mut T { /// /// See [`ptr::read`] for safety concerns and examples. /// - /// [`ptr::read`]: ./ptr/fn.read.html + /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read(self) -> T @@ -850,7 +850,7 @@ impl *mut T { /// /// See [`ptr::read_volatile`] for safety concerns and examples. /// - /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html + /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_volatile(self) -> T @@ -868,7 +868,7 @@ impl *mut T { /// /// See [`ptr::read_unaligned`] for safety concerns and examples. /// - /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html + /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_unaligned(self) -> T @@ -886,7 +886,7 @@ impl *mut T { /// /// See [`ptr::copy`] for safety concerns and examples. /// - /// [`ptr::copy`]: ./ptr/fn.copy.html + /// [`ptr::copy`]: crate::ptr::copy() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to(self, dest: *mut T, count: usize) @@ -904,7 +904,7 @@ impl *mut T { /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) @@ -922,7 +922,7 @@ impl *mut T { /// /// See [`ptr::copy`] for safety concerns and examples. /// - /// [`ptr::copy`]: ./ptr/fn.copy.html + /// [`ptr::copy`]: crate::ptr::copy() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_from(self, src: *const T, count: usize) @@ -940,7 +940,7 @@ impl *mut T { /// /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// - /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html + /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) @@ -955,7 +955,7 @@ impl *mut T { /// /// See [`ptr::drop_in_place`] for safety concerns and examples. /// - /// [`ptr::drop_in_place`]: ./ptr/fn.drop_in_place.html + /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn drop_in_place(self) { @@ -968,7 +968,7 @@ impl *mut T { /// /// See [`ptr::write`] for safety concerns and examples. /// - /// [`ptr::write`]: ./ptr/fn.write.html + /// [`ptr::write`]: crate::ptr::write() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write(self, val: T) @@ -984,7 +984,7 @@ impl *mut T { /// /// See [`ptr::write_bytes`] for safety concerns and examples. /// - /// [`ptr::write_bytes`]: ./ptr/fn.write_bytes.html + /// [`ptr::write_bytes`]: crate::ptr::write_bytes() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_bytes(self, val: u8, count: usize) @@ -1004,7 +1004,7 @@ impl *mut T { /// /// See [`ptr::write_volatile`] for safety concerns and examples. /// - /// [`ptr::write_volatile`]: ./ptr/fn.write_volatile.html + /// [`ptr::write_volatile`]: crate::ptr::write_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_volatile(self, val: T) @@ -1022,7 +1022,7 @@ impl *mut T { /// /// See [`ptr::write_unaligned`] for safety concerns and examples. /// - /// [`ptr::write_unaligned`]: ./ptr/fn.write_unaligned.html + /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_unaligned(self, val: T) @@ -1038,7 +1038,7 @@ impl *mut T { /// /// See [`ptr::replace`] for safety concerns and examples. /// - /// [`ptr::replace`]: ./ptr/fn.replace.html + /// [`ptr::replace`]: crate::ptr::replace() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn replace(self, src: T) -> T @@ -1055,7 +1055,7 @@ impl *mut T { /// /// See [`ptr::swap`] for safety concerns and examples. /// - /// [`ptr::swap`]: ./ptr/fn.swap.html + /// [`ptr::swap`]: crate::ptr::swap() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn swap(self, with: *mut T) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 5dc7171a7d..d849008b88 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -439,11 +439,11 @@ impl NonNull<[T]> { /// ```rust /// #![feature(allocator_api, ptr_as_uninit)] /// - /// use std::alloc::{AllocRef, Layout, Global}; + /// use std::alloc::{Allocator, Layout, Global}; /// use std::mem::MaybeUninit; /// use std::ptr::NonNull; /// - /// let memory: NonNull<[u8]> = Global.alloc(Layout::new::<[u8; 32]>())?; + /// let memory: NonNull<[u8]> = Global.allocate(Layout::new::<[u8; 32]>())?; /// // This is safe as `memory` is valid for reads and writes for `memory.len()` many bytes. /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized. /// # #[allow(unused_variables)] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index b6d9f13d88..0b4ca2b721 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1184,7 +1184,9 @@ impl Result, E> { /// Converts from `Result, E>` to `Result` /// /// # Examples + /// /// Basic usage: + /// /// ``` /// #![feature(result_flattening)] /// let x: Result, u32> = Ok(Ok("hello")); @@ -1197,7 +1199,7 @@ impl Result, E> { /// assert_eq!(Err(6), x.flatten()); /// ``` /// - /// Flattening once only removes one level of nesting: + /// Flattening only removes one level of nesting at a time: /// /// ``` /// #![feature(result_flattening)] diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index 0c0f175026..08077c700d 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -1,8 +1,6 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch -// ignore-tidy-undocumented-unsafe - use crate::cmp; use crate::mem; @@ -72,6 +70,8 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option { // search the body of the text let repeated_x = repeat_byte(x); while offset <= len - 2 * USIZE_BYTES { + // SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes + // between the offset and the end of the slice. unsafe { let u = *(ptr.add(offset) as *const usize); let v = *(ptr.add(offset + USIZE_BYTES) as *const usize); @@ -105,6 +105,8 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { let (min_aligned_offset, max_aligned_offset) = { // We call this just to obtain the length of the prefix and suffix. // In the middle we always process two chunks at once. + // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size differences + // which are handled by `align_to`. let (prefix, _, suffix) = unsafe { text.align_to::<(Chunk, Chunk)>() }; (prefix.len(), len - suffix.len()) }; @@ -121,6 +123,8 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { let chunk_bytes = mem::size_of::(); while offset > min_aligned_offset { + // SAFETY: offset starts at len - suffix.len(), as long as it is greater than + // min_aligned_offset (prefix.len()) the remaining distance is at least 2 * chunk_bytes. unsafe { let u = *(ptr.offset(offset as isize - 2 * chunk_bytes as isize) as *const Chunk); let v = *(ptr.offset(offset as isize - chunk_bytes as isize) as *const Chunk); diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 79ae1d5829..f5af48e0dd 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -88,8 +88,7 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_union))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_union))] + #[rustc_allow_const_fn_unstable(const_fn_union)] pub const fn len(&self) -> usize { // SAFETY: this is safe because `&[T]` and `FatPtr` have the same layout. // Only `std` can make this guarantee. @@ -605,8 +604,9 @@ impl [T] { // many bytes away from the end of `self`. // - Any initialized memory is valid `usize`. unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let ptr = self.as_mut_ptr(); + let pa = ptr.add(i); + let pb = ptr.add(ln - i - chunk); let va = ptr::read_unaligned(pa as *mut usize); let vb = ptr::read_unaligned(pb as *mut usize); ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); @@ -635,8 +635,9 @@ impl [T] { // always respected, ensuring the `pb` pointer can be used // safely. unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let ptr = self.as_mut_ptr(); + let pa = ptr.add(i); + let pb = ptr.add(ln - i - chunk); let va = ptr::read_unaligned(pa as *mut u32); let vb = ptr::read_unaligned(pb as *mut u32); ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); @@ -654,8 +655,9 @@ impl [T] { // aligned, and can be read from and written to. unsafe { // Unsafe swap to avoid the bounds check in safe swap. - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - 1); + let ptr = self.as_mut_ptr(); + let pa = ptr.add(i); + let pb = ptr.add(ln - i - 1); ptr::swap(pa, pb); } i += 1; @@ -1958,10 +1960,10 @@ impl [T] { /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), /// (1, 21), (2, 34), (4, 55)]; /// - /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); - /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); - /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); - /// let r = s.binary_search_by_key(&1, |&(a,b)| b); + /// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a, b)| b); /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] @@ -2579,13 +2581,12 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_fill)] - /// /// let mut buf = vec![0; 10]; /// buf.fill(1); /// assert_eq!(buf, vec![1; 10]); /// ``` - #[unstable(feature = "slice_fill", issue = "70758")] + #[doc(alias = "memset")] + #[stable(feature = "slice_fill", since = "1.50.0")] pub fn fill(&mut self, value: T) where T: Clone, @@ -2599,6 +2600,34 @@ impl [T] { } } + /// Fills `self` with elements returned by calling a closure repeatedly. + /// + /// This method uses a closure to create new values. If you'd rather + /// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`] + /// trait to generate values, you can pass [`Default::default`] as the + /// argument. + /// + /// [`fill`]: #method.fill + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_fill_with)] + /// + /// let mut buf = vec![1; 10]; + /// buf.fill_with(Default::default); + /// assert_eq!(buf, vec![0; 10]); + /// ``` + #[unstable(feature = "slice_fill_with", issue = "79221")] + pub fn fill_with(&mut self, mut f: F) + where + F: FnMut() -> T, + { + for el in self { + *el = f(); + } + } + /// Copies the elements from `src` into `self`. /// /// The length of `src` must be the same as `self`. @@ -2724,6 +2753,7 @@ impl [T] { /// /// [`clone_from_slice`]: #method.clone_from_slice /// [`split_at_mut`]: #method.split_at_mut + #[doc(alias = "memcpy")] #[stable(feature = "copy_from_slice", since = "1.9.0")] pub fn copy_from_slice(&mut self, src: &[T]) where diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 952d0598a7..73316433e0 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -157,8 +157,7 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")] -#[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] -#[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] +#[rustc_allow_const_fn_unstable(const_fn_transmute)] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 23d63a4787..83cf47c8c8 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -219,8 +219,7 @@ impl str { #[rustc_const_stable(feature = "str_as_bytes", since = "1.32.0")] #[inline(always)] #[allow(unused_attributes)] - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] pub const fn as_bytes(&self) -> &[u8] { // SAFETY: const sound because we transmute two types with the same layout unsafe { mem::transmute(self) } @@ -1132,6 +1131,13 @@ impl str { /// assert_eq!(v, ["lion", "tiger", "leopard"]); /// ``` /// + /// If the pattern is a slice of chars, split on each occurrence of any of the characters: + /// + /// ``` + /// let v: Vec<&str> = "2020-11-03 23:59".split(&['-', ' ', ':', '@'][..]).collect(); + /// assert_eq!(v, ["2020", "11", "03", "23", "59"]); + /// ``` + /// /// A more complex pattern, using a closure: /// /// ``` @@ -2253,9 +2259,9 @@ impl str { /// but non-ASCII letters are unchanged. /// /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. + /// [`to_ascii_uppercase()`]. /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase /// /// # Examples /// @@ -2280,9 +2286,9 @@ impl str { /// but non-ASCII letters are unchanged. /// /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. + /// [`to_ascii_lowercase()`]. /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase /// /// # Examples /// diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 10cf1e172e..373a821242 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -125,7 +125,7 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let old_offset = index; macro_rules! err { ($error_len: expr) => { - return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len }); + return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len }) }; } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index d48c02bf59..36857979af 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -47,9 +47,16 @@ //! //! * PowerPC and MIPS platforms with 32-bit pointers do not have `AtomicU64` or //! `AtomicI64` types. -//! * ARM platforms like `armv5te` that aren't for Linux do not have any atomics -//! at all. -//! * ARM targets with `thumbv6m` do not have atomic operations at all. +//! * ARM platforms like `armv5te` that aren't for Linux only provide `load` +//! and `store` operations, and do not support Compare and Swap (CAS) +//! operations, such as `swap`, `fetch_add`, etc. Additionally on Linux, +//! these CAS operations are implemented via [operating system support], which +//! may come with a performance penalty. +//! * ARM targets with `thumbv6m` only provide `load` and `store` operations, +//! and do not support Compare and Swap (CAS) operations, such as `swap`, +//! `fetch_add`, etc. +//! +//! [operating system support]: https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt //! //! Note that future platforms may be added that also do not have support for //! some atomic operations. Maximally portable code will want to be careful @@ -457,6 +464,23 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// + /// # Migrating to `compare_exchange` and `compare_exchange_weak` + /// + /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for + /// memory orderings: + /// + /// Original | Success | Failure + /// -------- | ------- | ------- + /// Relaxed | Relaxed | Relaxed + /// Acquire | Acquire | Acquire + /// Release | Release | Relaxed + /// AcqRel | AcqRel | Acquire + /// SeqCst | SeqCst | SeqCst + /// + /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, + /// which allows the compiler to generate better assembly code when the compare and swap + /// is used in a loop. + /// /// # Examples /// /// ``` @@ -472,6 +496,10 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated( + since = "1.50.0", + reason = "Use `compare_exchange` or `compare_exchange_weak` instead" + )] #[cfg(target_has_atomic = "8")] pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { @@ -486,9 +514,10 @@ impl AtomicBool { /// the previous value. On success this value is guaranteed to be equal to `current`. /// /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -518,6 +547,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] pub fn compare_exchange( &self, @@ -543,9 +573,10 @@ impl AtomicBool { /// previous value. /// /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -571,6 +602,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[doc(alias = "compare_and_swap")] #[cfg(target_has_atomic = "8")] pub fn compare_exchange_weak( &self, @@ -959,8 +991,16 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn load(&self, order: Ordering) -> *mut T { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_load(self.p.get(), order) + } + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_load(self.p.get() as *mut usize, order) as *mut T } + unsafe { + atomic_load(self.p.get() as *mut usize, order) as *mut T + } } /// Stores a value into the pointer. @@ -987,6 +1027,12 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, ptr: *mut T, order: Ordering) { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_store(self.p.get(), ptr, order); + } + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_store(self.p.get() as *mut usize, ptr as usize, order); @@ -1019,8 +1065,16 @@ impl AtomicPtr { #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_has_atomic = "ptr")] pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { + #[cfg(bootstrap)] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T + } + #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T } + unsafe { + atomic_swap(self.p.get(), ptr, order) + } } /// Stores a value into the pointer if the current value is the same as the `current` value. @@ -1037,6 +1091,23 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// + /// # Migrating to `compare_exchange` and `compare_exchange_weak` + /// + /// `compare_and_swap` is equivalent to `compare_exchange` with the following mapping for + /// memory orderings: + /// + /// Original | Success | Failure + /// -------- | ------- | ------- + /// Relaxed | Relaxed | Relaxed + /// Acquire | Acquire | Acquire + /// Release | Release | Relaxed + /// AcqRel | AcqRel | Acquire + /// SeqCst | SeqCst | SeqCst + /// + /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, + /// which allows the compiler to generate better assembly code when the compare and swap + /// is used in a loop. + /// /// # Examples /// /// ``` @@ -1051,6 +1122,10 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated( + since = "1.50.0", + reason = "Use `compare_exchange` or `compare_exchange_weak` instead" + )] #[cfg(target_has_atomic = "ptr")] pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { @@ -1065,9 +1140,10 @@ impl AtomicPtr { /// the previous value. On success this value is guaranteed to be equal to `current`. /// /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -1098,6 +1174,7 @@ impl AtomicPtr { success: Ordering, failure: Ordering, ) -> Result<*mut T, *mut T> { + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. unsafe { let res = atomic_compare_exchange( @@ -1112,6 +1189,11 @@ impl AtomicPtr { Err(x) => Err(x as *mut T), } } + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_compare_exchange(self.p.get(), current, new, success, failure) + } } /// Stores a value into the pointer if the current value is the same as the `current` value. @@ -1122,9 +1204,10 @@ impl AtomicPtr { /// previous value. /// /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. Using [`Acquire`] as success ordering makes the store part + /// ordering of this operation. `success` describes the required ordering for the + /// read-modify-write operation that takes place if the comparison with `current` succeeds. + /// `failure` describes the required ordering for the load operation that takes place when + /// the comparison fails. Using [`Acquire`] as success ordering makes the store part /// of this operation [`Relaxed`], and using [`Release`] makes the successful load /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] /// and must be equivalent to or weaker than the success ordering. @@ -1158,6 +1241,7 @@ impl AtomicPtr { success: Ordering, failure: Ordering, ) -> Result<*mut T, *mut T> { + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. unsafe { let res = atomic_compare_exchange_weak( @@ -1172,6 +1256,14 @@ impl AtomicPtr { Err(x) => Err(x as *mut T), } } + #[cfg(not(bootstrap))] + // SAFETY: This intrinsic is unsafe because it operates on a raw pointer + // but we know for sure that the pointer is valid (we just got it from + // an `UnsafeCell` that we have by reference) and the atomic operation + // itself allows us to safely mutate the `UnsafeCell` contents. + unsafe { + atomic_compare_exchange_weak(self.p.get(), current, new, success, failure) + } } /// Fetches the value, and applies a function to it that returns an optional @@ -1560,6 +1652,23 @@ happens, and using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). +# Migrating to `compare_exchange` and `compare_exchange_weak` + +`compare_and_swap` is equivalent to `compare_exchange` with the following mapping for +memory orderings: + +Original | Success | Failure +-------- | ------- | ------- +Relaxed | Relaxed | Relaxed +Acquire | Acquire | Acquire +Release | Release | Relaxed +AcqRel | AcqRel | Acquire +SeqCst | SeqCst | SeqCst + +`compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, +which allows the compiler to generate better assembly code when the compare and swap +is used in a loop. + # Examples ``` @@ -1575,6 +1684,10 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable] + #[rustc_deprecated( + since = "1.50.0", + reason = "Use `compare_exchange` or `compare_exchange_weak` instead") + ] #[$cfg_cas] pub fn compare_and_swap(&self, current: $int_type, @@ -1599,9 +1712,10 @@ containing the previous value. On success this value is guaranteed to be equal t `current`. `compare_exchange` takes two [`Ordering`] arguments to describe the memory -ordering of this operation. The first describes the required ordering if the -operation succeeds while the second describes the required ordering when the -operation fails. Using [`Acquire`] as success ordering makes the store part +ordering of this operation. `success` describes the required ordering for the +read-modify-write operation that takes place if the comparison with `current` succeeds. +`failure` describes the required ordering for the load operation that takes place when +the comparison fails. Using [`Acquire`] as success ordering makes the store part of this operation [`Relaxed`], and using [`Release`] makes the successful load [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the success ordering. @@ -1651,9 +1765,10 @@ platforms. The return value is a result indicating whether the new value was written and containing the previous value. `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory -ordering of this operation. The first describes the required ordering if the -operation succeeds while the second describes the required ordering when the -operation fails. Using [`Acquire`] as success ordering makes the store part +ordering of this operation. `success` describes the required ordering for the +read-modify-write operation that takes place if the comparison with `current` succeeds. +`failure` describes the required ordering for the load operation that takes place when +the comparison fails. Using [`Acquire`] as success ordering makes the store part of this operation [`Relaxed`], and using [`Release`] makes the successful load [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the success ordering. diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index e221aaf3fd..cbf6990001 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,15 +1,18 @@ -/// Extracts the successful type of a `Poll`. +/// Extracts the successful type of a [`Poll`]. /// -/// This macro bakes in propagation of `Pending` signals by returning early. +/// This macro bakes in propagation of [`Pending`] signals by returning early. +/// +/// [`Poll`]: crate::task::Poll +/// [`Pending`]: crate::task::Poll::Pending /// /// # Examples /// /// ``` /// #![feature(ready_macro)] /// -/// use core::task::{ready, Context, Poll}; -/// use core::future::{self, Future}; -/// use core::pin::Pin; +/// use std::task::{ready, Context, Poll}; +/// use std::future::{self, Future}; +/// use std::pin::Pin; /// /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// let mut fut = future::ready(42); @@ -28,9 +31,9 @@ /// ``` /// # #![feature(ready_macro)] /// # -/// # use core::task::{Context, Poll}; -/// # use core::future::{self, Future}; -/// # use core::pin::Pin; +/// # use std::task::{Context, Poll}; +/// # use std::future::{self, Future}; +/// # use std::pin::Pin; /// # /// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// # let mut fut = future::ready(42); diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index d3c0d9b784..b775e022a5 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -130,8 +130,7 @@ impl RawWakerVTable { #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_fn_ptr_basics))] + #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] pub const fn new( clone: unsafe fn(*const ()) -> RawWaker, wake: unsafe fn(*const ()), diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index 28c07f7717..37ca0a0779 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -18,17 +18,14 @@ mod unicode_data; pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION; // For use in liballoc, not re-exported in libstd. -pub mod derived_property { - pub use super::{Case_Ignorable, Cased}; -} +pub use unicode_data::{ + case_ignorable::lookup as Case_Ignorable, cased::lookup as Cased, conversions, +}; -pub use unicode_data::alphabetic::lookup as Alphabetic; -pub use unicode_data::case_ignorable::lookup as Case_Ignorable; -pub use unicode_data::cased::lookup as Cased; -pub use unicode_data::cc::lookup as Cc; -pub use unicode_data::conversions; -pub use unicode_data::grapheme_extend::lookup as Grapheme_Extend; -pub use unicode_data::lowercase::lookup as Lowercase; -pub use unicode_data::n::lookup as N; -pub use unicode_data::uppercase::lookup as Uppercase; -pub use unicode_data::white_space::lookup as White_Space; +pub(crate) use unicode_data::alphabetic::lookup as Alphabetic; +pub(crate) use unicode_data::cc::lookup as Cc; +pub(crate) use unicode_data::grapheme_extend::lookup as Grapheme_Extend; +pub(crate) use unicode_data::lowercase::lookup as Lowercase; +pub(crate) use unicode_data::n::lookup as N; +pub(crate) use unicode_data::uppercase::lookup as Uppercase; +pub(crate) use unicode_data::white_space::lookup as White_Space; diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 3244bbc2d6..66c25e449d 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -408,3 +408,56 @@ fn ascii_const() { const BYTE_IS_ASCII: bool = 97u8.is_ascii(); assert!(BYTE_IS_ASCII); } + +#[test] +fn ascii_ctype_const() { + macro_rules! suite { + ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { + $( + mod $fn { + const CHAR_A_LOWER: bool = 'a'.$fn(); + const CHAR_A_UPPER: bool = 'A'.$fn(); + const CHAR_NINE: bool = '9'.$fn(); + const CHAR_DOT: bool = '.'.$fn(); + const CHAR_SPACE: bool = ' '.$fn(); + + const U8_A_LOWER: bool = b'a'.$fn(); + const U8_A_UPPER: bool = b'A'.$fn(); + const U8_NINE: bool = b'9'.$fn(); + const U8_DOT: bool = b'.'.$fn(); + const U8_SPACE: bool = b' '.$fn(); + + pub fn run() { + assert_eq!(CHAR_A_LOWER, $a); + assert_eq!(CHAR_A_UPPER, $A); + assert_eq!(CHAR_NINE, $nine); + assert_eq!(CHAR_DOT, $dot); + assert_eq!(CHAR_SPACE, $space); + + assert_eq!(U8_A_LOWER, $a); + assert_eq!(U8_A_UPPER, $A); + assert_eq!(U8_NINE, $nine); + assert_eq!(U8_DOT, $dot); + assert_eq!(U8_SPACE, $space); + } + } + )* + + $( $fn::run(); )* + } + } + + suite! { + // 'a' 'A' '9' '.' ' ' + is_ascii_alphabetic => [true, true, false, false, false]; + is_ascii_uppercase => [false, true, false, false, false]; + is_ascii_lowercase => [true, false, false, false, false]; + is_ascii_alphanumeric => [true, true, true, false, false]; + is_ascii_digit => [false, false, true, false, false]; + is_ascii_hexdigit => [true, true, true, false, false]; + is_ascii_punctuation => [false, false, false, true, false]; + is_ascii_graphic => [true, true, true, true, false]; + is_ascii_whitespace => [false, false, false, false, true]; + is_ascii_control => [false, false, false, false, false]; + } +} diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index acbd913982..2d1e4496ae 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -4,11 +4,11 @@ use core::sync::atomic::*; #[test] fn bool_() { let a = AtomicBool::new(false); - assert_eq!(a.compare_and_swap(false, true, SeqCst), false); - assert_eq!(a.compare_and_swap(false, true, SeqCst), true); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Err(true)); a.store(false, SeqCst); - assert_eq!(a.compare_and_swap(false, true, SeqCst), false); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); } #[test] @@ -101,3 +101,82 @@ fn static_init() { assert!(S_INT.fetch_add(1, SeqCst) == 0); assert!(S_UINT.fetch_add(1, SeqCst) == 0); } + +#[test] +fn atomic_access_bool() { + static mut ATOMIC: AtomicBool = AtomicBool::new(false); + + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} + +#[test] +fn atomic_alignment() { + use std::mem::{align_of, size_of}; + + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::>(), size_of::>()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); +} + +#[test] +fn atomic_compare_exchange() { + use Ordering::*; + + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + + ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); + ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); +} diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs index e89eb2c7f9..e40f0482ae 100644 --- a/library/core/tests/bool.rs +++ b/library/core/tests/bool.rs @@ -1,3 +1,87 @@ +use core::cmp::Ordering::{Equal, Greater, Less}; +use core::ops::{BitAnd, BitOr, BitXor}; + +#[test] +fn test_bool() { + assert_eq!(false.eq(&true), false); + assert_eq!(false == false, true); + assert_eq!(false != true, true); + assert_eq!(false.ne(&false), false); + + assert_eq!(false.bitand(false), false); + assert_eq!(true.bitand(false), false); + assert_eq!(false.bitand(true), false); + assert_eq!(true.bitand(true), true); + + assert_eq!(false & false, false); + assert_eq!(true & false, false); + assert_eq!(false & true, false); + assert_eq!(true & true, true); + + assert_eq!(false.bitor(false), false); + assert_eq!(true.bitor(false), true); + assert_eq!(false.bitor(true), true); + assert_eq!(true.bitor(true), true); + + assert_eq!(false | false, false); + assert_eq!(true | false, true); + assert_eq!(false | true, true); + assert_eq!(true | true, true); + + assert_eq!(false.bitxor(false), false); + assert_eq!(true.bitxor(false), true); + assert_eq!(false.bitxor(true), true); + assert_eq!(true.bitxor(true), false); + + assert_eq!(false ^ false, false); + assert_eq!(true ^ false, true); + assert_eq!(false ^ true, true); + assert_eq!(true ^ true, false); + + assert_eq!(!true, false); + assert_eq!(!false, true); + + let s = false.to_string(); + assert_eq!(s, "false"); + let s = true.to_string(); + assert_eq!(s, "true"); + + assert!(true > false); + assert!(!(false > true)); + + assert!(false < true); + assert!(!(true < false)); + + assert!(false <= false); + assert!(false >= false); + assert!(true <= true); + assert!(true >= true); + + assert!(false <= true); + assert!(!(false >= true)); + assert!(true >= false); + assert!(!(true <= false)); + + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); +} + +#[test] +pub fn test_bool_not() { + if !false { + assert!((true)); + } else { + assert!((false)); + } + if !true { + assert!((false)); + } else { + assert!((true)); + } +} + #[test] fn test_bool_to_option() { assert_eq!(false.then_some(0), None); diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 835289daf7..11cf7add07 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -132,3 +132,74 @@ fn ordering_const() { const THEN: Ordering = Equal.then(ORDERING); assert_eq!(THEN, Greater); } + +#[test] +fn cmp_default() { + // Test default methods in PartialOrd and PartialEq + + #[derive(Debug)] + struct Fool(bool); + + impl PartialEq for Fool { + fn eq(&self, other: &Fool) -> bool { + let Fool(this) = *self; + let Fool(other) = *other; + this != other + } + } + + struct Int(isize); + + impl PartialEq for Int { + fn eq(&self, other: &Int) -> bool { + let Int(this) = *self; + let Int(other) = *other; + this == other + } + } + + impl PartialOrd for Int { + fn partial_cmp(&self, other: &Int) -> Option { + let Int(this) = *self; + let Int(other) = *other; + this.partial_cmp(&other) + } + } + + struct RevInt(isize); + + impl PartialEq for RevInt { + fn eq(&self, other: &RevInt) -> bool { + let RevInt(this) = *self; + let RevInt(other) = *other; + this == other + } + } + + impl PartialOrd for RevInt { + fn partial_cmp(&self, other: &RevInt) -> Option { + let RevInt(this) = *self; + let RevInt(other) = *other; + other.partial_cmp(&this) + } + } + + assert!(Int(2) > Int(1)); + assert!(Int(2) >= Int(1)); + assert!(Int(1) >= Int(1)); + assert!(Int(1) < Int(2)); + assert!(Int(1) <= Int(2)); + assert!(Int(1) <= Int(1)); + + assert!(RevInt(2) < RevInt(1)); + assert!(RevInt(2) <= RevInt(1)); + assert!(RevInt(1) <= RevInt(1)); + assert!(RevInt(1) > RevInt(2)); + assert!(RevInt(1) >= RevInt(2)); + assert!(RevInt(1) >= RevInt(1)); + + assert_eq!(Fool(true), Fool(false)); + assert!(Fool(true) != Fool(true)); + assert!(Fool(false) != Fool(false)); + assert_eq!(Fool(false), Fool(true)); +} diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 75ca897cad..ec4b49da38 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -1134,6 +1134,17 @@ fn test_iterator_peekable_next_if_eq() { assert_eq!(it.next_if_eq(""), None); } +#[test] +fn test_iterator_peekable_mut() { + let mut it = vec![1, 2, 3].into_iter().peekable(); + if let Some(p) = it.peek_mut() { + if *p == 1 { + *p = 5; + } + } + assert_eq!(it.collect::>(), vec![5, 2, 3]); +} + /// This is an iterator that follows the Iterator contract, /// but it is not fused. After having returned None once, it will start /// producing elements if .next() is called again. @@ -3482,3 +3493,15 @@ fn test_flatten_non_fused_inner() { assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), None); } + +#[test] +pub fn extend_for_unit() { + let mut x = 0; + { + let iter = (0..5).map(|_| { + x += 1; + }); + ().extend(iter); + } + assert_eq!(x, 5); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c9f9b890c3..2828235c3e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,8 +8,11 @@ #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(cfg_panic)] +#![feature(cfg_target_has_atomic)] #![feature(const_assume)] #![feature(const_cell_into_inner)] +#![feature(const_maybe_uninit_assume_init)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -31,6 +34,7 @@ #![feature(raw)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] +#![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(step_trait)] #![feature(step_trait_ext)] @@ -56,10 +60,14 @@ #![feature(unwrap_infallible)] #![feature(option_unwrap_none)] #![feature(peekable_next_if)] +#![feature(peekable_peek_mut)] #![feature(partition_point)] #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] #![feature(int_bits_const)] +#![feature(nonzero_leading_trailing_zeros)] +#![feature(const_option)] +#![feature(integer_atomics)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; @@ -79,6 +87,7 @@ mod hash; mod intrinsics; mod iter; mod lazy; +mod macros; mod manually_drop; mod mem; mod nonzero; @@ -95,3 +104,4 @@ mod str_lossy; mod task; mod time; mod tuple; +mod unicode; diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs new file mode 100644 index 0000000000..482f3c1c99 --- /dev/null +++ b/library/core/tests/macros.rs @@ -0,0 +1,14 @@ +#[test] +fn assert_eq_trailing_comma() { + assert_eq!(1, 1,); +} + +#[test] +fn assert_escape() { + assert!(r#"☃\backslash"#.contains("\\")); +} + +#[test] +fn assert_ne_trailing_comma() { + assert_ne!(1, 2,); +} diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 59588d9778..5d0fedd4d9 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -1,5 +1,8 @@ use core::mem::*; +#[cfg(panic = "unwind")] +use std::rc::Rc; + #[test] fn size_of_basic() { assert_eq!(size_of::(), 1); @@ -129,3 +132,138 @@ fn test_discriminant_send_sync() { is_send_sync::>(); is_send_sync::>(); } + +#[test] +#[cfg(not(bootstrap))] +fn assume_init_good() { + const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; + + assert!(TRUE); +} + +#[test] +fn uninit_write_slice() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + assert_eq!(MaybeUninit::write_slice(&mut dst, &src), &src); +} + +#[test] +#[should_panic(expected = "source slice length (32) does not match destination slice length (64)")] +fn uninit_write_slice_panic_lt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 32]; + + MaybeUninit::write_slice(&mut dst, &src); +} + +#[test] +#[should_panic(expected = "source slice length (128) does not match destination slice length (64)")] +fn uninit_write_slice_panic_gt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 128]; + + MaybeUninit::write_slice(&mut dst, &src); +} + +#[test] +fn uninit_clone_from_slice() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + assert_eq!(MaybeUninit::write_slice_cloned(&mut dst, &src), &src); +} + +#[test] +#[should_panic(expected = "destination and source slices have different lengths")] +fn uninit_write_slice_cloned_panic_lt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 32]; + + MaybeUninit::write_slice_cloned(&mut dst, &src); +} + +#[test] +#[should_panic(expected = "destination and source slices have different lengths")] +fn uninit_write_slice_cloned_panic_gt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 128]; + + MaybeUninit::write_slice_cloned(&mut dst, &src); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_write_slice_cloned_mid_panic() { + use std::panic; + + enum IncrementOrPanic { + Increment(Rc<()>), + ExpectedPanic, + UnexpectedPanic, + } + + impl Clone for IncrementOrPanic { + fn clone(&self) -> Self { + match self { + Self::Increment(rc) => Self::Increment(rc.clone()), + Self::ExpectedPanic => panic!("expected panic on clone"), + Self::UnexpectedPanic => panic!("unexpected panic on clone"), + } + } + } + + let rc = Rc::new(()); + + let mut dst = [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + + let src = [ + IncrementOrPanic::Increment(rc.clone()), + IncrementOrPanic::Increment(rc.clone()), + IncrementOrPanic::ExpectedPanic, + IncrementOrPanic::UnexpectedPanic, + ]; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::write_slice_cloned(&mut dst, &src); + })); + + drop(src); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +fn uninit_write_slice_cloned_no_drop() { + #[derive(Clone)] + struct Bomb; + + impl Drop for Bomb { + fn drop(&mut self) { + panic!("dropped a bomb! kaboom") + } + } + + let mut dst = [MaybeUninit::uninit()]; + let src = [Bomb]; + + MaybeUninit::write_slice_cloned(&mut dst, &src); + + forget(src); +} diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index fb1293c99b..b66c482c5e 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -1,5 +1,8 @@ use core::convert::TryFrom; -use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8}; +use core::num::{ + IntErrorKind, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, + NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, +}; use core::option::Option::{self, None, Some}; use std::mem::size_of; @@ -82,7 +85,7 @@ fn test_match_option_string() { let five = "Five".to_string(); match Some(five) { Some(s) => assert_eq!(s, "Five"), - None => panic!("unexpected None while matching on Some(String { ... })"), + None => panic!("{}", "unexpected None while matching on Some(String { ... })"), } } @@ -212,3 +215,100 @@ fn nonzero_const() { const ONE: Option = NonZeroU8::new(1); assert!(ONE.is_some()); } + +#[test] +fn nonzero_leading_zeros() { + assert_eq!(NonZeroU8::new(1).unwrap().leading_zeros(), 7); + assert_eq!(NonZeroI8::new(1).unwrap().leading_zeros(), 7); + assert_eq!(NonZeroU16::new(1).unwrap().leading_zeros(), 15); + assert_eq!(NonZeroI16::new(1).unwrap().leading_zeros(), 15); + assert_eq!(NonZeroU32::new(1).unwrap().leading_zeros(), 31); + assert_eq!(NonZeroI32::new(1).unwrap().leading_zeros(), 31); + assert_eq!(NonZeroU64::new(1).unwrap().leading_zeros(), 63); + assert_eq!(NonZeroI64::new(1).unwrap().leading_zeros(), 63); + assert_eq!(NonZeroU128::new(1).unwrap().leading_zeros(), 127); + assert_eq!(NonZeroI128::new(1).unwrap().leading_zeros(), 127); + assert_eq!(NonZeroUsize::new(1).unwrap().leading_zeros(), usize::BITS - 1); + assert_eq!(NonZeroIsize::new(1).unwrap().leading_zeros(), usize::BITS - 1); + + assert_eq!(NonZeroU8::new(u8::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI8::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU16::new(u16::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI16::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU32::new(u32::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI32::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU64::new(u64::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI64::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU128::new(u128::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI128::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroUsize::new(usize::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroIsize::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2); + + assert_eq!(NonZeroU8::new(u8::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI8::new(-1i8).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU16::new(u16::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI16::new(-1i16).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU32::new(u32::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI32::new(-1i32).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU64::new(u64::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI64::new(-1i64).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU128::new(u128::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI128::new(-1i128).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroUsize::new(usize::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroIsize::new(-1isize).unwrap().leading_zeros(), 0); + + const LEADING_ZEROS: u32 = NonZeroU16::new(1).unwrap().leading_zeros(); + assert_eq!(LEADING_ZEROS, 15); +} + +#[test] +fn nonzero_trailing_zeros() { + assert_eq!(NonZeroU8::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI8::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU16::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI16::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU32::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI32::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU64::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI64::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU128::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI128::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroUsize::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroIsize::new(1).unwrap().trailing_zeros(), 0); + + assert_eq!(NonZeroU8::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI8::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU16::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI16::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU32::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI32::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU64::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI64::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU128::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI128::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroUsize::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroIsize::new(1 << 2).unwrap().trailing_zeros(), 2); + + assert_eq!(NonZeroU8::new(1 << 7).unwrap().trailing_zeros(), 7); + assert_eq!(NonZeroI8::new(1 << 7).unwrap().trailing_zeros(), 7); + assert_eq!(NonZeroU16::new(1 << 15).unwrap().trailing_zeros(), 15); + assert_eq!(NonZeroI16::new(1 << 15).unwrap().trailing_zeros(), 15); + assert_eq!(NonZeroU32::new(1 << 31).unwrap().trailing_zeros(), 31); + assert_eq!(NonZeroI32::new(1 << 31).unwrap().trailing_zeros(), 31); + assert_eq!(NonZeroU64::new(1 << 63).unwrap().trailing_zeros(), 63); + assert_eq!(NonZeroI64::new(1 << 63).unwrap().trailing_zeros(), 63); + assert_eq!(NonZeroU128::new(1 << 127).unwrap().trailing_zeros(), 127); + assert_eq!(NonZeroI128::new(1 << 127).unwrap().trailing_zeros(), 127); + + assert_eq!( + NonZeroUsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), + usize::BITS - 1 + ); + assert_eq!( + NonZeroIsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), + usize::BITS - 1 + ); + + const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros(); + assert_eq!(TRAILING_ZEROS, 2); +} diff --git a/library/core/tests/num/i128.rs b/library/core/tests/num/i128.rs new file mode 100644 index 0000000000..72c0b22599 --- /dev/null +++ b/library/core/tests/num/i128.rs @@ -0,0 +1 @@ +int_module!(i128, i128); diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index fcb0d6031b..90c4765678 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -131,9 +131,9 @@ macro_rules! int_module { assert_eq!(B.rotate_left(0), B); assert_eq!(C.rotate_left(0), C); // Rotating by a multiple of word size should also have no effect - assert_eq!(A.rotate_left(64), A); - assert_eq!(B.rotate_left(64), B); - assert_eq!(C.rotate_left(64), C); + assert_eq!(A.rotate_left(128), A); + assert_eq!(B.rotate_left(128), B); + assert_eq!(C.rotate_left(128), C); } #[test] diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 49e5cc0eaa..012ab4ea5c 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -11,6 +11,7 @@ use core::str::FromStr; #[macro_use] mod int_macros; +mod i128; mod i16; mod i32; mod i64; @@ -19,6 +20,7 @@ mod i8; #[macro_use] mod uint_macros; +mod u128; mod u16; mod u32; mod u64; diff --git a/library/core/tests/num/nan.rs b/library/core/tests/num/nan.rs index 011ffa790b..ef81988c96 100644 --- a/library/core/tests/num/nan.rs +++ b/library/core/tests/num/nan.rs @@ -1,6 +1,5 @@ #[test] fn test_nan() { - use core::f64; let x = "NaN".to_string(); assert_eq!(format!("{}", f64::NAN), x); assert_eq!(format!("{:e}", f64::NAN), x); diff --git a/library/core/tests/num/u128.rs b/library/core/tests/num/u128.rs new file mode 100644 index 0000000000..716d1836f2 --- /dev/null +++ b/library/core/tests/num/u128.rs @@ -0,0 +1 @@ +uint_module!(u128, u128); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 952ec188dc..445f8fb350 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -96,9 +96,9 @@ macro_rules! uint_module { assert_eq!(B.rotate_left(0), B); assert_eq!(C.rotate_left(0), C); // Rotating by a multiple of word size should also have no effect - assert_eq!(A.rotate_left(64), A); - assert_eq!(B.rotate_left(64), B); - assert_eq!(C.rotate_left(64), C); + assert_eq!(A.rotate_left(128), A); + assert_eq!(B.rotate_left(128), B); + assert_eq!(C.rotate_left(128), C); } #[test] diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs index 5d4ecb2669..01defab2b3 100644 --- a/library/core/tests/num/wrapping.rs +++ b/library/core/tests/num/wrapping.rs @@ -74,3 +74,236 @@ wrapping_test!(u64, u64::MIN, u64::MAX); #[cfg(not(target_os = "emscripten"))] wrapping_test!(u128, u128::MIN, u128::MAX); wrapping_test!(usize, usize::MIN, usize::MAX); + +// Don't warn about overflowing ops on 32-bit platforms +#[cfg_attr(target_pointer_width = "32", allow(const_err))] +fn wrapping_int_api() { + assert_eq!(i8::MAX.wrapping_add(1), i8::MIN); + assert_eq!(i16::MAX.wrapping_add(1), i16::MIN); + assert_eq!(i32::MAX.wrapping_add(1), i32::MIN); + assert_eq!(i64::MAX.wrapping_add(1), i64::MIN); + assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); + + assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX); + assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX); + assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX); + assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX); + assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); + + assert_eq!(u8::MAX.wrapping_add(1), u8::MIN); + assert_eq!(u16::MAX.wrapping_add(1), u16::MIN); + assert_eq!(u32::MAX.wrapping_add(1), u32::MIN); + assert_eq!(u64::MAX.wrapping_add(1), u64::MIN); + assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); + + assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX); + assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX); + assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX); + assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX); + assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); + + assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8)); + assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16)); + assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32)); + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as i64) + ); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as isize) + ); + } + } + + assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8)); + assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16)); + assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32)); + assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64)); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), + (0xedcb_a987_6543_2170 as usize) + ); + } + } + + macro_rules! check_mul_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), ($e) * $f); + }; + } + macro_rules! check_mul_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), $e); + }; + } + + check_mul_no_wrap!(0xfe_u8 as i8, -1); + check_mul_no_wrap!(0xfedc_u16 as i16, -1); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_mul_no_wrap!(0xfe_u8 as i8, -2); + check_mul_no_wrap!(0xfedc_u16 as i16, -2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); + + check_mul_no_wrap!(0xfe_u8 as i8, 2); + check_mul_no_wrap!(0xfedc_u16 as i16, 2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); + + check_mul_wraps!(0x80_u8 as i8, -1); + check_mul_wraps!(0x8000_u16 as i16, -1); + check_mul_wraps!(0x8000_0000_u32 as i32, -1); + check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_mul_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_div_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), ($e) / $f); + }; + } + macro_rules! check_div_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), $e); + }; + } + + check_div_no_wrap!(0xfe_u8 as i8, -1); + check_div_no_wrap!(0xfedc_u16 as i16, -1); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_div_no_wrap!(0xfe_u8 as i8, -2); + check_div_no_wrap!(0xfedc_u16 as i16, -2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_div_no_wrap!(0xfe_u8 as i8, 2); + check_div_no_wrap!(0xfedc_u16 as i16, 2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_div_wraps!(-128 as i8, -1); + check_div_wraps!(0x8000_u16 as i16, -1); + check_div_wraps!(0x8000_0000_u32 as i32, -1); + check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_div_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_rem_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), ($e) % $f); + }; + } + macro_rules! check_rem_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), 0); + }; + } + + check_rem_no_wrap!(0xfe_u8 as i8, -1); + check_rem_no_wrap!(0xfedc_u16 as i16, -1); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_rem_no_wrap!(0xfe_u8 as i8, -2); + check_rem_no_wrap!(0xfedc_u16 as i16, -2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_rem_no_wrap!(0xfe_u8 as i8, 2); + check_rem_no_wrap!(0xfedc_u16 as i16, 2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_rem_wraps!(0x80_u8 as i8, -1); + check_rem_wraps!(0x8000_u16 as i16, -1); + check_rem_wraps!(0x8000_0000_u32 as i32, -1); + check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_rem_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_neg_no_wrap { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), -($e)); + }; + } + macro_rules! check_neg_wraps { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), ($e)); + }; + } + + check_neg_no_wrap!(0xfe_u8 as i8); + check_neg_no_wrap!(0xfedc_u16 as i16); + check_neg_no_wrap!(0xfedc_ba98_u32 as i32); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); + + check_neg_wraps!(0x80_u8 as i8); + check_neg_wraps!(0x8000_u16 as i16); + check_neg_wraps!(0x8000_0000_u32 as i32); + check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_neg_wraps!(0x8000_0000_u32 as isize); + } + #[cfg(target_pointer_width = "64")] + () => { + check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); + } + } +} diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs index 8f0cd3be40..53e5539fad 100644 --- a/library/core/tests/ops.rs +++ b/library/core/tests/ops.rs @@ -1,4 +1,5 @@ -use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}; +use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; +use core::ops::{Deref, DerefMut}; // Test the Range structs and syntax. @@ -59,6 +60,12 @@ fn test_range_inclusive() { assert_eq!(r.next(), None); } +#[test] +fn test_range_to_inclusive() { + // Not much to test. + let _ = RangeToInclusive { end: 42 }; +} + #[test] fn test_range_is_empty() { assert!(!(0.0..10.0).is_empty()); @@ -151,3 +158,75 @@ fn test_range_syntax_in_return_statement() { } // Not much to test. } + +#[test] +fn range_structural_match() { + // test that all range types can be structurally matched upon + + const RANGE: Range = 0..1000; + match RANGE { + RANGE => {} + _ => unreachable!(), + } + + const RANGE_FROM: RangeFrom = 0..; + match RANGE_FROM { + RANGE_FROM => {} + _ => unreachable!(), + } + + const RANGE_FULL: RangeFull = ..; + match RANGE_FULL { + RANGE_FULL => {} + } + + const RANGE_INCLUSIVE: RangeInclusive = 0..=999; + match RANGE_INCLUSIVE { + RANGE_INCLUSIVE => {} + _ => unreachable!(), + } + + const RANGE_TO: RangeTo = ..1000; + match RANGE_TO { + RANGE_TO => {} + _ => unreachable!(), + } + + const RANGE_TO_INCLUSIVE: RangeToInclusive = ..=999; + match RANGE_TO_INCLUSIVE { + RANGE_TO_INCLUSIVE => {} + _ => unreachable!(), + } +} + +// Test Deref implementations + +#[test] +fn deref_mut_on_ref() { + // Test that `&mut T` implements `DerefMut` + + fn inc + DerefMut>(mut t: T) { + *t += 1; + } + + let mut x: isize = 5; + inc(&mut x); + assert_eq!(x, 6); +} + +#[test] +fn deref_on_ref() { + // Test that `&T` and `&mut T` implement `Deref` + + fn deref>(t: T) -> U { + *t + } + + let x: isize = 3; + let y = deref(&x); + assert_eq!(y, 3); + + let mut x: isize = 4; + let y = deref(&mut x); + assert_eq!(y, 4); +} diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index ae814efec2..5388b47562 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -402,3 +402,13 @@ fn test_unwrap_drop() { assert_eq!(x.get(), 0); } + +#[test] +pub fn option_ext() { + let thing = "{{ f }}"; + let f = thing.find("{{"); + + if f.is_none() { + println!("None!"); + } +} diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index bf977c141c..57c2fb06c1 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -18,7 +18,7 @@ fn test() { struct Pair { fst: isize, snd: isize, - }; + } let mut p = Pair { fst: 10, snd: 20 }; let pptr: *mut Pair = &mut p; let iptr: *mut isize = pptr as *mut isize; @@ -400,3 +400,16 @@ fn align_offset_weird_strides() { } assert!(!x); } + +#[test] +fn offset_from() { + let mut a = [0; 5]; + let ptr1: *mut i32 = &mut a[1]; + let ptr2: *mut i32 = &mut a[3]; + unsafe { + assert_eq!(ptr2.offset_from(ptr1), 2); + assert_eq!(ptr1.offset_from(ptr2), -2); + assert_eq!(ptr1.offset(2), ptr2); + assert_eq!(ptr2.offset(-2), ptr1); + } +} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 39ea4831b9..81660870e9 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -320,3 +320,41 @@ fn result_const() { const IS_ERR: bool = RESULT.is_err(); assert!(!IS_ERR) } + +#[test] +fn result_opt_conversions() { + #[derive(Copy, Clone, Debug, PartialEq)] + struct BadNumErr; + + fn try_num(x: i32) -> Result { + if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) } + } + + type ResOpt = Result, BadNumErr>; + type OptRes = Option>; + + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result, BadNumErr> = (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { Some(y - 1) } else { None }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs new file mode 100644 index 0000000000..c28ea85911 --- /dev/null +++ b/library/core/tests/unicode.rs @@ -0,0 +1,5 @@ +#[test] +pub fn version() { + let (major, _minor, _update) = core::unicode::UNICODE_VERSION; + assert!(major >= 10); +} diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 9690996e60..a8ebb4b321 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -32,7 +32,7 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { abort(); cfg_if::cfg_if! { - if #[cfg(any(unix, target_os = "cloudabi"))] { + if #[cfg(unix)] { unsafe fn abort() -> ! { libc::abort(); } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 682289384c..0b74a844fe 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -49,7 +49,6 @@ cfg_if::cfg_if! { mod real_imp; } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), - target_os = "cloudabi", target_os = "psp", target_family = "unix", all(target_vendor = "fortanix", target_env = "sgx"), diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index dfe5df965c..c6bec5a6fb 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -401,8 +401,7 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( } impl Client crate::TokenStream> { - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] + #[rustc_allow_const_fn_unstable(const_fn)] pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, @@ -415,8 +414,7 @@ impl Client crate::TokenStream> { } impl Client crate::TokenStream> { - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] + #[rustc_allow_const_fn_unstable(const_fn)] pub const fn expand2( f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { @@ -461,8 +459,7 @@ impl ProcMacro { } } - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] + #[rustc_allow_const_fn_unstable(const_fn)] pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], @@ -471,8 +468,7 @@ impl ProcMacro { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] + #[rustc_allow_const_fn_unstable(const_fn)] pub const fn attr( name: &'static str, expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, @@ -480,8 +476,7 @@ impl ProcMacro { ProcMacro::Attr { name, client: Client::expand2(expand) } } - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] + #[rustc_allow_const_fn_unstable(const_fn)] pub const fn bang( name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream, diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs index e7c32b1038..e130785617 100644 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ b/library/proc_macro/src/bridge/scoped_cell.rs @@ -35,8 +35,7 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { pub struct ScopedCell(Cell<>::Out>); impl ScopedCell { - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] + #[rustc_allow_const_fn_unstable(const_fn)] pub const fn new(value: >::Out) -> Self { ScopedCell(Cell::new(value)) } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 03733d3b3e..ca40293ed5 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -18,7 +18,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] -#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] +#![feature(rustc_allow_const_fn_unstable)] #![feature(nll)] #![feature(staged_api)] #![feature(const_fn)] @@ -28,7 +28,8 @@ #![feature(extern_types)] #![feature(in_band_lifetimes)] #![feature(negative_impls)] -#![feature(optin_builtin_traits)] +#![cfg_attr(bootstrap, feature(optin_builtin_traits))] +#![cfg_attr(not(bootstrap), feature(auto_traits))] #![feature(restricted_std)] #![feature(rustc_attrs)] #![feature(min_specialization)] @@ -842,6 +843,13 @@ impl fmt::Debug for Punct { } } +#[stable(feature = "proc_macro_punct_eq", since = "1.49.0")] +impl PartialEq for Punct { + fn eq(&self, rhs: &char) -> bool { + self.as_char() == *rhs + } +} + /// An identifier (`ident`). #[derive(Clone)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] diff --git a/library/proc_macro/tests/test.rs b/library/proc_macro/tests/test.rs index 331b330cf2..d2e6b0bb80 100644 --- a/library/proc_macro/tests/test.rs +++ b/library/proc_macro/tests/test.rs @@ -1,6 +1,6 @@ #![feature(proc_macro_span)] -use proc_macro::LineColumn; +use proc_macro::{LineColumn, Punct}; #[test] fn test_line_column_ord() { @@ -10,3 +10,11 @@ fn test_line_column_ord() { assert!(line0_column0 < line0_column1); assert!(line0_column1 < line1_column0); } + +#[test] +fn test_punct_eq() { + // Good enough if it typechecks, since proc_macro::Punct can't exist in a test. + fn _check(punct: Punct) { + let _ = punct == ':'; + } +} diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index bd1946133e..b64f13dba4 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -9,10 +9,13 @@ // headers or footers. // // Note that the actual module entry point is located in the C runtime startup -// object (usually called `crtX.o), which then invokes initialization callbacks +// object (usually called `crtX.o`), which then invokes initialization callbacks // of other runtime components (registered via yet another special image section). -#![feature(no_core, lang_items, optin_builtin_traits)] +#![feature(no_core)] +#![feature(lang_items)] +#![cfg_attr(bootstrap, feature(optin_builtin_traits))] +#![cfg_attr(not(bootstrap), feature(auto_traits))] #![crate_type = "rlib"] #![no_core] #![allow(non_camel_case_types)] diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs index 333761cd97..18ee7c19ba 100644 --- a/library/rtstartup/rsend.rs +++ b/library/rtstartup/rsend.rs @@ -1,6 +1,9 @@ // See rsbegin.rs for details. -#![feature(no_core, lang_items, optin_builtin_traits)] +#![feature(no_core)] +#![feature(lang_items)] +#![cfg_attr(bootstrap, feature(optin_builtin_traits))] +#![cfg_attr(not(bootstrap), feature(auto_traits))] #![crate_type = "rlib"] #![no_core] diff --git a/library/rustc-std-workspace-core/README.md b/library/rustc-std-workspace-core/README.md index 9c2b1fa91d..40e0b62afa 100644 --- a/library/rustc-std-workspace-core/README.md +++ b/library/rustc-std-workspace-core/README.md @@ -4,12 +4,12 @@ This crate is a shim and empty crate which simply depends on `libcore` and reexports all of its contents. The crate is the crux of empowering the standard library to depend on crates from crates.io -Crates on crates.io that the standard library depend on the -`rustc-std-workspace-core` crate from crates.io. On crates.io, however, this -crate is empty. We use `[patch]` to override it to this crate in this -repository. As a result, crates on crates.io will draw a dependency edge to -`libcore`, the version defined in this repository. That should draw all the -dependency edges to ensure Cargo builds crates successfully! +Crates on crates.io that the standard library depend on need to depend on the +`rustc-std-workspace-core` crate from crates.io, which is empty. We use +`[patch]` to override it to this crate in this repository. As a result, crates +on crates.io will draw a dependency edge to `libcore`, the version defined in +this repository. That should draw all the dependency edges to ensure Cargo +builds crates successfully! Note that crates on crates.io need to depend on this crate with the name `core` for everything to work correctly. To do that they can use: diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 281ed4f336..71d00b5c08 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -23,20 +23,20 @@ unwind = { path = "../unwind" } hashbrown = { version = "0.9.0", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate -addr2line = { version = "0.13.0", optional = true, default-features = false } +addr2line = { version = "0.14.0", optional = true, default-features = false } rustc-demangle = { version = "0.1.18", features = ['rustc-dep-of-std'] } miniz_oxide = { version = "0.4.0", optional = true, default-features = false } [dependencies.object] -version = "0.20" +version = "0.22" optional = true default-features = false -features = ['read_core', 'elf', 'macho', 'pe'] +features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] [dev-dependencies] rand = "0.7" [target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] -dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] } +dlmalloc = { version = "0.2.1", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } @@ -60,6 +60,8 @@ panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] compiler-builtins-c = ["alloc/compiler-builtins-c"] compiler-builtins-mem = ["alloc/compiler-builtins-mem"] +compiler-builtins-asm = ["alloc/compiler-builtins-asm"] +compiler-builtins-mangled-names = ["alloc/compiler-builtins-mangled-names"] llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] diff --git a/library/std/build.rs b/library/std/build.rs index f2ed7552af..a14ac63c7a 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -3,66 +3,22 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); - if target.contains("linux") { - if target.contains("android") { - println!("cargo:rustc-link-lib=dl"); - println!("cargo:rustc-link-lib=log"); - println!("cargo:rustc-link-lib=gcc"); - } - } else if target.contains("freebsd") { - println!("cargo:rustc-link-lib=execinfo"); - println!("cargo:rustc-link-lib=pthread"); + if target.contains("freebsd") { if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() { println!("cargo:rustc-cfg=freebsd12"); } - } else if target.contains("netbsd") { - println!("cargo:rustc-link-lib=pthread"); - println!("cargo:rustc-link-lib=rt"); - } else if target.contains("dragonfly") || target.contains("openbsd") { - println!("cargo:rustc-link-lib=pthread"); - } else if target.contains("solaris") { - println!("cargo:rustc-link-lib=socket"); - println!("cargo:rustc-link-lib=posix4"); - println!("cargo:rustc-link-lib=pthread"); - println!("cargo:rustc-link-lib=resolv"); - } else if target.contains("illumos") { - println!("cargo:rustc-link-lib=socket"); - println!("cargo:rustc-link-lib=posix4"); - println!("cargo:rustc-link-lib=pthread"); - println!("cargo:rustc-link-lib=resolv"); - println!("cargo:rustc-link-lib=nsl"); - // Use libumem for the (malloc-compatible) allocator - println!("cargo:rustc-link-lib=umem"); - } else if target.contains("apple-darwin") { - println!("cargo:rustc-link-lib=System"); - - // res_init and friends require -lresolv on macOS/iOS. - // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html - println!("cargo:rustc-link-lib=resolv"); - } else if target.contains("apple-ios") { - println!("cargo:rustc-link-lib=System"); - println!("cargo:rustc-link-lib=objc"); - println!("cargo:rustc-link-lib=framework=Security"); - println!("cargo:rustc-link-lib=framework=Foundation"); - println!("cargo:rustc-link-lib=resolv"); - } else if target.contains("uwp") { - println!("cargo:rustc-link-lib=ws2_32"); - // For BCryptGenRandom - println!("cargo:rustc-link-lib=bcrypt"); - } else if target.contains("windows") { - println!("cargo:rustc-link-lib=advapi32"); - println!("cargo:rustc-link-lib=ws2_32"); - println!("cargo:rustc-link-lib=userenv"); - } else if target.contains("fuchsia") { - println!("cargo:rustc-link-lib=zircon"); - println!("cargo:rustc-link-lib=fdio"); - } else if target.contains("cloudabi") { - if cfg!(feature = "backtrace") { - println!("cargo:rustc-link-lib=unwind"); - } - println!("cargo:rustc-link-lib=c"); - println!("cargo:rustc-link-lib=compiler_rt"); - } else if (target.contains("sgx") && target.contains("fortanix")) + } else if target.contains("linux") + || target.contains("netbsd") + || target.contains("dragonfly") + || target.contains("openbsd") + || target.contains("solaris") + || target.contains("illumos") + || target.contains("apple-darwin") + || target.contains("apple-ios") + || target.contains("uwp") + || target.contains("windows") + || target.contains("fuchsia") + || (target.contains("sgx") && target.contains("fortanix")) || target.contains("hermit") || target.contains("l4re") || target.contains("redox") diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 375b015ccc..8491ff4003 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -1,4 +1,4 @@ -//! Memory allocation APIs +//! Memory allocation APIs. //! //! In a given program, the standard library has one “global” memory allocator //! that is used for example by `Box` and `Vec`. @@ -149,7 +149,7 @@ impl System { } } - // SAFETY: Same as `AllocRef::grow` + // SAFETY: Same as `Allocator::grow` #[inline] unsafe fn grow_impl( &self, @@ -190,29 +190,29 @@ impl System { old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(new_ptr) }, } } } -// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, +// The Allocator impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, // which is in `std::sys::*::alloc`. #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for System { +unsafe impl Allocator for System { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -257,7 +257,7 @@ unsafe impl AllocRef for System { match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, @@ -277,9 +277,9 @@ unsafe impl AllocRef for System { // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { - let new_ptr = AllocRef::alloc(&self, new_layout)?; + let new_ptr = Allocator::allocate(&self, new_layout)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(new_ptr) }, } diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index a9d8a4e2a8..7e8e0a621e 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -161,6 +161,7 @@ struct BacktraceSymbol { name: Option>, filename: Option, lineno: Option, + colno: Option, } enum BytesOrWide { @@ -197,6 +198,10 @@ impl fmt::Debug for Backtrace { impl fmt::Debug for BacktraceSymbol { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + // FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280 + // FIXME: Also, include column numbers into the debug format as Display already has them. + // Until there are stable per-frame accessors, the format shouldn't be changed: + // https://github.com/rust-lang/rust/issues/65280#issuecomment-638966585 write!(fmt, "{{ ")?; if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) { @@ -209,7 +214,7 @@ impl fmt::Debug for BacktraceSymbol { write!(fmt, ", file: \"{:?}\"", fname)?; } - if let Some(line) = self.lineno.as_ref() { + if let Some(line) = self.lineno { write!(fmt, ", line: {:?}", line)?; } @@ -381,7 +386,7 @@ impl fmt::Display for Backtrace { f.print_raw(frame.frame.ip(), None, None, None)?; } else { for symbol in frame.symbols.iter() { - f.print_raw( + f.print_raw_with_column( frame.frame.ip(), symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)), symbol.filename.as_ref().map(|b| match b { @@ -389,6 +394,7 @@ impl fmt::Display for Backtrace { BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), }), symbol.lineno, + symbol.colno, )?; } } @@ -427,6 +433,7 @@ impl Capture { BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), }), lineno: symbol.lineno(), + colno: symbol.colno(), }); }); } diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs index 287359cd54..f5f74d1eb9 100644 --- a/library/std/src/backtrace/tests.rs +++ b/library/std/src/backtrace/tests.rs @@ -13,6 +13,7 @@ fn test_debug() { name: Some(b"std::backtrace::Backtrace::create".to_vec()), filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), lineno: Some(100), + colno: None, }], }, BacktraceFrame { @@ -21,6 +22,7 @@ fn test_debug() { name: Some(b"__rust_maybe_catch_panic".to_vec()), filename: None, lineno: None, + colno: None, }], }, BacktraceFrame { @@ -30,11 +32,13 @@ fn test_debug() { name: Some(b"std::rt::lang_start_internal".to_vec()), filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), lineno: Some(300), + colno: Some(5), }, BacktraceSymbol { name: Some(b"std::rt::lang_start".to_vec()), filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), lineno: Some(400), + colno: None, }, ], }, diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index fa22925170..ac72345dad 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -34,8 +34,8 @@ use crate::sys; /// attacks such as HashDoS. /// /// The hashing algorithm can be replaced on a per-`HashMap` basis using the -/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many -/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. +/// There are many alternative [hashing algorithms available on crates.io]. /// /// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although /// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. @@ -57,6 +57,7 @@ use crate::sys; /// The original C++ version of SwissTable can be found [here], and this /// [CppCon talk] gives an overview of how the algorithm works. /// +/// [hashing algorithms available on crates.io]: https://crates.io/keywords/hasher /// [SwissTable]: https://abseil.io/blog/20180927-swisstables /// [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h /// [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 @@ -154,7 +155,6 @@ use crate::sys; /// [`default`]: Default::default /// [`with_hasher`]: Self::with_hasher /// [`with_capacity_and_hasher`]: Self::with_capacity_and_hasher -/// [`fnv`]: https://crates.io/crates/fnv /// /// ``` /// use std::collections::HashMap; @@ -2219,14 +2219,16 @@ impl<'a, K, V> Entry<'a, K, V> { } } - /// Ensures a value is in the entry by inserting, if empty, the result of the default function, - /// which takes the key as its argument, and returns a mutable reference to the value in the - /// entry. + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. /// /// # Examples /// /// ``` - /// #![feature(or_insert_with_key)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, usize> = HashMap::new(); @@ -2236,7 +2238,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 9); /// ``` #[inline] - #[unstable(feature = "or_insert_with_key", issue = "71024")] + #[stable(feature = "or_insert_with_key", since = "1.50.0")] pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 5771ca758a..0044e59d69 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -19,7 +19,7 @@ mod tests; use core::array; use core::convert::Infallible; -use crate::alloc::{AllocError, LayoutErr}; +use crate::alloc::{AllocError, LayoutError}; use crate::any::TypeId; use crate::backtrace::Backtrace; use crate::borrow::Cow; @@ -390,7 +390,7 @@ impl Error for ! {} impl Error for AllocError {} #[stable(feature = "alloc_layout", since = "1.28.0")] -impl Error for LayoutErr {} +impl Error for LayoutError {} #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::ParseBoolError { diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 2a54b117ff..c30458c054 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -206,8 +206,10 @@ impl f32 { /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// - /// Using `mul_add` can be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. /// /// # Examples /// @@ -877,40 +879,4 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - /// Restrict a value to a certain interval unless it is NaN. - /// - /// Returns `max` if `self` is greater than `max`, and `min` if `self` is - /// less than `min`. Otherwise this returns `self`. - /// - /// Note that this function returns NaN if the initial value was NaN as - /// well. - /// - /// # Panics - /// - /// Panics if `min > max`, `min` is NaN, or `max` is NaN. - /// - /// # Examples - /// - /// ``` - /// #![feature(clamp)] - /// assert!((-3.0f32).clamp(-2.0, 1.0) == -2.0); - /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); - /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); - /// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan()); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "clamp", issue = "44095")] - #[inline] - pub fn clamp(self, min: f32, max: f32) -> f32 { - assert!(min <= max); - let mut x = self; - if x < min { - x = min; - } - if x > max { - x = max; - } - x - } } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 363d1a0047..f4cc53979d 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -206,8 +206,10 @@ impl f64 { /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// - /// Using `mul_add` can be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. /// /// # Examples /// @@ -880,42 +882,6 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - /// Restrict a value to a certain interval unless it is NaN. - /// - /// Returns `max` if `self` is greater than `max`, and `min` if `self` is - /// less than `min`. Otherwise this returns `self`. - /// - /// Note that this function returns NaN if the initial value was NaN as - /// well. - /// - /// # Panics - /// - /// Panics if `min > max`, `min` is NaN, or `max` is NaN. - /// - /// # Examples - /// - /// ``` - /// #![feature(clamp)] - /// assert!((-3.0f64).clamp(-2.0, 1.0) == -2.0); - /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); - /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); - /// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan()); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - #[unstable(feature = "clamp", issue = "44095")] - #[inline] - pub fn clamp(self, min: f64, max: f64) -> f64 { - assert!(min <= max); - let mut x = self; - if x < min { - x = min; - } - if x > max { - x = max; - } - x - } - // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 8c6d6c8040..60b642a6db 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1266,7 +1266,7 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run - /// # #![allow(unused_must_use)] #![cfg_attr(not(bootstrap), allow(temporary_cstring_as_ptr))] + /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)] /// use std::ffi::CString; /// /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr(); diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 7e7a28be2b..5d93016cad 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -667,10 +667,10 @@ impl OsStr { /// Gets the underlying byte representation. /// - /// Note: it is *crucial* that this API is private, to avoid + /// Note: it is *crucial* that this API is not externally public, to avoid /// revealing the internal, platform-specific encodings. #[inline] - fn bytes(&self) -> &[u8] { + pub(crate) fn bytes(&self) -> &[u8] { unsafe { &*(&self.inner as *const _ as *const [u8]) } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c256f556b3..e2d4f2e6a5 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -8,7 +8,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))] mod tests; use crate::ffi::OsString; @@ -1656,7 +1656,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// the length of the `to` file as reported by `metadata`. /// /// If you’re wanting to copy the contents of one file to another and you’re -/// working with [`File`]s, see the [`io::copy`] function. +/// working with [`File`]s, see the [`io::copy()`] function. /// /// # Platform-specific behavior /// @@ -1698,12 +1698,14 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// Creates a new hard link on the filesystem. /// -/// The `dst` path will be a link pointing to the `src` path. Note that systems -/// often require these two paths to both be located on the same filesystem. +/// The `link` path will be a link pointing to the `original` path. Note that +/// systems often require these two paths to both be located on the same +/// filesystem. /// -/// If `src` names a symbolic link, it is platform-specific whether the symbolic -/// link is followed. On platforms where it's possible to not follow it, it is -/// not followed, and the created hard link points to the symbolic link itself. +/// If `original` names a symbolic link, it is platform-specific whether the +/// symbolic link is followed. On platforms where it's possible to not follow +/// it, it is not followed, and the created hard link points to the symbolic +/// link itself. /// /// # Platform-specific behavior /// @@ -1718,7 +1720,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// This function will return an error in the following situations, but is not /// limited to just these cases: /// -/// * The `src` path is not a file or doesn't exist. +/// * The `original` path is not a file or doesn't exist. /// /// # Examples /// @@ -1731,13 +1733,13 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - fs_imp::link(src.as_ref(), dst.as_ref()) +pub fn hard_link, Q: AsRef>(original: P, link: Q) -> io::Result<()> { + fs_imp::link(original.as_ref(), link.as_ref()) } /// Creates a new symbolic link on the filesystem. /// -/// The `dst` path will be a symbolic link pointing to the `src` path. +/// The `link` path will be a symbolic link pointing to the `original` path. /// On Windows, this will be a file symlink, not a directory symlink; /// for this reason, the platform-specific [`std::os::unix::fs::symlink`] /// and [`std::os::windows::fs::symlink_file`] or [`symlink_dir`] should be @@ -1763,8 +1765,8 @@ pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( reason = "replaced with std::os::unix::fs::symlink and \ std::os::windows::fs::{symlink_file, symlink_dir}" )] -pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - fs_imp::symlink(src.as_ref(), dst.as_ref()) +pub fn soft_link, Q: AsRef>(original: P, link: Q) -> io::Result<()> { + fs_imp::symlink(original.as_ref(), link.as_ref()) } /// Reads a symbolic link, returning the file that the link points to. diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 0642dca8e4..5c96974159 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1341,6 +1341,9 @@ fn metadata_access_times() { #[test] fn symlink_hard_link() { let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; // Create "file", a file. check!(fs::File::create(tmpdir.join("file"))); diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 067ed6ba7f..3b3399860b 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -328,24 +328,57 @@ impl Write for BufWriter { } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum::(); - if self.buf.len() + total_len > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if total_len >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_vectored(bufs); - self.panicked = false; - r + if self.get_ref().is_write_vectored() { + let total_len = bufs.iter().map(|b| b.len()).sum::(); + if self.buf.len() + total_len > self.buf.capacity() { + self.flush_buf()?; + } + if total_len >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_vectored(bufs); + self.panicked = false; + r + } else { + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) + } } else { - bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); - Ok(total_len) + let mut iter = bufs.iter(); + let mut total_written = if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) { + // This is the first non-empty slice to write, so if it does + // not fit in the buffer, we still get to flush and proceed. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + if buf.len() >= self.buf.capacity() { + // The slice is at least as large as the buffering capacity, + // so it's better to write it directly, bypassing the buffer. + self.panicked = true; + let r = self.get_mut().write(buf); + self.panicked = false; + return r; + } else { + self.buf.extend_from_slice(buf); + buf.len() + } + } else { + return Ok(0); + }; + debug_assert!(total_written != 0); + for buf in iter { + if self.buf.len() + buf.len() > self.buf.capacity() { + break; + } else { + self.buf.extend_from_slice(buf); + total_written += buf.len(); + } + } + Ok(total_written) } } fn is_write_vectored(&self) -> bool { - self.get_ref().is_write_vectored() + true } fn flush(&mut self) -> io::Result<()> { diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index a80d08db86..d0c859d2e0 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -20,6 +20,12 @@ impl<'a, W: Write> LineWriterShim<'a, W> { Self { buffer } } + /// Get a reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). + fn inner(&self) -> &W { + self.buffer.get_ref() + } + /// Get a mutable reference to the inner writer (that is, the writer /// wrapped by the BufWriter). Be careful with this writer, as writes to /// it will bypass the buffer. @@ -227,7 +233,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> { } fn is_write_vectored(&self) -> bool { - self.buffer.is_write_vectored() + self.inner().is_write_vectored() } /// Write some data into this BufReader with line buffering. This means diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index f9caeaf98e..65497817f8 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -126,6 +126,51 @@ impl IntoInnerError { pub fn into_inner(self) -> W { self.0 } + + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail. Unlike `error`, this can be used to + /// obtain ownership of the underlying error. + /// + /// # Example + /// ``` + /// #![feature(io_into_inner_error_parts)] + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let err = into_inner_err.into_error(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// ``` + #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + pub fn into_error(self) -> Error { + self.1 + } + + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail, and the underlying writer. + /// + /// This can be used to simply obtain ownership of the underlying error; it can also be used for + /// advanced error recovery. + /// + /// # Example + /// ``` + /// #![feature(io_into_inner_error_parts)] + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let (err, recovered_writer) = into_inner_err.into_parts(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// assert_eq!(recovered_writer.buffer(), b"t be actually written"); + /// ``` + #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + pub fn into_parts(self) -> (Error, W) { + (self.1, self.0) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs new file mode 100644 index 0000000000..b88bca2f2b --- /dev/null +++ b/library/std/src/io/copy.rs @@ -0,0 +1,88 @@ +use crate::io::{self, ErrorKind, Read, Write}; +use crate::mem::MaybeUninit; + +/// Copies the entire contents of a reader into a writer. +/// +/// This function will continuously read data from `reader` and then +/// write it into `writer` in a streaming fashion until `reader` +/// returns EOF. +/// +/// On success, the total number of bytes that were copied from +/// `reader` to `writer` is returned. +/// +/// If you’re wanting to copy the contents of one file to another and you’re +/// working with filesystem paths, see the [`fs::copy`] function. +/// +/// [`fs::copy`]: crate::fs::copy +/// +/// # Errors +/// +/// This function will return an error immediately if any call to [`read`] or +/// [`write`] returns an error. All instances of [`ErrorKind::Interrupted`] are +/// handled by this function and the underlying operation is retried. +/// +/// [`read`]: Read::read +/// [`write`]: Write::write +/// +/// # Examples +/// +/// ``` +/// use std::io; +/// +/// fn main() -> io::Result<()> { +/// let mut reader: &[u8] = b"hello"; +/// let mut writer: Vec = vec![]; +/// +/// io::copy(&mut reader, &mut writer)?; +/// +/// assert_eq!(&b"hello"[..], &writer[..]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn copy(reader: &mut R, writer: &mut W) -> io::Result +where + R: Read, + W: Write, +{ + cfg_if::cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "android"))] { + crate::sys::kernel_copy::copy_spec(reader, writer) + } else { + generic_copy(reader, writer) + } + } +} + +/// The general read-write-loop implementation of +/// `io::copy` that is used when specializations are not available or not applicable. +pub(crate) fn generic_copy(reader: &mut R, writer: &mut W) -> io::Result +where + R: Read, + W: Write, +{ + let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit(); + // FIXME: #42788 + // + // - This creates a (mut) reference to a slice of + // _uninitialized_ integers, which is **undefined behavior** + // + // - Only the standard library gets to soundly "ignore" this, + // based on its privileged knowledge of unstable rustc + // internals; + unsafe { + reader.initializer().initialize(buf.assume_init_mut()); + } + + let mut written = 0; + loop { + let len = match reader.read(unsafe { buf.assume_init_mut() }) { + Ok(0) => return Ok(written), + Ok(len) => len, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + }; + writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?; + written += len as u64; + } +} diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 66426101d2..00bf8b9af7 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -209,20 +209,6 @@ impl BufRead for Box { } } -// Used by panicking::default_hook -#[cfg(test)] -/// This impl is only used by printing logic, so any error returned is always -/// of kind `Other`, and should be ignored. -impl Write for dyn ::realstd::io::LocalOutput { - fn write(&mut self, buf: &[u8]) -> io::Result { - (*self).write(buf).map_err(|_| ErrorKind::Other.into()) - } - - fn flush(&mut self) -> io::Result<()> { - (*self).flush().map_err(|_| ErrorKind::Other.into()) - } -} - // ============================================================================= // In-memory buffer implementations @@ -320,6 +306,10 @@ impl BufRead for &[u8] { /// /// Note that writing updates the slice to point to the yet unwritten part. /// The slice will be empty when it has been completely overwritten. +/// +/// If the number of bytes to be written exceeds the size of the slice, write operations will +/// return short writes: ultimately, `Ok(0)`; in this situation, `write_all` returns an error of +/// kind `ErrorKind::WriteZero`. #[stable(feature = "rust1", since = "1.0.0")] impl Write for &mut [u8] { #[inline] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index e6efe6ec57..30d80b76ab 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -266,24 +266,25 @@ pub use self::buffered::IntoInnerError; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::{BufReader, BufWriter, LineWriter}; #[stable(feature = "rust1", since = "1.0.0")] +pub use self::copy::copy; +#[stable(feature = "rust1", since = "1.0.0")] pub use self::cursor::Cursor; #[stable(feature = "rust1", since = "1.0.0")] pub use self::error::{Error, ErrorKind, Result}; +#[unstable(feature = "internal_output_capture", issue = "none")] +#[doc(no_inline, hidden)] +pub use self::stdio::set_output_capture; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{StderrLock, StdinLock, StdoutLock}; #[unstable(feature = "print_internals", issue = "none")] pub use self::stdio::{_eprint, _print}; -#[unstable(feature = "libstd_io_internals", issue = "42788")] -#[doc(no_inline, hidden)] -pub use self::stdio::{set_panic, set_print, LocalOutput}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::util::{copy, empty, repeat, sink, Empty, Repeat, Sink}; - -pub(crate) use self::stdio::clone_io; +pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink}; mod buffered; +pub(crate) mod copy; mod cursor; mod error; mod impls; @@ -366,7 +367,6 @@ where { let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf }; - let ret; loop { if g.len == g.buf.len() { unsafe { @@ -385,21 +385,20 @@ where } } - match r.read(&mut g.buf[g.len..]) { - Ok(0) => { - ret = Ok(g.len - start_len); - break; + let buf = &mut g.buf[g.len..]; + match r.read(buf) { + Ok(0) => return Ok(g.len - start_len), + Ok(n) => { + // We can't allow bogus values from read. If it is too large, the returned vec could have its length + // set past its capacity, or if it overflows the vec could be shortened which could create an invalid + // string if this is called via read_to_string. + assert!(n <= buf.len()); + g.len += n; } - Ok(n) => g.len += n, Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } + Err(e) => return Err(e), } } - - ret } pub(crate) fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result @@ -1306,10 +1305,10 @@ pub trait Write { default_write_vectored(|b| self.write(b), bufs) } - /// Determines if this `Write`er has an efficient [`write_vectored`] + /// Determines if this `Write`r has an efficient [`write_vectored`] /// implementation. /// - /// If a `Write`er does not override the default [`write_vectored`] + /// If a `Write`r does not override the default [`write_vectored`] /// implementation, code using it may want to avoid the method all together /// and coalesce writes into a single buffer for higher performance. /// diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 360c435aff..1160011f35 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -5,45 +5,39 @@ mod tests; use crate::io::prelude::*; -use crate::cell::RefCell; +use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; use crate::lazy::SyncOnceCell; use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; -use crate::sync::{Mutex, MutexGuard}; +use crate::sync::{Arc, Mutex, MutexGuard}; use crate::sys::stdio; use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; -use crate::thread::LocalKey; -thread_local! { - /// Used by the test crate to capture the output of the print! and println! macros. - static LOCAL_STDOUT: RefCell>> = { - RefCell::new(None) - } -} +type LocalStream = Arc>>; thread_local! { - /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics. - static LOCAL_STDERR: RefCell>> = { - RefCell::new(None) + /// Used by the test crate to capture the output of the print macros and panics. + static OUTPUT_CAPTURE: Cell> = { + Cell::new(None) } } -/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used. +/// Flag to indicate OUTPUT_CAPTURE is used. /// -/// If both are None and were never set on any thread, this flag is set to -/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all -/// threads, saving some time and memory registering an unused thread local. +/// If it is None and was never set on any thread, this flag is set to false, +/// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time +/// and memory registering an unused thread local. /// -/// Note about memory ordering: This contains information about whether two -/// thread local variables might be in use. Although this is a global flag, the +/// Note about memory ordering: This contains information about whether a +/// thread local variable might be in use. Although this is a global flag, the /// memory ordering between threads does not matter: we only want this flag to -/// have a consistent order between set_print/set_panic and print_to *within +/// have a consistent order between set_output_capture and print_to *within /// the same thread*. Within the same thread, things always have a perfectly /// consistent order. So Ordering::Relaxed is fine. -static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false); +static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false); /// A handle to a raw instance of the standard input stream of this process. /// @@ -410,6 +404,14 @@ impl Read for Stdin { } } +// only used by platform-dependent io::copy specializations, i.e. unused on some platforms +#[cfg(any(target_os = "linux", target_os = "android"))] +impl StdinLock<'_> { + pub(crate) fn as_mut_buf(&mut self) -> &mut BufReader { + &mut self.inner + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Read for StdinLock<'_> { fn read(&mut self, buf: &mut [u8]) -> io::Result { @@ -888,97 +890,24 @@ impl fmt::Debug for StderrLock<'_> { } } -/// A writer than can be cloned to new threads. -#[unstable( - feature = "set_stdio", - reason = "this trait may disappear completely or be replaced \ - with a more general mechanism", - issue = "none" -)] -#[doc(hidden)] -pub trait LocalOutput: Write + Send { - fn clone_box(&self) -> Box; -} - -/// Resets the thread-local stderr handle to the specified writer -/// -/// This will replace the current thread's stderr handle, returning the old -/// handle. All future calls to `panic!` and friends will emit their output to -/// this specified handle. -/// -/// Note that this does not need to be called for all new threads; the default -/// output handle is to the process's stderr stream. -#[unstable( - feature = "set_stdio", - reason = "this function may disappear completely or be replaced \ - with a more general mechanism", - issue = "none" -)] -#[doc(hidden)] -pub fn set_panic(sink: Option>) -> Option> { - use crate::mem; - if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { - // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false. - return None; - } - let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( - |mut s| { - let _ = s.flush(); - Some(s) - }, - ); - LOCAL_STREAMS.store(true, Ordering::Relaxed); - s -} - -/// Resets the thread-local stdout handle to the specified writer -/// -/// This will replace the current thread's stdout handle, returning the old -/// handle. All future calls to `print!` and friends will emit their output to -/// this specified handle. -/// -/// Note that this does not need to be called for all new threads; the default -/// output handle is to the process's stdout stream. +/// Sets the thread-local output capture buffer and returns the old one. #[unstable( - feature = "set_stdio", - reason = "this function may disappear completely or be replaced \ - with a more general mechanism", + feature = "internal_output_capture", + reason = "this function is meant for use in the test crate \ + and may disappear in the future", issue = "none" )] #[doc(hidden)] -pub fn set_print(sink: Option>) -> Option> { - use crate::mem; - if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { - // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false. +pub fn set_output_capture(sink: Option) -> Option { + if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) { + // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false. return None; } - let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( - |mut s| { - let _ = s.flush(); - Some(s) - }, - ); - LOCAL_STREAMS.store(true, Ordering::Relaxed); - s -} - -pub(crate) fn clone_io() -> (Option>, Option>) { - // Don't waste time when LOCAL_{STDOUT,STDERR} are definitely None. - if !LOCAL_STREAMS.load(Ordering::Relaxed) { - return (None, None); - } - - LOCAL_STDOUT.with(|stdout| { - LOCAL_STDERR.with(|stderr| { - ( - stdout.borrow().as_ref().map(|o| o.clone_box()), - stderr.borrow().as_ref().map(|o| o.clone_box()), - ) - }) - }) + OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed); + OUTPUT_CAPTURE.with(move |slot| slot.replace(sink)) } -/// Write `args` to output stream `local_s` if possible, `global_s` +/// Write `args` to the capture buffer if enabled and possible, or `global_s` /// otherwise. `label` identifies the stream in a panic message. /// /// This function is used to print error messages, so it takes extra @@ -988,36 +917,26 @@ pub(crate) fn clone_io() -> (Option>, Option( - args: fmt::Arguments<'_>, - local_s: &'static LocalKey>>>, - global_s: fn() -> T, - label: &str, -) where +fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) +where T: Write, { - let result = LOCAL_STREAMS - .load(Ordering::Relaxed) - .then(|| { - local_s - .try_with(|s| { - // Note that we completely remove a local sink to write to in case - // our printing recursively panics/prints, so the recursive - // panic/print goes to the global sink instead of our local sink. - let prev = s.borrow_mut().take(); - if let Some(mut w) = prev { - let result = w.write_fmt(args); - *s.borrow_mut() = Some(w); - return result; - } - global_s().write_fmt(args) - }) - .ok() - }) - .flatten() - .unwrap_or_else(|| global_s().write_fmt(args)); - - if let Err(e) = result { + if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) + && OUTPUT_CAPTURE.try_with(|s| { + // Note that we completely remove a local sink to write to in case + // our printing recursively panics/prints, so the recursive + // panic/print goes to the global sink instead of our local sink. + s.take().map(|w| { + let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args); + s.set(Some(w)); + }) + }) == Ok(Some(())) + { + // Succesfully wrote to capture buffer. + return; + } + + if let Err(e) = global_s().write_fmt(args) { panic!("failed printing to {}: {}", label, e); } } @@ -1030,7 +949,7 @@ fn print_to( #[doc(hidden)] #[cfg(not(test))] pub fn _print(args: fmt::Arguments<'_>) { - print_to(args, &LOCAL_STDOUT, stdout, "stdout"); + print_to(args, stdout, "stdout"); } #[unstable( @@ -1041,7 +960,7 @@ pub fn _print(args: fmt::Arguments<'_>) { #[doc(hidden)] #[cfg(not(test))] pub fn _eprint(args: fmt::Arguments<'_>) { - print_to(args, &LOCAL_STDERR, stderr, "stderr"); + print_to(args, stderr, "stderr"); } #[cfg(test)] diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 913b28538b..f176c2f088 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,7 +1,7 @@ use super::{repeat, Cursor, SeekFrom}; use crate::cmp::{self, min}; -use crate::io::prelude::*; use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{BufRead, Read, Seek, Write}; use crate::ops::Deref; #[test] diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 2b1f371129..db845457c9 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -4,78 +4,7 @@ mod tests; use crate::fmt; -use crate::io::{self, BufRead, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Write}; -use crate::mem::MaybeUninit; - -/// Copies the entire contents of a reader into a writer. -/// -/// This function will continuously read data from `reader` and then -/// write it into `writer` in a streaming fashion until `reader` -/// returns EOF. -/// -/// On success, the total number of bytes that were copied from -/// `reader` to `writer` is returned. -/// -/// If you’re wanting to copy the contents of one file to another and you’re -/// working with filesystem paths, see the [`fs::copy`] function. -/// -/// [`fs::copy`]: crate::fs::copy -/// -/// # Errors -/// -/// This function will return an error immediately if any call to [`read`] or -/// [`write`] returns an error. All instances of [`ErrorKind::Interrupted`] are -/// handled by this function and the underlying operation is retried. -/// -/// [`read`]: Read::read -/// [`write`]: Write::write -/// -/// # Examples -/// -/// ``` -/// use std::io; -/// -/// fn main() -> io::Result<()> { -/// let mut reader: &[u8] = b"hello"; -/// let mut writer: Vec = vec![]; -/// -/// io::copy(&mut reader, &mut writer)?; -/// -/// assert_eq!(&b"hello"[..], &writer[..]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn copy(reader: &mut R, writer: &mut W) -> io::Result -where - R: Read, - W: Write, -{ - let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit(); - // FIXME: #42788 - // - // - This creates a (mut) reference to a slice of - // _uninitialized_ integers, which is **undefined behavior** - // - // - Only the standard library gets to soundly "ignore" this, - // based on its privileged knowledge of unstable rustc - // internals; - unsafe { - reader.initializer().initialize(buf.assume_init_mut()); - } - - let mut written = 0; - loop { - let len = match reader.read(unsafe { buf.assume_init_mut() }) { - Ok(0) => return Ok(written), - Ok(len) => len, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Err(e), - }; - writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?; - written += len as u64; - } -} +use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Write}; /// A reader which is always at EOF. /// diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b990b78570..417a54e9df 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -20,19 +20,30 @@ /// explicitly using `as` allows a few more coercions that aren't allowed implicitly, such as /// changing the type of a raw pointer or turning closures into raw pointers. /// -/// `as` is also used to rename imports in [`use`] and [`extern crate`] statements: +/// `as` can be seen as the primitive for `From` and `Into`: `as` only works with primitives +/// (`u8`, `bool`, `str`, pointers, ...) whereas `From` and `Into` also works with types like +/// `String` or `Vec`. +/// +/// `as` can also be used with the `_` placeholder when the destination type can be inferred. Note +/// that this can cause inference breakage and usually such code should use an explicit type for +/// both clarity and stability. This is most useful when converting pointers using `as *const _` or +/// `as *mut _` though the [`cast`][const-cast] method is recommended over `as *const _` and it is +/// [the same][mut-cast] for `as *mut _`: those methods make the intent clearer. +/// +/// `as` is also used to rename imports in [`use`] and [`extern crate`][`crate`] statements: /// /// ``` /// # #[allow(unused_imports)] /// use std::{mem as memory, net as network}; /// // Now you can use the names `memory` and `network` to refer to `std::mem` and `std::net`. /// ``` -/// /// For more information on what `as` is capable of, see the [Reference]. /// /// [Reference]: ../reference/expressions/operator-expr.html#type-cast-expressions +/// [`crate`]: keyword.crate.html /// [`use`]: keyword.use.html -/// [`extern crate`]: keyword.crate.html +/// [const-cast]: primitive.pointer.html#method.cast +/// [mut-cast]: primitive.pointer.html#method.cast-1 mod as_keyword {} #[doc(keyword = "break")] @@ -554,8 +565,12 @@ mod fn_keyword {} /// /// For more information on for-loops, see the [Rust book] or the [Reference]. /// +/// See also, [`loop`], [`while`]. +/// /// [`in`]: keyword.in.html /// [`impl`]: keyword.impl.html +/// [`loop`]: keyword.loop.html +/// [`while`]: keyword.while.html /// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds /// [Rust book]: /// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for @@ -707,8 +722,8 @@ mod impl_keyword {} /// /// ## Literal Examples: /// -/// * `for _ **in** 1..3 {}` - Iterate over an exclusive range up to but excluding 3. -/// * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and including 3. +/// * `for _ in 1..3 {}` - Iterate over an exclusive range up to but excluding 3. +/// * `for _ in 1..=3 {}` - Iterate over an inclusive range up to and including 3. /// /// (Read more about [range patterns]) /// @@ -831,6 +846,8 @@ mod let_keyword {} /// /// For more information on `while` and loops in general, see the [reference]. /// +/// See also, [`for`], [`loop`]. +/// /// [`for`]: keyword.for.html /// [`loop`]: keyword.loop.html /// [reference]: ../reference/expressions/loop-expr.html#predicate-loops @@ -879,6 +896,10 @@ mod while_keyword {} /// /// For more information on `loop` and loops in general, see the [Reference]. /// +/// See also, [`for`], [`while`]. +/// +/// [`for`]: keyword.for.html +/// [`while`]: keyword.while.html /// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword {} @@ -1739,7 +1760,7 @@ mod super_keyword {} /// /// # Differences between the 2015 and 2018 editions /// -/// In the 2015 edition parameters pattern where not needed for traits: +/// In the 2015 edition the parameters pattern was not needed for traits: /// /// ```rust,edition2015 /// trait Tr { @@ -2175,6 +2196,7 @@ mod where_keyword {} // 2018 Edition keywords +#[doc(alias = "promise")] #[doc(keyword = "async")] // /// Return a [`Future`] instead of blocking the current thread. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 667d109fb2..5bc5ddaa5f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -206,12 +206,13 @@ #![needs_panic_runtime] // std may use features in a platform-specific way #![allow(unused_features)] -#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] -#![cfg_attr(test, feature(print_internals, set_stdio, update_panic_count))] +#![feature(rustc_allow_const_fn_unstable)] +#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] +#![deny(rustc::existing_doc_keyword)] #![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable @@ -227,7 +228,6 @@ #![feature(asm)] #![feature(associated_type_bounds)] #![feature(atomic_mut_ptr)] -#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(c_variadic)] #![feature(cfg_accessible)] @@ -235,7 +235,6 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(char_internals)] -#![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] @@ -289,7 +288,8 @@ #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(once_cell)] -#![feature(optin_builtin_traits)] +#![cfg_attr(bootstrap, feature(optin_builtin_traits))] +#![cfg_attr(not(bootstrap), feature(auto_traits))] #![feature(or_patterns)] #![feature(panic_info_message)] #![feature(panic_internals)] @@ -313,18 +313,18 @@ #![feature(stdsimd)] #![feature(stmt_expr_attributes)] #![feature(str_internals)] +#![feature(str_split_once)] #![feature(test)] #![feature(thread_local)] #![feature(thread_local_internals)] #![feature(toowned_clone_into)] #![feature(total_cmp)] #![feature(trace_macros)] +#![feature(try_blocks)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unsafe_block_in_unsafe_fn)] -#![feature(unsafe_cell_get_mut)] #![feature(unsafe_cell_raw_get)] -#![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] #![feature(wake_trait)] @@ -566,5 +566,5 @@ include!("keyword_docs.rs"); // This is required to avoid an unstable error when `restricted-std` is not // enabled. The use of #![feature(restricted_std)] in rustc-std-workspace-std // is unconditional, so the unstable feature needs to be defined somewhere. -#[cfg_attr(not(feature = "restricted-std"), unstable(feature = "restricted_std", issue = "none"))] +#[unstable(feature = "restricted_std", issue = "none")] mod __restricted_std_workaround {} diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 57649d6f8f..de072e83df 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -8,6 +8,7 @@ #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(libstd_sys_internals)] +#[cfg_attr(not(any(bootstrap, test)), rustc_diagnostic_item = "std_panic_macro")] macro_rules! panic { () => ({ $crate::panic!("explicit panic") }); ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) }); diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index bb3ece4c27..d33b772633 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -148,7 +148,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_unspecified(&self) -> bool { match self { @@ -170,7 +170,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_loopback(&self) -> bool { match self { @@ -215,7 +215,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_multicast(&self) -> bool { match self { @@ -263,8 +263,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); /// ``` + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")] - pub fn is_ipv4(&self) -> bool { + pub const fn is_ipv4(&self) -> bool { matches!(self, IpAddr::V4(_)) } @@ -281,8 +282,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); /// ``` + #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")] - pub fn is_ipv6(&self) -> bool { + pub const fn is_ipv6(&self) -> bool { matches!(self, IpAddr::V6(_)) } } @@ -299,8 +301,8 @@ impl Ipv4Addr { /// /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] + #[stable(feature = "rust1", since = "1.0.0")] pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { // `s_addr` is stored as BE on all machine and the array is in BE order. // So the native endian conversion method is used so that it's never swapped. @@ -356,7 +358,7 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!(addr.octets(), [127, 0, 0, 1]); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn octets(&self) -> [u8; 4] { // This returns the order we want because s_addr is stored in big-endian. @@ -378,8 +380,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); /// ``` - #[stable(feature = "ip_shared", since = "1.12.0")] #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] + #[stable(feature = "ip_shared", since = "1.12.0")] pub const fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 } @@ -398,7 +400,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 @@ -427,7 +429,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_private(&self) -> bool { match self.octets() { @@ -453,7 +455,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_link_local(&self) -> bool { matches!(self.octets(), [169, 254, ..]) @@ -673,7 +675,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 @@ -693,7 +695,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_broadcast(&self) -> bool { u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) @@ -719,7 +721,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_documentation(&self) -> bool { match self.octets() { @@ -749,7 +751,7 @@ impl Ipv4Addr { /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) /// ); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); @@ -772,7 +774,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); @@ -1041,10 +1043,9 @@ impl Ipv6Addr { /// /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] - #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] + #[stable(feature = "rust1", since = "1.0.0")] pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { let addr16 = [ a.to_be(), @@ -1060,6 +1061,8 @@ impl Ipv6Addr { inner: c::in6_addr { // All elements in `addr16` are big endian. // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. + // rustc_allow_const_fn_unstable: the transmute could be written as stable const + // code, but that leads to worse code generation (#75085) s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) }, }, } @@ -1101,11 +1104,14 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn segments(&self) -> [u16; 8] { // All elements in `s6_addr` must be big endian. // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. + // rustc_allow_const_fn_unstable: the transmute could be written as stable const code, but + // that leads to worse code generation (#75085) let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) }; // We want native endian u16 [ @@ -1134,7 +1140,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_unspecified(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) @@ -1154,7 +1160,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_loopback(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) @@ -1464,7 +1470,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(since = "1.7.0", feature = "ip_17")] pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 @@ -1519,7 +1525,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), /// Some(Ipv4Addr::new(0, 0, 0, 1))); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn to_ipv4(&self) -> Option { if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { @@ -1539,8 +1545,8 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// ``` - #[stable(feature = "ipv6_to_octets", since = "1.12.0")] #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] + #[stable(feature = "ipv6_to_octets", since = "1.12.0")] pub const fn octets(&self) -> [u8; 16] { self.inner.s6_addr } diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index d9fbdd1b5e..44fb3adf07 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -936,4 +936,10 @@ fn ip_const() { const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); + + const IS_IP_V4: bool = IP_ADDRESS.is_ipv4(); + assert!(IS_IP_V4); + + const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); + assert!(!IS_IP_V6); } diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 58c6343ea3..325acf0b97 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -1,6 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests; use crate::io::prelude::*; diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 17e3e4497c..2377a76a33 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))] mod tests; use crate::fmt; diff --git a/library/std/src/num/tests.rs b/library/std/src/num/tests.rs index 2f50b73f49..df0df3f23f 100644 --- a/library/std/src/num/tests.rs +++ b/library/std/src/num/tests.rs @@ -75,8 +75,8 @@ fn test_checked_mul() { macro_rules! test_is_power_of_two { ($test_name:ident, $T:ident) => { + #[test] fn $test_name() { - #![test] assert_eq!((0 as $T).is_power_of_two(), false); assert_eq!((1 as $T).is_power_of_two(), true); assert_eq!((2 as $T).is_power_of_two(), true); @@ -96,8 +96,8 @@ test_is_power_of_two! { test_is_power_of_two_uint, usize } macro_rules! test_next_power_of_two { ($test_name:ident, $T:ident) => { + #[test] fn $test_name() { - #![test] assert_eq!((0 as $T).next_power_of_two(), 1); let mut next_power = 1; for i in 1 as $T..40 { @@ -118,8 +118,8 @@ test_next_power_of_two! { test_next_power_of_two_uint, usize } macro_rules! test_checked_next_power_of_two { ($test_name:ident, $T:ident) => { + #[test] fn $test_name() { - #![test] assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); let smax = $T::MAX >> 1; assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1)); diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index fbbc61f4e6..8ba3feccb6 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -24,11 +24,11 @@ use crate::sys_common::{thread_info, util}; use crate::thread; #[cfg(not(test))] -use crate::io::set_panic; +use crate::io::set_output_capture; // make sure to use the stderr output configured // by libtest in the real copy of std #[cfg(test)] -use realstd::io::set_panic; +use realstd::io::set_output_capture; // Binary interface to the panic runtime that the standard library depends on. // @@ -218,11 +218,9 @@ fn default_hook(info: &PanicInfo<'_>) { } }; - if let Some(mut local) = set_panic(None) { - // NB. In `cfg(test)` this uses the forwarding impl - // for `dyn ::realstd::io::LocalOutput`. - write(&mut local); - set_panic(Some(local)); + if let Some(local) = set_output_capture(None) { + write(&mut *local.lock().unwrap_or_else(|e| e.into_inner())); + set_output_capture(Some(local)); } else if let Some(mut out) = panic_output() { write(&mut out); } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index ff94fda5a2..896d6c2a64 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -873,12 +873,12 @@ pub fn test_decompositions_windows() { ); t!("\\\\.\\foo/bar", - iter: ["\\\\.\\foo/bar", "\\"], + iter: ["\\\\.\\foo", "\\", "bar"], has_root: true, is_absolute: true, - parent: None, - file_name: None, - file_stem: None, + parent: Some("\\\\.\\foo/"), + file_name: Some("bar"), + file_stem: Some("bar"), extension: None ); diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index c7a7c779d3..a3776681d0 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -26,38 +26,37 @@ //! # Prelude contents //! //! The current version of the prelude (version 1) lives in -//! [`std::prelude::v1`], and re-exports the following. +//! [`std::prelude::v1`], and re-exports the following: //! -//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]}. The -//! marker traits indicate fundamental properties of types. -//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various +//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]}, +//! marker traits that indicate fundamental properties of types. +//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}, various //! operations for both destructors and overloading `()`. //! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly //! dropping a value. //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. -//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines +//! * [`std::borrow`]::[`ToOwned`], the conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a //! borrowed type. //! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines //! [`clone`][`Clone::clone`], the method for producing a copy of a value. -//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The +//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }, the //! comparison traits, which implement the comparison operators and are often //! seen in trait bounds. -//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic +//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}, generic //! conversions, used by savvy API authors to create overloaded methods. //! * [`std::default`]::[`Default`], types that have default values. -//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`], -//! [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various +//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`] +//! [`DoubleEndedIterator`], [`ExactSizeIterator`]}, iterators of various //! kinds. -//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}. A +//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}, a //! type which expresses the presence or absence of a value. This type is so //! commonly used, its variants are also exported. -//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}. A type +//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}, a type //! for functions that may succeed or fail. Like [`Option`], its variants are //! exported as well. //! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings. -//! * [`std::vec`]::[`Vec`], a growable, heap-allocated -//! vector. +//! * [`std::vec`]::[`Vec`], a growable, heap-allocated vector. //! //! [`mem::drop`]: crate::mem::drop //! [`std::borrow`]: crate::borrow diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 83a282c8cd..ec12e9f09d 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -198,7 +198,7 @@ mod prim_bool {} /// words, they can't return `!` from every code path. As an example, this code doesn't compile: /// /// ```compile_fail -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// unimplemented!() @@ -208,7 +208,7 @@ mod prim_bool {} /// But this code does: /// /// ``` -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// if true { @@ -478,8 +478,10 @@ mod prim_unit {} #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} +#[doc(alias = "[]")] +#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases +#[doc(alias = "[T; N]")] #[doc(primitive = "array")] -// /// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the /// non-negative compile-time constant size, `N`. /// @@ -489,6 +491,10 @@ mod prim_pointer {} /// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. /// The type of `x` must be [`Copy`]. /// +/// Note that `[expr; 0]` is allowed, and produces an empty array. +/// This will still evaluate `expr`, however, and immediately drop the resulting value, so +/// be mindful of side effects. +/// /// Arrays of *any* size implement the following traits if the element type allows it: /// /// - [`Copy`] @@ -920,6 +926,7 @@ mod prim_usize {} #[doc(primitive = "reference")] #[doc(alias = "&")] +#[doc(alias = "&mut")] // /// References, both shared and mutable. /// diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 2c7ed4614b..fb78e62834 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -97,7 +97,7 @@ #![stable(feature = "process", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))] mod tests; use crate::io::prelude::*; @@ -1779,6 +1779,7 @@ pub fn exit(code: i32) -> ! { /// /// [panic hook]: crate::panic::set_hook #[stable(feature = "process_abort", since = "1.17.0")] +#[cold] pub fn abort() -> ! { crate::sys::abort_internal(); } diff --git a/library/std/src/sync/mpsc/blocking.rs b/library/std/src/sync/mpsc/blocking.rs index d34de6a4fa..4c852b8ee8 100644 --- a/library/std/src/sync/mpsc/blocking.rs +++ b/library/std/src/sync/mpsc/blocking.rs @@ -36,7 +36,11 @@ pub fn tokens() -> (WaitToken, SignalToken) { impl SignalToken { pub fn signal(&self) -> bool { - let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst); + let wake = self + .inner + .woken + .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) + .is_ok(); if wake { self.inner.thread.unpark(); } diff --git a/library/std/src/sync/mpsc/oneshot.rs b/library/std/src/sync/mpsc/oneshot.rs index 75f5621fa1..3dcf03f579 100644 --- a/library/std/src/sync/mpsc/oneshot.rs +++ b/library/std/src/sync/mpsc/oneshot.rs @@ -129,7 +129,7 @@ impl Packet { let ptr = unsafe { signal_token.cast_to_usize() }; // race with senders to enter the blocking state - if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY { + if self.state.compare_exchange(EMPTY, ptr, Ordering::SeqCst, Ordering::SeqCst).is_ok() { if let Some(deadline) = deadline { let timed_out = !wait_token.wait_max_until(deadline); // Try to reset the state @@ -161,7 +161,12 @@ impl Packet { // the state changes under our feet we'd rather just see that state // change. DATA => { - self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst); + let _ = self.state.compare_exchange( + DATA, + EMPTY, + Ordering::SeqCst, + Ordering::SeqCst, + ); match (&mut *self.data.get()).take() { Some(data) => Ok(data), None => unreachable!(), @@ -264,7 +269,10 @@ impl Packet { // If we've got a blocked thread, then use an atomic to gain ownership // of it (may fail) - ptr => self.state.compare_and_swap(ptr, EMPTY, Ordering::SeqCst), + ptr => self + .state + .compare_exchange(ptr, EMPTY, Ordering::SeqCst, Ordering::SeqCst) + .unwrap_or_else(|x| x), }; // Now that we've got ownership of our state, figure out what to do diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs index 898654f21f..0c32e636a5 100644 --- a/library/std/src/sync/mpsc/shared.rs +++ b/library/std/src/sync/mpsc/shared.rs @@ -385,8 +385,15 @@ impl Packet { self.port_dropped.store(true, Ordering::SeqCst); let mut steals = unsafe { *self.steals.get() }; while { - let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst); - cnt != DISCONNECTED && cnt != steals + match self.cnt.compare_exchange( + steals, + DISCONNECTED, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_) => false, + Err(old) => old != DISCONNECTED, + } } { // See the discussion in 'try_recv' for why we yield // control of this thread. diff --git a/library/std/src/sync/mpsc/stream.rs b/library/std/src/sync/mpsc/stream.rs index 9f7c1af895..a652f24c58 100644 --- a/library/std/src/sync/mpsc/stream.rs +++ b/library/std/src/sync/mpsc/stream.rs @@ -322,12 +322,15 @@ impl Packet { // (because there is a bounded number of senders). let mut steals = unsafe { *self.queue.consumer_addition().steals.get() }; while { - let cnt = self.queue.producer_addition().cnt.compare_and_swap( + match self.queue.producer_addition().cnt.compare_exchange( steals, DISCONNECTED, Ordering::SeqCst, - ); - cnt != DISCONNECTED && cnt != steals + Ordering::SeqCst, + ) { + Ok(_) => false, + Err(old) => old != DISCONNECTED, + } } { while self.queue.pop().is_some() { steals += 1; diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index de5ddf1daf..6a33083448 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -65,7 +65,7 @@ // must do so with Release ordering to make the result available. // - `wait` inserts `Waiter` nodes as a pointer in `state_and_queue`, and // needs to make the nodes available with Release ordering. The load in -// its `compare_and_swap` can be Relaxed because it only has to compare +// its `compare_exchange` can be Relaxed because it only has to compare // the atomic, not to read other data. // - `WaiterQueue::Drop` must see the `Waiter` nodes, so it must load // `state_and_queue` with Acquire ordering. @@ -110,7 +110,7 @@ use crate::thread::{self, Thread}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Once { - // `state_and_queue` is actually an a pointer to a `Waiter` with extra state + // `state_and_queue` is actually a pointer to a `Waiter` with extra state // bits, so we add the `PhantomData` appropriately. state_and_queue: AtomicUsize, _marker: marker::PhantomData<*const Waiter>, @@ -395,12 +395,13 @@ impl Once { } POISONED | INCOMPLETE => { // Try to register this thread as the one RUNNING. - let old = self.state_and_queue.compare_and_swap( + let exchange_result = self.state_and_queue.compare_exchange( state_and_queue, RUNNING, Ordering::Acquire, + Ordering::Acquire, ); - if old != state_and_queue { + if let Err(old) = exchange_result { state_and_queue = old; continue; } @@ -452,8 +453,13 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) { // Try to slide in the node at the head of the linked list, making sure // that another thread didn't just replace the head of the linked list. - let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release); - if old != current_state { + let exchange_result = state_and_queue.compare_exchange( + current_state, + me | RUNNING, + Ordering::Release, + Ordering::Relaxed, + ); + if let Err(old) = exchange_result { current_state = old; continue; } diff --git a/library/std/src/sys/cloudabi/abi/bitflags.rs b/library/std/src/sys/cloudabi/abi/bitflags.rs deleted file mode 100644 index 2383277ad7..0000000000 --- a/library/std/src/sys/cloudabi/abi/bitflags.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -#[cfg(feature = "bitflags")] -use bitflags::bitflags; - -// Minimal implementation of bitflags! in case we can't depend on the bitflags -// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't -// actually truncate. -#[cfg(not(feature = "bitflags"))] -macro_rules! bitflags { - ( - $(#[$attr:meta])* - pub struct $name:ident: $type:ty { - $($(#[$const_attr:meta])* const $const:ident = $val:expr;)* - } - ) => { - $(#[$attr])* - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] - pub struct $name { bits: $type } - impl $name { - $($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)* - pub fn bits(&self) -> $type { self.bits } - pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } } - } - } -} diff --git a/library/std/src/sys/cloudabi/abi/cloudabi.rs b/library/std/src/sys/cloudabi/abi/cloudabi.rs deleted file mode 100644 index d67f0f81a9..0000000000 --- a/library/std/src/sys/cloudabi/abi/cloudabi.rs +++ /dev/null @@ -1,2954 +0,0 @@ -// Copyright (c) 2016-2017 Nuxi and contributors. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// -// This file is automatically generated. Do not edit. -// -// Source: https://github.com/NuxiNL/cloudabi - -// Appease Rust's tidy. -// ignore-tidy-linelength - -//! **PLEASE NOTE: This entire crate including this -//! documentation is automatically generated from -//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt)** -//! -//! # Nuxi CloudABI -//! -//! CloudABI is what you get if you take POSIX, add capability-based -//! security, and remove everything that's incompatible with that. The -//! result is a minimal ABI consisting of only 49 syscalls. -//! -//! CloudABI doesn't have its own kernel, but instead is implemented in existing -//! kernels: FreeBSD has CloudABI support for x86-64 and arm64, and [a patch-set -//! for NetBSD](https://github.com/NuxiNL/netbsd) and [a patch-set for -//! Linux](https://github.com/NuxiNL/linux) are available as well. This means that -//! CloudABI binaries can be executed on different operating systems, without any -//! modification. -//! -//! ## Capability-Based Security -//! -//! Capability-based security means that processes can only perform -//! actions that have no global impact. Processes cannot open files by -//! their absolute path, cannot open network connections, and cannot -//! observe global system state such as the process table. -//! -//! The capabilities of a process are fully determined by its set of open -//! file descriptors (fds). For example, files can only be opened if the -//! process already has a file descriptor to a directory the file is in. -//! -//! Unlike in POSIX, where processes are normally started with file -//! descriptors 0, 1, and 2 reserved for standard input, output, and -//! error, CloudABI does not reserve any file descriptor numbers for -//! specific purposes. -//! -//! In CloudABI, a process depends on its parent process to launch it with -//! the right set of resources, since the process will not be able to open -//! any new resources. For example, a simple static web server would need -//! to be started with a file descriptor to a [TCP -//! listener](https://github.com/NuxiNL/flower), and a file descriptor to -//! the directory for which to serve files. The web server will then be -//! unable to do anything other than reading files in that directory, and -//! process incoming network connections. -//! -//! So, unknown CloudABI binaries can safely be executed without the need -//! for containers, virtual machines, or other sandboxing technologies. -//! -//! Watch [Ed Schouten's Talk at -//! 32C3](https://www.youtube.com/watch?v=3N29vrPoDv8) for more -//! information about what capability-based security for UNIX means. -//! -//! ## Cloudlibc -//! -//! [Cloudlibc](https://github.com/NuxiNL/cloudlibc) is an implementation -//! of the C standard library, without all CloudABI-incompatible -//! functions. For example, Cloudlibc does not have `printf`, but does -//! have `fprintf`. It does not have `open`, but does have `openat`. -//! -//! ## CloudABI-Ports -//! -//! [CloudABI-Ports](https://github.com/NuxiNL/cloudabi-ports) is a -//! collection of ports of commonly used libraries and applications to -//! CloudABI. It contains software such as `zlib`, `libpng`, `boost`, -//! `memcached`, and much more. The software is patched to not depend on -//! any global state, such as files in `/etc` or `/dev`, using `open()`, -//! etc. -//! -//! ## Using CloudABI -//! -//! Instructions for using CloudABI (including kernel modules/patches, -//! toolchain, and ports) are available for several operating systems: -//! -//! - [Arch Linux](https://nuxi.nl/cloudabi/archlinux/) -//! - [Debian, Ubuntu, and other Debian derivatives](https://nuxi.nl/cloudabi/debian/) -//! - [FreeBSD, PC-BSD and DragonFly BSD](https://nuxi.nl/cloudabi/freebsd/) -//! - [Mac OS X](https://nuxi.nl/cloudabi/mac/) -//! - [NetBSD](https://nuxi.nl/cloudabi/netbsd/) -//! -//! ## Specification of the ABI -//! -//! The entire ABI is specified in a file called -//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt), -//! from which all -//! [headers](https://github.com/NuxiNL/cloudabi/tree/master/headers) -//! and documentation (including the one you're reading now) is generated. - -#![no_std] -#![allow(non_camel_case_types)] -#![allow(deprecated)] // FIXME: using `mem::uninitialized()` - -include!("bitflags.rs"); - -/// File or memory access pattern advisory information. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum advice { - /// The application expects that it will not access the - /// specified data in the near future. - DONTNEED = 1, - /// The application expects to access the specified data - /// once and then not reuse it thereafter. - NOREUSE = 2, - /// The application has no advice to give on its behavior - /// with respect to the specified data. - NORMAL = 3, - /// The application expects to access the specified data - /// in a random order. - RANDOM = 4, - /// The application expects to access the specified data - /// sequentially from lower offsets to higher offsets. - SEQUENTIAL = 5, - /// The application expects to access the specified data - /// in the near future. - WILLNEED = 6, -} - -/// Enumeration describing the kind of value stored in [`auxv`]. -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum auxtype { - /// Base address of the binary argument data provided to - /// [`proc_exec()`](fn.proc_exec.html). - ARGDATA = 256, - /// Length of the binary argument data provided to - /// [`proc_exec()`](fn.proc_exec.html). - ARGDATALEN = 257, - /// Base address at which the executable is placed in - /// memory. - BASE = 7, - /// Base address of a buffer of random data that may be - /// used for non-cryptographic purposes, for example as a - /// canary for stack smashing protection. - CANARY = 258, - /// Length of a buffer of random data that may be used - /// for non-cryptographic purposes, for example as a - /// canary for stack smashing protection. - CANARYLEN = 259, - /// Number of CPUs that the system this process is running - /// on has. - NCPUS = 260, - /// Terminator of the auxiliary vector. - NULL = 0, - /// Smallest memory object size for which individual - /// memory protection controls can be configured. - PAGESZ = 6, - /// Address of the first ELF program header of the - /// executable. - PHDR = 3, - /// Number of ELF program headers of the executable. - PHNUM = 4, - /// Identifier of the process. - /// - /// This environment does not provide any simple numerical - /// process identifiers, for the reason that these are not - /// useful in distributed contexts. Instead, processes are - /// identified by a UUID. - /// - /// This record should point to sixteen bytes of binary - /// data, containing a version 4 UUID (fully random). - PID = 263, - /// Address of the ELF header of the vDSO. - /// - /// The vDSO is a shared library that is mapped in the - /// address space of the process. It provides entry points - /// for every system call supported by the environment, - /// all having a corresponding symbol that is prefixed - /// with `cloudabi_sys_`. System calls should be invoked - /// through these entry points. - /// - /// The first advantage of letting processes call into a - /// vDSO to perform system calls instead of raising - /// hardware traps is that it allows for easy emulation of - /// executables on top of existing operating systems. The - /// second advantage is that in cases where an operating - /// system provides native support for CloudABI executables, - /// it may still implement partial userspace - /// implementations of these system calls to improve - /// performance (e.g., [`clock_time_get()`](fn.clock_time_get.html)). It also provides - /// a more dynamic way of adding, removing or replacing - /// system calls. - SYSINFO_EHDR = 262, - /// Thread ID of the initial thread of the process. - TID = 261, -} - -/// Identifiers for clocks. -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum clockid { - /// The system-wide monotonic clock, which is defined as a - /// clock measuring real time, whose value cannot be - /// adjusted and which cannot have negative clock jumps. - /// - /// The epoch of this clock is undefined. The absolute - /// time value of this clock therefore has no meaning. - MONOTONIC = 1, - /// The CPU-time clock associated with the current - /// process. - PROCESS_CPUTIME_ID = 2, - /// The system-wide clock measuring real time. Time value - /// zero corresponds with 1970-01-01T00:00:00Z. - REALTIME = 3, - /// The CPU-time clock associated with the current thread. - THREAD_CPUTIME_ID = 4, -} - -/// A userspace condition variable. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct condvar(pub u32); -/// The condition variable is in its initial state. There -/// are no threads waiting to be woken up. If the -/// condition variable has any other value, the kernel -/// must be called to wake up any sleeping threads. -pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0); - -/// Identifier for a device containing a file system. Can be used -/// in combination with [`inode`] to uniquely identify a file on the -/// local system. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct device(pub u64); - -/// A reference to the offset of a directory entry. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct dircookie(pub u64); -/// Permanent reference to the first directory entry -/// within a directory. -pub const DIRCOOKIE_START: dircookie = dircookie(0); - -/// Error codes returned by system calls. -/// -/// Not all of these error codes are returned by the system calls -/// provided by this environment, but are either used in userspace -/// exclusively or merely provided for alignment with POSIX. -#[repr(u16)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum errno { - /// No error occurred. System call completed successfully. - SUCCESS = 0, - /// Argument list too long. - TOOBIG = 1, - /// Permission denied. - ACCES = 2, - /// Address in use. - ADDRINUSE = 3, - /// Address not available. - ADDRNOTAVAIL = 4, - /// Address family not supported. - AFNOSUPPORT = 5, - /// Resource unavailable, or operation would block. - AGAIN = 6, - /// Connection already in progress. - ALREADY = 7, - /// Bad file descriptor. - BADF = 8, - /// Bad message. - BADMSG = 9, - /// Device or resource busy. - BUSY = 10, - /// Operation canceled. - CANCELED = 11, - /// No child processes. - CHILD = 12, - /// Connection aborted. - CONNABORTED = 13, - /// Connection refused. - CONNREFUSED = 14, - /// Connection reset. - CONNRESET = 15, - /// Resource deadlock would occur. - DEADLK = 16, - /// Destination address required. - DESTADDRREQ = 17, - /// Mathematics argument out of domain of function. - DOM = 18, - /// Reserved. - DQUOT = 19, - /// File exists. - EXIST = 20, - /// Bad address. - FAULT = 21, - /// File too large. - FBIG = 22, - /// Host is unreachable. - HOSTUNREACH = 23, - /// Identifier removed. - IDRM = 24, - /// Illegal byte sequence. - ILSEQ = 25, - /// Operation in progress. - INPROGRESS = 26, - /// Interrupted function. - INTR = 27, - /// Invalid argument. - INVAL = 28, - /// I/O error. - IO = 29, - /// Socket is connected. - ISCONN = 30, - /// Is a directory. - ISDIR = 31, - /// Too many levels of symbolic links. - LOOP = 32, - /// File descriptor value too large. - MFILE = 33, - /// Too many links. - MLINK = 34, - /// Message too large. - MSGSIZE = 35, - /// Reserved. - MULTIHOP = 36, - /// Filename too long. - NAMETOOLONG = 37, - /// Network is down. - NETDOWN = 38, - /// Connection aborted by network. - NETRESET = 39, - /// Network unreachable. - NETUNREACH = 40, - /// Too many files open in system. - NFILE = 41, - /// No buffer space available. - NOBUFS = 42, - /// No such device. - NODEV = 43, - /// No such file or directory. - NOENT = 44, - /// Executable file format error. - NOEXEC = 45, - /// No locks available. - NOLCK = 46, - /// Reserved. - NOLINK = 47, - /// Not enough space. - NOMEM = 48, - /// No message of the desired type. - NOMSG = 49, - /// Protocol not available. - NOPROTOOPT = 50, - /// No space left on device. - NOSPC = 51, - /// Function not supported. - NOSYS = 52, - /// The socket is not connected. - NOTCONN = 53, - /// Not a directory or a symbolic link to a directory. - NOTDIR = 54, - /// Directory not empty. - NOTEMPTY = 55, - /// State not recoverable. - NOTRECOVERABLE = 56, - /// Not a socket. - NOTSOCK = 57, - /// Not supported, or operation not supported on socket. - NOTSUP = 58, - /// Inappropriate I/O control operation. - NOTTY = 59, - /// No such device or address. - NXIO = 60, - /// Value too large to be stored in data type. - OVERFLOW = 61, - /// Previous owner died. - OWNERDEAD = 62, - /// Operation not permitted. - PERM = 63, - /// Broken pipe. - PIPE = 64, - /// Protocol error. - PROTO = 65, - /// Protocol not supported. - PROTONOSUPPORT = 66, - /// Protocol wrong type for socket. - PROTOTYPE = 67, - /// Result too large. - RANGE = 68, - /// Read-only file system. - ROFS = 69, - /// Invalid seek. - SPIPE = 70, - /// No such process. - SRCH = 71, - /// Reserved. - STALE = 72, - /// Connection timed out. - TIMEDOUT = 73, - /// Text file busy. - TXTBSY = 74, - /// Cross-device link. - XDEV = 75, - /// Extension: Capabilities insufficient. - NOTCAPABLE = 76, -} - -bitflags! { - /// The state of the file descriptor subscribed to with - /// [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - #[repr(C)] - pub struct eventrwflags: u16 { - /// The peer of this socket has closed or disconnected. - const HANGUP = 0x0001; - } -} - -/// Type of a subscription to an event or its occurrence. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum eventtype { - /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id) - /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout). - CLOCK = 1, - /// Condition variable [`subscription.union.condvar.condvar`](struct.subscription_condvar.html#structfield.condvar) has - /// been woken up and [`subscription.union.condvar.lock`](struct.subscription_condvar.html#structfield.lock) has been - /// acquired for writing. - CONDVAR = 2, - /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has - /// data available for reading. This event always triggers - /// for regular files. - FD_READ = 3, - /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has - /// capacity available for writing. This event always - /// triggers for regular files. - FD_WRITE = 4, - /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for - /// reading. - LOCK_RDLOCK = 5, - /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for - /// writing. - LOCK_WRLOCK = 6, - /// The process associated with process descriptor - /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated. - PROC_TERMINATE = 7, -} - -/// Exit code generated by a process when exiting. -pub type exitcode = u32; - -/// A file descriptor number. -/// -/// Unlike on POSIX-compliant systems, none of the file descriptor -/// numbers are reserved for a purpose (e.g., stdin, stdout, -/// stderr). Operating systems are not required to allocate new -/// file descriptors in ascending order. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct fd(pub u32); -/// Returned to the child process by [`proc_fork()`](fn.proc_fork.html). -pub const PROCESS_CHILD: fd = fd(0xffffffff); -/// Passed to [`mem_map()`](fn.mem_map.html) when creating a mapping to -/// anonymous memory. -pub const MAP_ANON_FD: fd = fd(0xffffffff); - -bitflags! { - /// File descriptor flags. - #[repr(C)] - pub struct fdflags: u16 { - /// Append mode: Data written to the file is always - /// appended to the file's end. - const APPEND = 0x0001; - /// Write according to synchronized I/O data integrity - /// completion. Only the data stored in the file is - /// synchronized. - const DSYNC = 0x0002; - /// Non-blocking mode. - const NONBLOCK = 0x0004; - /// Synchronized read I/O operations. - const RSYNC = 0x0008; - /// Write according to synchronized I/O file integrity - /// completion. In addition to synchronizing the data - /// stored in the file, the system may also synchronously - /// update the file's metadata. - const SYNC = 0x0010; - } -} - -bitflags! { - /// Which file descriptor attributes to adjust. - #[repr(C)] - pub struct fdsflags: u16 { - /// Adjust the file descriptor flags stored in - /// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags). - const FLAGS = 0x0001; - /// Restrict the rights of the file descriptor to the - /// rights stored in [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and - /// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting). - const RIGHTS = 0x0002; - } -} - -/// Relative offset within a file. -pub type filedelta = i64; - -/// Non-negative file size or length of a region within a file. -pub type filesize = u64; - -/// The type of a file descriptor or file. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum filetype { - /// The type of the file descriptor or file is unknown or - /// is different from any of the other types specified. - UNKNOWN = 0, - /// The file descriptor or file refers to a block device - /// inode. - BLOCK_DEVICE = 16, - /// The file descriptor or file refers to a character - /// device inode. - CHARACTER_DEVICE = 17, - /// The file descriptor or file refers to a directory - /// inode. - DIRECTORY = 32, - /// The file descriptor refers to a process handle. - PROCESS = 80, - /// The file descriptor or file refers to a regular file - /// inode. - REGULAR_FILE = 96, - /// The file descriptor refers to a shared memory object. - SHARED_MEMORY = 112, - /// The file descriptor or file refers to a datagram - /// socket. - SOCKET_DGRAM = 128, - /// The file descriptor or file refers to a byte-stream - /// socket. - SOCKET_STREAM = 130, - /// The file refers to a symbolic link inode. - SYMBOLIC_LINK = 144, -} - -bitflags! { - /// Which file attributes to adjust. - #[repr(C)] - pub struct fsflags: u16 { - /// Adjust the last data access timestamp to the value - /// stored in [`filestat.st_atim`](struct.filestat.html#structfield.st_atim). - const ATIM = 0x0001; - /// Adjust the last data access timestamp to the time - /// of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). - const ATIM_NOW = 0x0002; - /// Adjust the last data modification timestamp to the - /// value stored in [`filestat.st_mtim`](struct.filestat.html#structfield.st_mtim). - const MTIM = 0x0004; - /// Adjust the last data modification timestamp to the - /// time of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). - const MTIM_NOW = 0x0008; - /// Truncate or extend the file to the size stored in - /// [`filestat.st_size`](struct.filestat.html#structfield.st_size). - const SIZE = 0x0010; - } -} - -/// File serial number that is unique within its file system. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct inode(pub u64); - -/// Number of hard links to an inode. -pub type linkcount = u32; - -/// A userspace read-recursive readers-writer lock, similar to a -/// Linux futex or a FreeBSD umtx. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct lock(pub u32); -/// Value indicating that the lock is in its initial -/// unlocked state. -pub const LOCK_UNLOCKED: lock = lock(0x00000000); -/// Bitmask indicating that the lock is write-locked. If -/// set, the lower 30 bits of the lock contain the -/// identifier of the thread that owns the write lock. -/// Otherwise, the lower 30 bits of the lock contain the -/// number of acquired read locks. -pub const LOCK_WRLOCKED: lock = lock(0x40000000); -/// Bitmask indicating that the lock is either read locked -/// or write locked, and that one or more threads have -/// their execution suspended, waiting to acquire the -/// lock. The last owner of the lock must call the -/// kernel to unlock. -/// -/// When the lock is acquired for reading and this bit is -/// set, it means that one or more threads are attempting -/// to acquire this lock for writing. In that case, other -/// threads should only acquire additional read locks if -/// suspending execution would cause a deadlock. It is -/// preferred to suspend execution, as this prevents -/// starvation of writers. -pub const LOCK_KERNEL_MANAGED: lock = lock(0x80000000); -/// Value indicating that the lock is in an incorrect -/// state. A lock cannot be in its initial unlocked state, -/// while also managed by the kernel. -pub const LOCK_BOGUS: lock = lock(0x80000000); - -bitflags! { - /// Flags determining the method of how paths are resolved. - #[repr(C)] - pub struct lookupflags: u32 { - /// As long as the resolved path corresponds to a symbolic - /// link, it is expanded. - const SYMLINK_FOLLOW = 0x00000001; - } -} - -bitflags! { - /// Memory mapping flags. - #[repr(C)] - pub struct mflags: u8 { - /// Instead of mapping the contents of the file provided, - /// create a mapping to anonymous memory. The file - /// descriptor argument must be set to [`MAP_ANON_FD`](constant.MAP_ANON_FD.html), - /// and the offset must be set to zero. - const ANON = 0x01; - /// Require that the mapping is performed at the base - /// address provided. - const FIXED = 0x02; - /// Changes are private. - const PRIVATE = 0x04; - /// Changes are shared. - const SHARED = 0x08; - } -} - -bitflags! { - /// Memory page protection options. - /// - /// This implementation enforces the `W^X` property: Pages cannot be - /// mapped for execution while also mapped for writing. - #[repr(C)] - pub struct mprot: u8 { - /// Page can be executed. - const EXEC = 0x01; - /// Page can be written. - const WRITE = 0x02; - /// Page can be read. - const READ = 0x04; - } -} - -bitflags! { - /// Methods of synchronizing memory with physical storage. - #[repr(C)] - pub struct msflags: u8 { - /// Performs asynchronous writes. - const ASYNC = 0x01; - /// Invalidates cached data. - const INVALIDATE = 0x02; - /// Performs synchronous writes. - const SYNC = 0x04; - } -} - -/// Specifies the number of threads sleeping on a condition -/// variable that should be woken up. -pub type nthreads = u32; - -bitflags! { - /// Open flags used by [`file_open()`](fn.file_open.html). - #[repr(C)] - pub struct oflags: u16 { - /// Create file if it does not exist. - const CREAT = 0x0001; - /// Fail if not a directory. - const DIRECTORY = 0x0002; - /// Fail if file already exists. - const EXCL = 0x0004; - /// Truncate file to size 0. - const TRUNC = 0x0008; - } -} - -bitflags! { - /// Flags provided to [`sock_recv()`](fn.sock_recv.html). - #[repr(C)] - pub struct riflags: u16 { - /// Returns the message without removing it from the - /// socket's receive queue. - const PEEK = 0x0004; - /// On byte-stream sockets, block until the full amount - /// of data can be returned. - const WAITALL = 0x0010; - } -} - -bitflags! { - /// File descriptor rights, determining which actions may be - /// performed. - #[repr(C)] - pub struct rights: u64 { - /// The right to invoke [`fd_datasync()`](fn.fd_datasync.html). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). - const FD_DATASYNC = 0x0000000000000001; - /// The right to invoke [`fd_read()`](fn.fd_read.html) and [`sock_recv()`](fn.sock_recv.html). - /// - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to - /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option - /// [`READ`](struct.mprot.html#associatedconstant.READ). - /// - /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to invoke - /// [`fd_pread()`](fn.fd_pread.html). - const FD_READ = 0x0000000000000002; - /// The right to invoke [`fd_seek()`](fn.fd_seek.html). This flag implies - /// [`FD_TELL`](struct.rights.html#associatedconstant.FD_TELL). - const FD_SEEK = 0x0000000000000004; - /// The right to invoke [`fd_stat_put()`](fn.fd_stat_put.html) with - /// [`FLAGS`](struct.fdsflags.html#associatedconstant.FLAGS). - const FD_STAT_PUT_FLAGS = 0x0000000000000008; - /// The right to invoke [`fd_sync()`](fn.fd_sync.html). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`RSYNC`](struct.fdflags.html#associatedconstant.RSYNC) and - /// [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). - const FD_SYNC = 0x0000000000000010; - /// The right to invoke [`fd_seek()`](fn.fd_seek.html) in such a way that the - /// file offset remains unaltered (i.e., [`CUR`](enum.whence.html#variant.CUR) with - /// offset zero). - const FD_TELL = 0x0000000000000020; - /// The right to invoke [`fd_write()`](fn.fd_write.html) and [`sock_send()`](fn.sock_send.html). - /// - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to - /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option - /// [`WRITE`](struct.mprot.html#associatedconstant.WRITE). - /// - /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to - /// invoke [`fd_pwrite()`](fn.fd_pwrite.html). - const FD_WRITE = 0x0000000000000040; - /// The right to invoke [`file_advise()`](fn.file_advise.html). - const FILE_ADVISE = 0x0000000000000080; - /// The right to invoke [`file_allocate()`](fn.file_allocate.html). - const FILE_ALLOCATE = 0x0000000000000100; - /// The right to invoke [`file_create()`](fn.file_create.html) with - /// [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY). - const FILE_CREATE_DIRECTORY = 0x0000000000000200; - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, the right to invoke - /// [`file_open()`](fn.file_open.html) with [`CREAT`](struct.oflags.html#associatedconstant.CREAT). - const FILE_CREATE_FILE = 0x0000000000000400; - /// The right to invoke [`file_link()`](fn.file_link.html) with the file - /// descriptor as the source directory. - const FILE_LINK_SOURCE = 0x0000000000001000; - /// The right to invoke [`file_link()`](fn.file_link.html) with the file - /// descriptor as the target directory. - const FILE_LINK_TARGET = 0x0000000000002000; - /// The right to invoke [`file_open()`](fn.file_open.html). - const FILE_OPEN = 0x0000000000004000; - /// The right to invoke [`file_readdir()`](fn.file_readdir.html). - const FILE_READDIR = 0x0000000000008000; - /// The right to invoke [`file_readlink()`](fn.file_readlink.html). - const FILE_READLINK = 0x0000000000010000; - /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file - /// descriptor as the source directory. - const FILE_RENAME_SOURCE = 0x0000000000020000; - /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file - /// descriptor as the target directory. - const FILE_RENAME_TARGET = 0x0000000000040000; - /// The right to invoke [`file_stat_fget()`](fn.file_stat_fget.html). - const FILE_STAT_FGET = 0x0000000000080000; - /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with - /// [`SIZE`](struct.fsflags.html#associatedconstant.SIZE). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`TRUNC`](struct.oflags.html#associatedconstant.TRUNC). - const FILE_STAT_FPUT_SIZE = 0x0000000000100000; - /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with - /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), - /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). - const FILE_STAT_FPUT_TIMES = 0x0000000000200000; - /// The right to invoke [`file_stat_get()`](fn.file_stat_get.html). - const FILE_STAT_GET = 0x0000000000400000; - /// The right to invoke [`file_stat_put()`](fn.file_stat_put.html) with - /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), - /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). - const FILE_STAT_PUT_TIMES = 0x0000000000800000; - /// The right to invoke [`file_symlink()`](fn.file_symlink.html). - const FILE_SYMLINK = 0x0000000001000000; - /// The right to invoke [`file_unlink()`](fn.file_unlink.html). - const FILE_UNLINK = 0x0000000002000000; - /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`] set to - /// zero. - const MEM_MAP = 0x0000000004000000; - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke - /// [`mem_map()`](fn.mem_map.html) with [`EXEC`](struct.mprot.html#associatedconstant.EXEC). - const MEM_MAP_EXEC = 0x0000000008000000; - /// If [`FD_READ`](struct.rights.html#associatedconstant.FD_READ) is set, includes the right to - /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_READ`](enum.eventtype.html#variant.FD_READ). - /// - /// If [`FD_WRITE`](struct.rights.html#associatedconstant.FD_WRITE) is set, includes the right to - /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - const POLL_FD_READWRITE = 0x0000000010000000; - /// The right to invoke [`poll()`](fn.poll.html) to subscribe to - /// [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - const POLL_PROC_TERMINATE = 0x0000000040000000; - /// The right to invoke [`proc_exec()`](fn.proc_exec.html). - const PROC_EXEC = 0x0000000100000000; - /// The right to invoke [`sock_shutdown()`](fn.sock_shutdown.html). - const SOCK_SHUTDOWN = 0x0000008000000000; - } -} - -bitflags! { - /// Flags returned by [`sock_recv()`](fn.sock_recv.html). - #[repr(C)] - pub struct roflags: u16 { - /// Returned by [`sock_recv()`](fn.sock_recv.html): List of file descriptors - /// has been truncated. - const FDS_TRUNCATED = 0x0001; - /// Returned by [`sock_recv()`](fn.sock_recv.html): Message data has been - /// truncated. - const DATA_TRUNCATED = 0x0008; - } -} - -/// Indicates whether an object is stored in private or shared -/// memory. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum scope { - /// The object is stored in private memory. - PRIVATE = 4, - /// The object is stored in shared memory. - SHARED = 8, -} - -bitflags! { - /// Which channels on a socket need to be shut down. - #[repr(C)] - pub struct sdflags: u8 { - /// Disables further receive operations. - const RD = 0x01; - /// Disables further send operations. - const WR = 0x02; - } -} - -bitflags! { - /// Flags provided to [`sock_send()`](fn.sock_send.html). As there are currently no flags - /// defined, it must be set to zero. - #[repr(C)] - pub struct siflags: u16 { - const DEFAULT = 0; - } -} - -/// Signal condition. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum signal { - /// Process abort signal. - /// - /// Action: Terminates the process. - ABRT = 1, - /// Alarm clock. - /// - /// Action: Terminates the process. - ALRM = 2, - /// Access to an undefined portion of a memory object. - /// - /// Action: Terminates the process. - BUS = 3, - /// Child process terminated, stopped, or continued. - /// - /// Action: Ignored. - CHLD = 4, - /// Continue executing, if stopped. - /// - /// Action: Continues executing, if stopped. - CONT = 5, - /// Erroneous arithmetic operation. - /// - /// Action: Terminates the process. - FPE = 6, - /// Hangup. - /// - /// Action: Terminates the process. - HUP = 7, - /// Illegal instruction. - /// - /// Action: Terminates the process. - ILL = 8, - /// Terminate interrupt signal. - /// - /// Action: Terminates the process. - INT = 9, - /// Kill. - /// - /// Action: Terminates the process. - KILL = 10, - /// Write on a pipe with no one to read it. - /// - /// Action: Ignored. - PIPE = 11, - /// Terminal quit signal. - /// - /// Action: Terminates the process. - QUIT = 12, - /// Invalid memory reference. - /// - /// Action: Terminates the process. - SEGV = 13, - /// Stop executing. - /// - /// Action: Stops executing. - STOP = 14, - /// Bad system call. - /// - /// Action: Terminates the process. - SYS = 15, - /// Termination signal. - /// - /// Action: Terminates the process. - TERM = 16, - /// Trace/breakpoint trap. - /// - /// Action: Terminates the process. - TRAP = 17, - /// Terminal stop signal. - /// - /// Action: Stops executing. - TSTP = 18, - /// Background process attempting read. - /// - /// Action: Stops executing. - TTIN = 19, - /// Background process attempting write. - /// - /// Action: Stops executing. - TTOU = 20, - /// High bandwidth data is available at a socket. - /// - /// Action: Ignored. - URG = 21, - /// User-defined signal 1. - /// - /// Action: Terminates the process. - USR1 = 22, - /// User-defined signal 2. - /// - /// Action: Terminates the process. - USR2 = 23, - /// Virtual timer expired. - /// - /// Action: Terminates the process. - VTALRM = 24, - /// CPU time limit exceeded. - /// - /// Action: Terminates the process. - XCPU = 25, - /// File size limit exceeded. - /// - /// Action: Terminates the process. - XFSZ = 26, -} - -bitflags! { - /// Flags determining how the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) should be interpreted. - #[repr(C)] - pub struct subclockflags: u16 { - /// If set, treat the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) as an absolute timestamp - /// of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). - /// - /// If clear, treat the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) relative to the current - /// time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). - const ABSTIME = 0x0001; - } -} - -bitflags! { - /// Flags influencing the method of polling for read or writing on - /// a file descriptor. - #[repr(C)] - pub struct subrwflags: u16 { - /// Deprecated. Must be set by callers and ignored by - /// implementations. - const POLL = 0x0001; - } -} - -/// Unique system-local identifier of a thread. This identifier is -/// only valid during the lifetime of the thread. -/// -/// Threads must be aware of their thread identifier, as it is -/// written it into locks when acquiring them for writing. It is -/// not advised to use these identifiers for any other purpose. -/// -/// As the thread identifier is also stored in [`lock`] when -/// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread -/// must always be set to zero. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct tid(pub u32); - -/// Timestamp in nanoseconds. -pub type timestamp = u64; - -bitflags! { - /// Specifies whether files are unlinked or directories are - /// removed. - #[repr(C)] - pub struct ulflags: u8 { - /// If set, removes a directory. Otherwise, unlinks any - /// non-directory file. - const REMOVEDIR = 0x01; - } -} - -/// User-provided value that can be attached to objects that is -/// retained when extracted from the kernel. -pub type userdata = u64; - -/// Relative to which position the offset of the file descriptor -/// should be set. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum whence { - /// Seek relative to current position. - CUR = 1, - /// Seek relative to end-of-file. - END = 2, - /// Seek relative to start-of-file. - SET = 3, -} - -/// Auxiliary vector entry. -/// -/// The auxiliary vector is a list of key-value pairs that is -/// provided to the process on startup. Unlike structures, it is -/// extensible, as it is possible to add new records later on. -/// The auxiliary vector is always terminated by an entry having -/// type [`NULL`](enum.auxtype.html#variant.NULL). -/// -/// The auxiliary vector is part of the x86-64 ABI, but is used by -/// this environment on all architectures. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct auxv { - /// The type of the auxiliary vector entry. - pub a_type: auxtype, - pub union: auxv_union, -} -/// A union inside `auxv`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union auxv_union { - /// Used when `a_type` is [`ARGDATALEN`](enum.auxtype.html#variant.ARGDATALEN), [`CANARYLEN`](enum.auxtype.html#variant.CANARYLEN), [`NCPUS`](enum.auxtype.html#variant.NCPUS), [`PAGESZ`](enum.auxtype.html#variant.PAGESZ), [`PHNUM`](enum.auxtype.html#variant.PHNUM), or [`TID`](enum.auxtype.html#variant.TID). - /// A numerical value. - pub a_val: usize, - /// Used when `a_type` is [`ARGDATA`](enum.auxtype.html#variant.ARGDATA), [`BASE`](enum.auxtype.html#variant.BASE), [`CANARY`](enum.auxtype.html#variant.CANARY), [`PHDR`](enum.auxtype.html#variant.PHDR), [`PID`](enum.auxtype.html#variant.PID), or [`SYSINFO_EHDR`](enum.auxtype.html#variant.SYSINFO_EHDR). - /// A pointer value. - pub a_ptr: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn auxv_layout_test_32() { - assert_eq!(core::mem::size_of::(), 8); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: auxv = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.a_type as *const _ as usize - base, 0); - assert_eq!(&obj.union.a_val as *const _ as usize - base, 4); - assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn auxv_layout_test_64() { - assert_eq!(core::mem::size_of::(), 16); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: auxv = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.a_type as *const _ as usize - base, 0); - assert_eq!(&obj.union.a_val as *const _ as usize - base, 8); - assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 8); - } -} - -/// A region of memory for scatter/gather writes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ciovec { - /// The address and length of the buffer to be written. - pub buf: (*const (), usize), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn ciovec_layout_test_32() { - assert_eq!(core::mem::size_of::(), 8); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: ciovec = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn ciovec_layout_test_64() { - assert_eq!(core::mem::size_of::(), 16); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: ciovec = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); - } -} - -/// A directory entry. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct dirent { - /// The offset of the next directory entry stored in this - /// directory. - pub d_next: dircookie, - /// The serial number of the file referred to by this - /// directory entry. - pub d_ino: inode, - /// The length of the name of the directory entry. - pub d_namlen: u32, - /// The type of the file referred to by this directory - /// entry. - pub d_type: filetype, -} -#[test] -fn dirent_layout_test() { - assert_eq!(core::mem::size_of::(), 24); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: dirent = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.d_next as *const _ as usize - base, 0); - assert_eq!(&obj.d_ino as *const _ as usize - base, 8); - assert_eq!(&obj.d_namlen as *const _ as usize - base, 16); - assert_eq!(&obj.d_type as *const _ as usize - base, 20); - } -} - -/// An event that occurred. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event { - /// User-provided value that got attached to - /// [`subscription.userdata`](struct.subscription.html#structfield.userdata). - pub userdata: userdata, - /// If non-zero, an error that occurred while processing - /// the subscription request. - pub error: errno, - /// The type of the event that occurred. - pub type_: eventtype, - pub union: event_union, -} -/// A union inside `event`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union event_union { - /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - pub fd_readwrite: event_fd_readwrite, - /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - pub proc_terminate: event_proc_terminate, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event_fd_readwrite { - /// The number of bytes available - /// for reading or writing. - pub nbytes: filesize, - /// Obsolete. - pub unused: [u8; 4], - /// The state of the file - /// descriptor. - pub flags: eventrwflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event_proc_terminate { - /// Obsolete. - pub unused: [u8; 4], - /// If zero, the process has - /// exited. - /// Otherwise, the signal - /// condition causing it to - /// terminated. - pub signal: signal, - /// If exited, the exit code of - /// the process. - pub exitcode: exitcode, -} -#[test] -fn event_layout_test() { - assert_eq!(core::mem::size_of::(), 32); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: event = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.error as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.fd_readwrite.nbytes as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.unused as *const _ as usize - base, 24); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 28); - assert_eq!(&obj.union.proc_terminate.unused as *const _ as usize - base, 16); - assert_eq!(&obj.union.proc_terminate.signal as *const _ as usize - base, 20); - assert_eq!(&obj.union.proc_terminate.exitcode as *const _ as usize - base, 24); - } -} - -/// File descriptor attributes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct fdstat { - /// File type. - pub fs_filetype: filetype, - /// File descriptor flags. - pub fs_flags: fdflags, - /// Rights that apply to this file descriptor. - pub fs_rights_base: rights, - /// Maximum set of rights that can be installed on new - /// file descriptors that are created through this file - /// descriptor, e.g., through [`file_open()`](fn.file_open.html). - pub fs_rights_inheriting: rights, -} -#[test] -fn fdstat_layout_test() { - assert_eq!(core::mem::size_of::(), 24); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: fdstat = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.fs_filetype as *const _ as usize - base, 0); - assert_eq!(&obj.fs_flags as *const _ as usize - base, 2); - assert_eq!(&obj.fs_rights_base as *const _ as usize - base, 8); - assert_eq!(&obj.fs_rights_inheriting as *const _ as usize - base, 16); - } -} - -/// File attributes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct filestat { - /// Device ID of device containing the file. - pub st_dev: device, - /// File serial number. - pub st_ino: inode, - /// File type. - pub st_filetype: filetype, - /// Number of hard links to the file. - pub st_nlink: linkcount, - /// For regular files, the file size in bytes. For - /// symbolic links, the length in bytes of the pathname - /// contained in the symbolic link. - pub st_size: filesize, - /// Last data access timestamp. - pub st_atim: timestamp, - /// Last data modification timestamp. - pub st_mtim: timestamp, - /// Last file status change timestamp. - pub st_ctim: timestamp, -} -#[test] -fn filestat_layout_test() { - assert_eq!(core::mem::size_of::(), 56); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: filestat = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.st_dev as *const _ as usize - base, 0); - assert_eq!(&obj.st_ino as *const _ as usize - base, 8); - assert_eq!(&obj.st_filetype as *const _ as usize - base, 16); - assert_eq!(&obj.st_nlink as *const _ as usize - base, 20); - assert_eq!(&obj.st_size as *const _ as usize - base, 24); - assert_eq!(&obj.st_atim as *const _ as usize - base, 32); - assert_eq!(&obj.st_mtim as *const _ as usize - base, 40); - assert_eq!(&obj.st_ctim as *const _ as usize - base, 48); - } -} - -/// A region of memory for scatter/gather reads. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct iovec { - /// The address and length of the buffer to be filled. - pub buf: (*mut (), usize), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn iovec_layout_test_32() { - assert_eq!(core::mem::size_of::(), 8); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: iovec = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn iovec_layout_test_64() { - assert_eq!(core::mem::size_of::(), 16); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: iovec = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); - } -} - -/// Path lookup properties. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct lookup { - /// The working directory at which the resolution of the - /// path starts. - pub fd: fd, - /// Flags determining the method of how the path is - /// resolved. - pub flags: lookupflags, -} -#[test] -fn lookup_layout_test() { - assert_eq!(core::mem::size_of::(), 8); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: lookup = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.fd as *const _ as usize - base, 0); - assert_eq!(&obj.flags as *const _ as usize - base, 4); - } -} - -/// Entry point for a process (`_start`). -/// -/// **auxv**: -/// The auxiliary vector. See [`auxv`]. -pub type processentry = unsafe extern "C" fn(auxv: *const auxv) -> (); - -/// Arguments of [`sock_recv()`](fn.sock_recv.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct recv_in { - /// List of scatter/gather vectors where message data - /// should be stored. - pub ri_data: (*const iovec, usize), - /// Buffer where numbers of incoming file descriptors - /// should be stored. - pub ri_fds: (*mut fd, usize), - /// Message flags. - pub ri_flags: riflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn recv_in_layout_test_32() { - assert_eq!(core::mem::size_of::(), 20); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: recv_in = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 4); - assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 8); - assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 12); - assert_eq!(&obj.ri_flags as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn recv_in_layout_test_64() { - assert_eq!(core::mem::size_of::(), 40); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: recv_in = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 8); - assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 16); - assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 24); - assert_eq!(&obj.ri_flags as *const _ as usize - base, 32); - } -} - -/// Results of [`sock_recv()`](fn.sock_recv.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct recv_out { - /// Number of bytes stored in [`recv_in.ri_data`](struct.recv_in.html#structfield.ri_data). - pub ro_datalen: usize, - /// Number of file descriptors stored in [`recv_in.ri_fds`](struct.recv_in.html#structfield.ri_fds). - pub ro_fdslen: usize, - /// Fields that were used by previous implementations. - pub ro_unused: [u8; 40], - /// Message flags. - pub ro_flags: roflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn recv_out_layout_test_32() { - assert_eq!(core::mem::size_of::(), 52); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: recv_out = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); - assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 4); - assert_eq!(&obj.ro_unused as *const _ as usize - base, 8); - assert_eq!(&obj.ro_flags as *const _ as usize - base, 48); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn recv_out_layout_test_64() { - assert_eq!(core::mem::size_of::(), 64); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: recv_out = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); - assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 8); - assert_eq!(&obj.ro_unused as *const _ as usize - base, 16); - assert_eq!(&obj.ro_flags as *const _ as usize - base, 56); - } -} - -/// Arguments of [`sock_send()`](fn.sock_send.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct send_in { - /// List of scatter/gather vectors where message data - /// should be retrieved. - pub si_data: (*const ciovec, usize), - /// File descriptors that need to be attached to the - /// message. - pub si_fds: (*const fd, usize), - /// Message flags. - pub si_flags: siflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn send_in_layout_test_32() { - assert_eq!(core::mem::size_of::(), 20); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: send_in = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.si_data.1 as *const _ as usize - base, 4); - assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 8); - assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 12); - assert_eq!(&obj.si_flags as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn send_in_layout_test_64() { - assert_eq!(core::mem::size_of::(), 40); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: send_in = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.si_data.1 as *const _ as usize - base, 8); - assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 16); - assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 24); - assert_eq!(&obj.si_flags as *const _ as usize - base, 32); - } -} - -/// Results of [`sock_send()`](fn.sock_send.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct send_out { - /// Number of bytes transmitted. - pub so_datalen: usize, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn send_out_layout_test_32() { - assert_eq!(core::mem::size_of::(), 4); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: send_out = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn send_out_layout_test_64() { - assert_eq!(core::mem::size_of::(), 8); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: send_out = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); - } -} - -/// Subscription to an event. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription { - /// User-provided value that is attached to the - /// subscription in the kernel and returned through - /// [`event.userdata`](struct.event.html#structfield.userdata). - pub userdata: userdata, - /// Used by previous implementations. Ignored. - pub unused: u16, - /// The type of the event to which to subscribe. - /// - /// Currently, [`CONDVAR`](enum.eventtype.html#variant.CONDVAR), - /// [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK), and [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK) - /// must be provided as the first subscription and may - /// only be followed by up to one other subscription, - /// having type [`CLOCK`](enum.eventtype.html#variant.CLOCK). - pub type_: eventtype, - pub union: subscription_union, -} -/// A union inside `subscription`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union subscription_union { - /// Used when `type_` is [`CLOCK`](enum.eventtype.html#variant.CLOCK). - pub clock: subscription_clock, - /// Used when `type_` is [`CONDVAR`](enum.eventtype.html#variant.CONDVAR). - pub condvar: subscription_condvar, - /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - pub fd_readwrite: subscription_fd_readwrite, - /// Used when `type_` is [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK) or [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK). - pub lock: subscription_lock, - /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - pub proc_terminate: subscription_proc_terminate, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_clock { - /// The user-defined unique - /// identifier of the clock. - pub identifier: userdata, - /// The clock against which the - /// timestamp should be compared. - pub clock_id: clockid, - /// The absolute or relative - /// timestamp. - pub timeout: timestamp, - /// The amount of time that the - /// kernel may wait additionally - /// to coalesce with other events. - pub precision: timestamp, - /// Flags specifying whether the - /// timeout is absolute or - /// relative. - pub flags: subclockflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_condvar { - /// The condition variable on - /// which to wait to be woken up. - pub condvar: *mut condvar, - /// The lock that will be - /// released while waiting. - /// - /// The lock will be reacquired - /// for writing when the condition - /// variable triggers. - pub lock: *mut lock, - /// Whether the condition variable - /// is stored in private or shared - /// memory. - pub condvar_scope: scope, - /// Whether the lock is stored in - /// private or shared memory. - pub lock_scope: scope, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_fd_readwrite { - /// The file descriptor on which - /// to wait for it to become ready - /// for reading or writing. - pub fd: fd, - /// Under which conditions to - /// trigger. - pub flags: subrwflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_lock { - /// The lock that will be acquired - /// for reading or writing. - pub lock: *mut lock, - /// Whether the lock is stored in - /// private or shared memory. - pub lock_scope: scope, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_proc_terminate { - /// The process descriptor on - /// which to wait for process - /// termination. - pub fd: fd, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn subscription_layout_test_32() { - assert_eq!(core::mem::size_of::(), 56); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: subscription = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.unused as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); - assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); - assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); - assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); - assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); - assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); - assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 20); - assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 24); - assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 25); - assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); - assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); - assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 20); - assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn subscription_layout_test_64() { - assert_eq!(core::mem::size_of::(), 56); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: subscription = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.unused as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); - assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); - assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); - assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); - assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); - assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); - assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 24); - assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 32); - assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 33); - assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); - assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); - assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 24); - assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); - } -} - -/// The Thread Control Block (TCB). -/// -/// After a thread begins execution (at program startup or when -/// created through [`thread_create()`](fn.thread_create.html)), the CPU's registers -/// controlling Thread-Local Storage (TLS) will already be -/// initialized. They will point to an area only containing the -/// TCB. -/// -/// If the thread needs space for storing thread-specific -/// variables, the thread may allocate a larger area and adjust -/// the CPU's registers to point to that area instead. However, it -/// does need to make sure that the TCB is copied over to the new -/// TLS area. -/// -/// The purpose of the TCB is that it allows light-weight -/// emulators to store information related to individual threads. -/// For example, it may be used to store a copy of the CPU -/// registers prior emulation, so that TLS for the host system -/// can be restored if needed. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct tcb { - /// Pointer that may be freely assigned by the system. Its - /// value cannot be interpreted by the application. - pub parent: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn tcb_layout_test_32() { - assert_eq!(core::mem::size_of::(), 4); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: tcb = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.parent as *const _ as usize - base, 0); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn tcb_layout_test_64() { - assert_eq!(core::mem::size_of::(), 8); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: tcb = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.parent as *const _ as usize - base, 0); - } -} - -/// Entry point for additionally created threads. -/// -/// `tid`: thread ID of the current thread. -/// -/// `aux`: copy of the value stored in -/// [`threadattr.argument`](struct.threadattr.html#structfield.argument). -pub type threadentry = unsafe extern "C" fn(tid: tid, aux: *mut ()) -> (); - -/// Attributes for thread creation. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct threadattr { - /// Initial program counter value. - pub entry_point: threadentry, - /// Region allocated to serve as stack space. - pub stack: (*mut (), usize), - /// Argument to be forwarded to the entry point function. - pub argument: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn threadattr_layout_test_32() { - assert_eq!(core::mem::size_of::(), 16); - assert_eq!(core::mem::align_of::(), 4); - unsafe { - let obj: threadattr = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.entry_point as *const _ as usize - base, 0); - assert_eq!(&obj.stack.0 as *const _ as usize - base, 4); - assert_eq!(&obj.stack.1 as *const _ as usize - base, 8); - assert_eq!(&obj.argument as *const _ as usize - base, 12); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn threadattr_layout_test_64() { - assert_eq!(core::mem::size_of::(), 32); - assert_eq!(core::mem::align_of::(), 8); - unsafe { - let obj: threadattr = core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.entry_point as *const _ as usize - base, 0); - assert_eq!(&obj.stack.0 as *const _ as usize - base, 8); - assert_eq!(&obj.stack.1 as *const _ as usize - base, 16); - assert_eq!(&obj.argument as *const _ as usize - base, 24); - } -} - -/// The table with pointers to all syscall implementations. -#[allow(improper_ctypes)] -extern "C" { - fn cloudabi_sys_clock_res_get(_: clockid, _: *mut timestamp) -> errno; - fn cloudabi_sys_clock_time_get(_: clockid, _: timestamp, _: *mut timestamp) -> errno; - fn cloudabi_sys_condvar_signal(_: *mut condvar, _: scope, _: nthreads) -> errno; - fn cloudabi_sys_fd_close(_: fd) -> errno; - fn cloudabi_sys_fd_create1(_: filetype, _: *mut fd) -> errno; - fn cloudabi_sys_fd_create2(_: filetype, _: *mut fd, _: *mut fd) -> errno; - fn cloudabi_sys_fd_datasync(_: fd) -> errno; - fn cloudabi_sys_fd_dup(_: fd, _: *mut fd) -> errno; - fn cloudabi_sys_fd_pread(_: fd, _: *const iovec, _: usize, _: filesize, _: *mut usize) - -> errno; - fn cloudabi_sys_fd_pwrite( - _: fd, - _: *const ciovec, - _: usize, - _: filesize, - _: *mut usize, - ) -> errno; - fn cloudabi_sys_fd_read(_: fd, _: *const iovec, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_fd_replace(_: fd, _: fd) -> errno; - fn cloudabi_sys_fd_seek(_: fd, _: filedelta, _: whence, _: *mut filesize) -> errno; - fn cloudabi_sys_fd_stat_get(_: fd, _: *mut fdstat) -> errno; - fn cloudabi_sys_fd_stat_put(_: fd, _: *const fdstat, _: fdsflags) -> errno; - fn cloudabi_sys_fd_sync(_: fd) -> errno; - fn cloudabi_sys_fd_write(_: fd, _: *const ciovec, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_file_advise(_: fd, _: filesize, _: filesize, _: advice) -> errno; - fn cloudabi_sys_file_allocate(_: fd, _: filesize, _: filesize) -> errno; - fn cloudabi_sys_file_create(_: fd, _: *const u8, _: usize, _: filetype) -> errno; - fn cloudabi_sys_file_link( - _: lookup, - _: *const u8, - _: usize, - _: fd, - _: *const u8, - _: usize, - ) -> errno; - fn cloudabi_sys_file_open( - _: lookup, - _: *const u8, - _: usize, - _: oflags, - _: *const fdstat, - _: *mut fd, - ) -> errno; - fn cloudabi_sys_file_readdir(_: fd, _: *mut (), _: usize, _: dircookie, _: *mut usize) - -> errno; - fn cloudabi_sys_file_readlink( - _: fd, - _: *const u8, - _: usize, - _: *mut u8, - _: usize, - _: *mut usize, - ) -> errno; - fn cloudabi_sys_file_rename( - _: fd, - _: *const u8, - _: usize, - _: fd, - _: *const u8, - _: usize, - ) -> errno; - fn cloudabi_sys_file_stat_fget(_: fd, _: *mut filestat) -> errno; - fn cloudabi_sys_file_stat_fput(_: fd, _: *const filestat, _: fsflags) -> errno; - fn cloudabi_sys_file_stat_get(_: lookup, _: *const u8, _: usize, _: *mut filestat) -> errno; - fn cloudabi_sys_file_stat_put( - _: lookup, - _: *const u8, - _: usize, - _: *const filestat, - _: fsflags, - ) -> errno; - fn cloudabi_sys_file_symlink(_: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; - fn cloudabi_sys_file_unlink(_: fd, _: *const u8, _: usize, _: ulflags) -> errno; - fn cloudabi_sys_lock_unlock(_: *mut lock, _: scope) -> errno; - fn cloudabi_sys_mem_advise(_: *mut (), _: usize, _: advice) -> errno; - fn cloudabi_sys_mem_map( - _: *mut (), - _: usize, - _: mprot, - _: mflags, - _: fd, - _: filesize, - _: *mut *mut (), - ) -> errno; - fn cloudabi_sys_mem_protect(_: *mut (), _: usize, _: mprot) -> errno; - fn cloudabi_sys_mem_sync(_: *mut (), _: usize, _: msflags) -> errno; - fn cloudabi_sys_mem_unmap(_: *mut (), _: usize) -> errno; - fn cloudabi_sys_poll(_: *const subscription, _: *mut event, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_proc_exec(_: fd, _: *const (), _: usize, _: *const fd, _: usize) -> errno; - fn cloudabi_sys_proc_exit(_: exitcode) -> !; - fn cloudabi_sys_proc_fork(_: *mut fd, _: *mut tid) -> errno; - fn cloudabi_sys_proc_raise(_: signal) -> errno; - fn cloudabi_sys_random_get(_: *mut (), _: usize) -> errno; - fn cloudabi_sys_sock_recv(_: fd, _: *const recv_in, _: *mut recv_out) -> errno; - fn cloudabi_sys_sock_send(_: fd, _: *const send_in, _: *mut send_out) -> errno; - fn cloudabi_sys_sock_shutdown(_: fd, _: sdflags) -> errno; - fn cloudabi_sys_thread_create(_: *mut threadattr, _: *mut tid) -> errno; - fn cloudabi_sys_thread_exit(_: *mut lock, _: scope) -> !; - fn cloudabi_sys_thread_yield() -> errno; -} - -/// Obtains the resolution of a clock. -/// -/// ## Parameters -/// -/// **clock_id**: -/// The clock for which the resolution needs to be -/// returned. -/// -/// **resolution**: -/// The resolution of the clock. -#[inline] -pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno { - unsafe { cloudabi_sys_clock_res_get(clock_id_, resolution_) } -} - -/// Obtains the time value of a clock. -/// -/// ## Parameters -/// -/// **clock_id**: -/// The clock for which the time needs to be -/// returned. -/// -/// **precision**: -/// The maximum lag (exclusive) that the returned -/// time value may have, compared to its actual -/// value. -/// -/// **time**: -/// The time value of the clock. -#[inline] -pub unsafe fn clock_time_get( - clock_id_: clockid, - precision_: timestamp, - time_: *mut timestamp, -) -> errno { - unsafe { cloudabi_sys_clock_time_get(clock_id_, precision_, time_) } -} - -/// Wakes up threads waiting on a userspace condition variable. -/// -/// If an invocation of this system call causes all waiting -/// threads to be woken up, the value of the condition variable -/// is set to [`CONDVAR_HAS_NO_WAITERS`](constant.CONDVAR_HAS_NO_WAITERS.html). As long as the condition -/// variable is set to this value, it is not needed to invoke this -/// system call. -/// -/// ## Parameters -/// -/// **condvar**: -/// The userspace condition variable that has -/// waiting threads. -/// -/// **scope**: -/// Whether the condition variable is stored in -/// private or shared memory. -/// -/// **nwaiters**: -/// The number of threads that need to be woken -/// up. If it exceeds the number of waiting -/// threads, all threads are woken up. -#[inline] -pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno { - unsafe { cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_) } -} - -/// Closes a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor that needs to be closed. -#[inline] -pub unsafe fn fd_close(fd_: fd) -> errno { - unsafe { cloudabi_sys_fd_close(fd_) } -} - -/// Creates a file descriptor. -/// -/// ## Parameters -/// -/// **type**: -/// Possible values: -/// -/// - [`SHARED_MEMORY`](enum.filetype.html#variant.SHARED_MEMORY): -/// Creates an anonymous shared memory -/// object. -/// -/// **fd**: -/// The file descriptor that has been created. -#[inline] -pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno { - unsafe { cloudabi_sys_fd_create1(type_, fd_) } -} - -/// Creates a pair of file descriptors. -/// -/// ## Parameters -/// -/// **type**: -/// Possible values: -/// -/// - [`SOCKET_DGRAM`](enum.filetype.html#variant.SOCKET_DGRAM): -/// Creates a UNIX datagram socket pair. -/// - [`SOCKET_STREAM`](enum.filetype.html#variant.SOCKET_STREAM): -/// Creates a UNIX byte-stream socket -/// pair. -/// -/// **fd1**: -/// The first file descriptor of the pair. -/// -/// **fd2**: -/// The second file descriptor of the pair. -#[inline] -pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno { - // SAFETY: the caller must uphold the safety contract for `cloudabi_sys_fd_create2`. - unsafe { cloudabi_sys_fd_create2(type_, fd1_, fd2_) } -} - -/// Synchronizes the data of a file to disk. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor of the file whose data -/// needs to be synchronized to disk. -#[inline] -pub unsafe fn fd_datasync(fd_: fd) -> errno { - // SAFETY: the caller must guarantee that `fd` is valid - // for synchronization. - unsafe { cloudabi_sys_fd_datasync(fd_) } -} - -/// Duplicates a file descriptor. -/// -/// ## Parameters -/// -/// **from**: -/// The file descriptor that needs to be -/// duplicated. -/// -/// **fd**: -/// The new file descriptor. -#[inline] -pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno { - unsafe { cloudabi_sys_fd_dup(from_, fd_) } -} - -/// Reads from a file descriptor, without using and updating the -/// file descriptor's offset. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor from which data should be -/// read. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be stored. -/// -/// **offset**: -/// The offset within the file at which reading -/// should start. -/// -/// **nread**: -/// The number of bytes read. -#[inline] -pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno { - unsafe { cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_) } -} - -/// Writes to a file descriptor, without using and updating the -/// file descriptor's offset. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor to which data should be -/// written. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be retrieved. -/// -/// **offset**: -/// The offset within the file at which writing -/// should start. -/// -/// **nwritten**: -/// The number of bytes written. -#[inline] -pub unsafe fn fd_pwrite( - fd_: fd, - iovs_: &[ciovec], - offset_: filesize, - nwritten_: &mut usize, -) -> errno { - unsafe { cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_) } -} - -/// Reads from a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor from which data should be -/// read. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be stored. -/// -/// **nread**: -/// The number of bytes read. -#[inline] -pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno { - unsafe { cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_) } -} - -/// Atomically replaces a file descriptor by a copy of another -/// file descriptor. -/// -/// Due to the strong focus on thread safety, this environment -/// does not provide a mechanism to duplicate a file descriptor to -/// an arbitrary number, like dup2(). This would be prone to race -/// conditions, as an actual file descriptor with the same number -/// could be allocated by a different thread at the same time. -/// -/// This system call provides a way to atomically replace file -/// descriptors, which would disappear if dup2() were to be -/// removed entirely. -/// -/// ## Parameters -/// -/// **from**: -/// The file descriptor that needs to be copied. -/// -/// **to**: -/// The file descriptor that needs to be -/// overwritten. -#[inline] -pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno { - unsafe { cloudabi_sys_fd_replace(from_, to_) } -} - -/// Moves the offset of the file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose offset has to be -/// moved. -/// -/// **offset**: -/// The number of bytes to move. -/// -/// **whence**: -/// Relative to which position the move should -/// take place. -/// -/// **newoffset**: -/// The new offset of the file descriptor, -/// relative to the start of the file. -#[inline] -pub unsafe fn fd_seek( - fd_: fd, - offset_: filedelta, - whence_: whence, - newoffset_: &mut filesize, -) -> errno { - unsafe { cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) } -} - -/// Gets attributes of a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file descriptor's -/// attributes are stored. -#[inline] -pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno { - unsafe { cloudabi_sys_fd_stat_get(fd_, buf_) } -} - -/// Adjusts attributes of a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file descriptor -/// attributes that are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno { - unsafe { cloudabi_sys_fd_stat_put(fd_, buf_, flags_) } -} - -/// Synchronizes the data and metadata of a file to disk. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor of the file whose data -/// and metadata needs to be synchronized to disk. -#[inline] -pub unsafe fn fd_sync(fd_: fd) -> errno { - unsafe { cloudabi_sys_fd_sync(fd_) } -} - -/// Writes to a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor to which data should be -/// written. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be retrieved. -/// -/// **nwritten**: -/// The number of bytes written. -#[inline] -pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno { - unsafe { cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_) } -} - -/// Provides file advisory information on a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor for which to provide file -/// advisory information. -/// -/// **offset**: -/// The offset within the file to which the -/// advisory applies. -/// -/// **len**: -/// The length of the region to which the advisory -/// applies. -/// -/// **advice**: -/// The advice. -#[inline] -pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno { - unsafe { cloudabi_sys_file_advise(fd_, offset_, len_, advice_) } -} - -/// Forces the allocation of space in a file. -/// -/// ## Parameters -/// -/// **fd**: -/// The file in which the space should be -/// allocated. -/// -/// **offset**: -/// The offset at which the allocation should -/// start. -/// -/// **len**: -/// The length of the area that is allocated. -#[inline] -pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno { - unsafe { cloudabi_sys_file_allocate(fd_, offset_, len_) } -} - -/// Creates a file of a specified type. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the file to be created starts. -/// -/// **path**: -/// The path at which the file should be created. -/// -/// **type**: -/// Possible values: -/// -/// - [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY): -/// Creates a directory. -#[inline] -pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno { - unsafe { cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)} -} - -/// Creates a hard link. -/// -/// ## Parameters -/// -/// **fd1**: -/// The working directory at which the resolution -/// of the source path starts. -/// -/// **path1**: -/// The source path of the file that should be -/// hard linked. -/// -/// **fd2**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path at which the hard link -/// should be created. -#[inline] -pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { - unsafe { cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) } -} - -/// Opens a file. -/// -/// ## Parameters -/// -/// **dirfd**: -/// The working directory at which the resolution -/// of the file to be opened starts. -/// -/// **path**: -/// The path of the file that should be opened. -/// -/// **oflags**: -/// The method at which the file should be opened. -/// -/// **fds**: -/// [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and -/// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting) specify the -/// initial rights of the newly created file -/// descriptor. The operating system is allowed to -/// return a file descriptor with fewer rights -/// than specified, if and only if those rights do -/// not apply to the type of file being opened. -/// -/// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags) specifies the initial flags -/// of the file descriptor. -/// -/// [`fdstat.fs_filetype`](struct.fdstat.html#structfield.fs_filetype) is ignored. -/// -/// **fd**: -/// The file descriptor of the file that has been -/// opened. -#[inline] -pub unsafe fn file_open( - dirfd_: lookup, - path_: &[u8], - oflags_: oflags, - fds_: *const fdstat, - fd_: &mut fd, -) -> errno { - unsafe { cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_) } -} - -/// Reads directory entries from a directory. -/// -/// When successful, the contents of the output buffer consist of -/// a sequence of directory entries. Each directory entry consists -/// of a [`dirent`] object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes -/// holding the name of the directory entry. -/// -/// This system call fills the output buffer as much as possible, -/// potentially truncating the last directory entry. This allows -/// the caller to grow its read buffer size in case it's too small -/// to fit a single large directory entry, or skip the oversized -/// directory entry. -/// -/// ## Parameters -/// -/// **fd**: -/// The directory from which to read the directory -/// entries. -/// -/// **buf**: -/// The buffer where directory entries are stored. -/// -/// **cookie**: -/// The location within the directory to start -/// reading. -/// -/// **bufused**: -/// The number of bytes stored in the read buffer. -/// If less than the size of the read buffer, the -/// end of the directory has been reached. -#[inline] -pub unsafe fn file_readdir( - fd_: fd, - buf_: &mut [u8], - cookie_: dircookie, - bufused_: &mut usize, -) -> errno { - unsafe { cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_) } -} - -/// Reads the contents of a symbolic link. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path of the symbolic starts. -/// -/// **path**: -/// The path of the symbolic link whose contents -/// should be read. -/// -/// **buf**: -/// The buffer where the contents of the symbolic -/// link should be stored. -/// -/// **bufused**: -/// The number of bytes placed in the buffer. -#[inline] -pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno { - unsafe { - cloudabi_sys_file_readlink( - fd_, - path_.as_ptr(), - path_.len(), - buf_.as_mut_ptr(), - buf_.len(), - bufused_, - ) - } -} - -/// Renames a file. -/// -/// ## Parameters -/// -/// **fd1**: -/// The working directory at which the resolution -/// of the source path starts. -/// -/// **path1**: -/// The source path of the file that should be -/// renamed. -/// -/// **fd2**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path to which the file should -/// be renamed. -#[inline] -pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { - unsafe { - cloudabi_sys_file_rename( - fd1_, - path1_.as_ptr(), - path1_.len(), - fd2_, - path2_.as_ptr(), - path2_.len(), - ) - } -} - -/// Gets attributes of a file by file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file's attributes are -/// stored. -#[inline] -pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno { - unsafe { cloudabi_sys_file_stat_fget(fd_, buf_) } -} - -/// Adjusts attributes of a file by file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file attributes that -/// are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno { - unsafe { cloudabi_sys_file_stat_fput(fd_, buf_, flags_) } -} - -/// Gets attributes of a file by path. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path whose attributes have to be -/// obtained starts. -/// -/// **path**: -/// The path of the file whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file's attributes are -/// stored. -#[inline] -pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno { - unsafe { cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_) } -} - -/// Adjusts attributes of a file by path. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path whose attributes have to be -/// adjusted starts. -/// -/// **path**: -/// The path of the file whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file attributes that -/// are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn file_stat_put( - fd_: lookup, - path_: &[u8], - buf_: *const filestat, - flags_: fsflags, -) -> errno { - unsafe { cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_) } -} - -/// Creates a symbolic link. -/// -/// ## Parameters -/// -/// **path1**: -/// The contents of the symbolic link. -/// -/// **fd**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path at which the symbolic -/// link should be created. -#[inline] -pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno { - unsafe { cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len()) } -} - -/// Unlinks a file, or removes a directory. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path starts. -/// -/// **path**: -/// The path that needs to be unlinked or removed. -/// -/// **flags**: -/// Possible values: -/// -/// - [`REMOVEDIR`](struct.ulflags.html#associatedconstant.REMOVEDIR): -/// If set, attempt to remove a directory. -/// Otherwise, unlink a file. -#[inline] -pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno { - unsafe { cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_) } -} - -/// Unlocks a write-locked userspace lock. -/// -/// If a userspace lock is unlocked while having its -/// [`LOCK_KERNEL_MANAGED`](constant.LOCK_KERNEL_MANAGED.html) flag set, the lock cannot be unlocked in -/// userspace directly. This system call needs to be performed -/// instead, so that any waiting threads can be woken up. -/// -/// To prevent spurious invocations of this system call, the lock -/// must be locked for writing. This prevents other threads from -/// acquiring additional read locks while the system call is in -/// progress. If the lock is acquired for reading, it must first -/// be upgraded to a write lock. -/// -/// ## Parameters -/// -/// **lock**: -/// The userspace lock that is locked for writing -/// by the calling thread. -/// -/// **scope**: -/// Whether the lock is stored in private or -/// shared memory. -#[inline] -pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno { - unsafe { cloudabi_sys_lock_unlock(lock_, scope_) } -} - -/// Provides memory advisory information on a region of memory. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages for which to provide memory advisory -/// information. -/// -/// **advice**: -/// The advice. -#[inline] -pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno { - unsafe { cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_) } -} - -/// Creates a memory mapping, making the contents of a file -/// accessible through memory. -/// -/// ## Parameters -/// -/// **addr**: -/// If [`FIXED`](struct.mflags.html#associatedconstant.FIXED) is set, specifies to which -/// address the file region is mapped. Otherwise, -/// the mapping is performed at an unused -/// location. -/// -/// **len**: -/// The length of the memory mapping to be -/// created. -/// -/// **prot**: -/// Initial memory protection options for the -/// memory mapping. -/// -/// **flags**: -/// Memory mapping flags. -/// -/// **fd**: -/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be -/// [`MAP_ANON_FD`](constant.MAP_ANON_FD.html). Otherwise, this argument -/// specifies the file whose contents need to be -/// mapped. -/// -/// **off**: -/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be -/// zero. Otherwise, this argument specifies the -/// offset within the file at which the mapping -/// starts. -/// -/// **mem**: -/// The starting address of the memory mapping. -#[inline] -pub unsafe fn mem_map( - addr_: *mut (), - len_: usize, - prot_: mprot, - flags_: mflags, - fd_: fd, - off_: filesize, - mem_: &mut *mut (), -) -> errno { - unsafe { cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_) } -} - -/// Changes the protection of a memory mapping. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that need their protection changed. -/// -/// **prot**: -/// New protection options. -#[inline] -pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno { - unsafe { cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_) } -} - -/// Synchronizes a region of memory with its physical storage. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that need to be synchronized. -/// -/// **flags**: -/// The method of synchronization. -#[inline] -pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno { - unsafe { cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_) } -} - -/// Unmaps a region of memory. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that needs to be unmapped. -#[inline] -pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno { - unsafe { cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len()) } -} - -/// Concurrently polls for the occurrence of a set of events. -/// -/// ## Parameters -/// -/// **in**: -/// The events to which to subscribe. -/// -/// **out**: -/// The events that have occurred. -/// -/// **nsubscriptions**: -/// Both the number of subscriptions and events. -/// -/// **nevents**: -/// The number of events stored. -#[inline] -pub unsafe fn poll( - in_: *const subscription, - out_: *mut event, - nsubscriptions_: usize, - nevents_: *mut usize, -) -> errno { - unsafe { cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) } -} - -/// Replaces the process by a new executable. -/// -/// Process execution in CloudABI differs from POSIX in two ways: -/// handling of arguments and inheritance of file descriptors. -/// -/// CloudABI does not use string command line arguments. Instead, -/// a buffer with binary data is copied into the address space of -/// the new executable. The kernel does not enforce any specific -/// structure to this data, although CloudABI's C library uses it -/// to store a tree structure that is semantically identical to -/// YAML. -/// -/// Due to the strong focus on thread safety, file descriptors -/// aren't inherited through close-on-exec flags. An explicit -/// list of file descriptors that need to be retained needs to be -/// provided. After execution, file descriptors are placed in the -/// order in which they are stored in the array. This not only -/// makes the execution process deterministic. It also prevents -/// potential information disclosures about the layout of the -/// original process. -/// -/// ## Parameters -/// -/// **fd**: -/// A file descriptor of the new executable. -/// -/// **data**: -/// Binary argument data that is passed on to the -/// new executable. -/// -/// **fds**: -/// The layout of the file descriptor table after -/// execution. -#[inline] -pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno { - unsafe { cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len()) } -} - -/// Terminates the process normally. -/// -/// ## Parameters -/// -/// **rval**: -/// The exit code returned by the process. The -/// exit code can be obtained by other processes -/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode). -#[inline] -pub unsafe fn proc_exit(rval_: exitcode) -> ! { - unsafe { cloudabi_sys_proc_exit(rval_) } -} - -/// Forks the process of the calling thread. -/// -/// After forking, a new process shall be created, having only a -/// copy of the calling thread. The parent process will obtain a -/// process descriptor. When closed, the child process is -/// automatically signaled with [`KILL`](enum.signal.html#variant.KILL). -/// -/// ## Parameters -/// -/// **fd**: -/// In the parent process: the file descriptor -/// number of the process descriptor. -/// -/// In the child process: [`PROCESS_CHILD`](constant.PROCESS_CHILD.html). -/// -/// **tid**: -/// In the parent process: undefined. -/// -/// In the child process: the thread ID of the -/// initial thread of the child process. -#[inline] -pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno { - unsafe { cloudabi_sys_proc_fork(fd_, tid_) } -} - -/// Sends a signal to the process of the calling thread. -/// -/// ## Parameters -/// -/// **sig**: -/// The signal condition that should be triggered. -/// If the signal causes the process to terminate, -/// its condition can be obtained by other -/// processes through -/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal). -#[inline] -pub unsafe fn proc_raise(sig_: signal) -> errno { - unsafe { cloudabi_sys_proc_raise(sig_) } -} - -/// Obtains random data from the kernel random number generator. -/// -/// As this interface is not guaranteed to be fast, it is advised -/// that the random data obtained through this system call is used -/// as the seed for a userspace pseudo-random number generator. -/// -/// ## Parameters -/// -/// **buf**: -/// The buffer that needs to be filled with random -/// data. -#[inline] -pub unsafe fn random_get(buf_: &mut [u8]) -> errno { - unsafe { cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len()) } -} - -/// Receives a message on a socket. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket on which a message should be -/// received. -/// -/// **in**: -/// Input parameters. -/// -/// **out**: -/// Output parameters. -#[inline] -pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno { - unsafe { cloudabi_sys_sock_recv(sock_, in_, out_) } -} - -/// Sends a message on a socket. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket on which a message should be sent. -/// -/// **in**: -/// Input parameters. -/// -/// **out**: -/// Output parameters. -#[inline] -pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno { - unsafe { cloudabi_sys_sock_send(sock_, in_, out_) } -} - -/// Shuts down socket send and receive channels. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket that needs its channels shut down. -/// -/// **how**: -/// Which channels on the socket need to be shut -/// down. -#[inline] -pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno { - unsafe { cloudabi_sys_sock_shutdown(sock_, how_) } -} - -/// Creates a new thread within the current process. -/// -/// ## Parameters -/// -/// **attr**: -/// The desired attributes of the new thread. -/// -/// **tid**: -/// The thread ID of the new thread. -#[inline] -pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno { - unsafe { cloudabi_sys_thread_create(attr_, tid_) } -} - -/// Terminates the calling thread. -/// -/// This system call can also unlock a single userspace lock -/// after termination, which can be used to implement thread -/// joining. -/// -/// ## Parameters -/// -/// **lock**: -/// Userspace lock that is locked for writing by -/// the calling thread. -/// -/// **scope**: -/// Whether the lock is stored in private or -/// shared memory. -#[inline] -pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! { - unsafe { cloudabi_sys_thread_exit(lock_, scope_) } -} - -/// Temporarily yields execution of the calling thread. -#[inline] -pub unsafe fn thread_yield() -> errno { - unsafe { cloudabi_sys_thread_yield() } -} diff --git a/library/std/src/sys/cloudabi/abi/mod.rs b/library/std/src/sys/cloudabi/abi/mod.rs deleted file mode 100644 index 9d01d24ea8..0000000000 --- a/library/std/src/sys/cloudabi/abi/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[allow(warnings)] -mod cloudabi; -pub use self::cloudabi::*; diff --git a/library/std/src/sys/cloudabi/args.rs b/library/std/src/sys/cloudabi/args.rs deleted file mode 100644 index dea562abad..0000000000 --- a/library/std/src/sys/cloudabi/args.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use crate::sys::cloudabi::shims::args::*; - -#[allow(dead_code)] -pub fn init(_: isize, _: *const *const u8) {} - -#[allow(dead_code)] -pub fn cleanup() {} diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs deleted file mode 100644 index f09bc01701..0000000000 --- a/library/std/src/sys/cloudabi/condvar.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::mem; -use crate::sync::atomic::{AtomicU32, Ordering}; -use crate::sys::cloudabi::abi; -use crate::sys::mutex::{self, Mutex}; -use crate::sys::time::checked_dur2intervals; -use crate::time::Duration; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -pub struct Condvar { - condvar: AtomicU32, -} - -pub type MovableCondvar = Condvar; - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) } - } - - pub unsafe fn init(&mut self) {} - - pub unsafe fn notify_one(&self) { - if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal( - &self.condvar as *const AtomicU32 as *mut abi::condvar, - abi::scope::PRIVATE, - 1, - ); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable"); - } - } - - pub unsafe fn notify_all(&self) { - if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal( - &self.condvar as *const AtomicU32 as *mut abi::condvar, - abi::scope::PRIVATE, - abi::nthreads::MAX, - ); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to broadcast on condition variable"); - } - } - - pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = mutex::raw(mutex); - assert_eq!( - mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This lock is not write-locked by this thread" - ); - - // Call into the kernel to wait on the condition variable. - let subscription = abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, - condvar_scope: abi::scope::PRIVATE, - lock: mutex as *const AtomicU32 as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let mut nevents: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to wait on condition variable"); - assert_eq!( - event.assume_init().error, - abi::errno::SUCCESS, - "Failed to wait on condition variable" - ); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let mutex = mutex::raw(mutex); - assert_eq!( - mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This lock is not write-locked by this thread" - ); - - // Call into the kernel to wait on the condition variable. - let timeout = - checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds"); - let subscriptions = [ - abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, - condvar_scope: abi::scope::PRIVATE, - lock: mutex as *const AtomicU32 as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }, - abi::subscription { - type_: abi::eventtype::CLOCK, - union: abi::subscription_union { - clock: abi::subscription_clock { - clock_id: abi::clockid::MONOTONIC, - timeout, - ..mem::zeroed() - }, - }, - ..mem::zeroed() - }, - ]; - let mut events: [mem::MaybeUninit; 2] = [mem::MaybeUninit::uninit(); 2]; - let mut nevents: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let ret = abi::poll( - subscriptions.as_ptr(), - mem::MaybeUninit::slice_as_mut_ptr(&mut events), - 2, - nevents.as_mut_ptr(), - ); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to wait on condition variable"); - let nevents = nevents.assume_init(); - for i in 0..nevents { - assert_eq!( - events[i].assume_init().error, - abi::errno::SUCCESS, - "Failed to wait on condition variable" - ); - if events[i].assume_init().type_ == abi::eventtype::CONDVAR { - return true; - } - } - false - } - - pub unsafe fn destroy(&self) { - assert_eq!( - self.condvar.load(Ordering::Relaxed), - abi::CONDVAR_HAS_NO_WAITERS.0, - "Attempted to destroy a condition variable with blocked threads" - ); - } -} diff --git a/library/std/src/sys/cloudabi/io.rs b/library/std/src/sys/cloudabi/io.rs deleted file mode 100644 index d5f475b431..0000000000 --- a/library/std/src/sys/cloudabi/io.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::mem; - -#[derive(Copy, Clone)] -pub struct IoSlice<'a>(&'a [u8]); - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - self.0 = &self.0[n..] - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } -} - -pub struct IoSliceMut<'a>(&'a mut [u8]); - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - let slice = mem::replace(&mut self.0, &mut []); - let (_, remaining) = slice.split_at_mut(n); - self.0 = remaining; - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - self.0 - } -} diff --git a/library/std/src/sys/cloudabi/mod.rs b/library/std/src/sys/cloudabi/mod.rs deleted file mode 100644 index 13f1bc8826..0000000000 --- a/library/std/src/sys/cloudabi/mod.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -use crate::io::ErrorKind; -use crate::mem; - -#[path = "../unix/alloc.rs"] -pub mod alloc; -pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; -pub mod condvar; -pub mod io; -#[path = "../unix/memchr.rs"] -pub mod memchr; -pub mod mutex; -pub mod os; -pub mod rwlock; -pub mod stack_overflow; -pub mod stdio; -pub mod thread; -#[path = "../unix/thread_local_key.rs"] -pub mod thread_local_key; -pub mod time; - -pub use crate::sys_common::os_str_bytes as os_str; - -mod abi; - -mod shims; -pub use self::shims::*; - -#[allow(dead_code)] -pub fn init() {} - -pub fn decode_error_kind(errno: i32) -> ErrorKind { - match errno { - x if x == abi::errno::ACCES as i32 => ErrorKind::PermissionDenied, - x if x == abi::errno::ADDRINUSE as i32 => ErrorKind::AddrInUse, - x if x == abi::errno::ADDRNOTAVAIL as i32 => ErrorKind::AddrNotAvailable, - x if x == abi::errno::AGAIN as i32 => ErrorKind::WouldBlock, - x if x == abi::errno::CONNABORTED as i32 => ErrorKind::ConnectionAborted, - x if x == abi::errno::CONNREFUSED as i32 => ErrorKind::ConnectionRefused, - x if x == abi::errno::CONNRESET as i32 => ErrorKind::ConnectionReset, - x if x == abi::errno::EXIST as i32 => ErrorKind::AlreadyExists, - x if x == abi::errno::INTR as i32 => ErrorKind::Interrupted, - x if x == abi::errno::INVAL as i32 => ErrorKind::InvalidInput, - x if x == abi::errno::NOENT as i32 => ErrorKind::NotFound, - x if x == abi::errno::NOTCONN as i32 => ErrorKind::NotConnected, - x if x == abi::errno::PERM as i32 => ErrorKind::PermissionDenied, - x if x == abi::errno::PIPE as i32 => ErrorKind::BrokenPipe, - x if x == abi::errno::TIMEDOUT as i32 => ErrorKind::TimedOut, - _ => ErrorKind::Other, - } -} - -pub fn abort_internal() -> ! { - core::intrinsics::abort(); -} - -pub use libc::strlen; - -pub fn hashmap_random_keys() -> (u64, u64) { - unsafe { - let mut v: mem::MaybeUninit<(u64, u64)> = mem::MaybeUninit::uninit(); - libc::arc4random_buf(v.as_mut_ptr() as *mut libc::c_void, mem::size_of_val(&v)); - v.assume_init() - } -} diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs deleted file mode 100644 index 9dafcbc1fb..0000000000 --- a/library/std/src/sys/cloudabi/mutex.rs +++ /dev/null @@ -1,153 +0,0 @@ -use crate::cell::Cell; -use crate::mem; -use crate::mem::MaybeUninit; -use crate::sync::atomic::{AtomicU32, Ordering}; -use crate::sys::cloudabi::abi; -use crate::sys::rwlock::{self, RWLock}; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -// Implement Mutex using an RWLock. This doesn't introduce any -// performance overhead in this environment, as the operations would be -// implemented identically. -pub struct Mutex(RWLock); - -pub type MovableMutex = Mutex; - -pub unsafe fn raw(m: &Mutex) -> &AtomicU32 { - rwlock::raw(&m.0) -} - -impl Mutex { - pub const fn new() -> Mutex { - Mutex(RWLock::new()) - } - - pub unsafe fn init(&mut self) { - // This function should normally reinitialize the mutex after - // moving it to a different memory address. This implementation - // does not require adjustments after moving. - } - - pub unsafe fn try_lock(&self) -> bool { - self.0.try_write() - } - - pub unsafe fn lock(&self) { - self.0.write() - } - - pub unsafe fn unlock(&self) { - self.0.write_unlock() - } - - pub unsafe fn destroy(&self) { - self.0.destroy() - } -} - -pub struct ReentrantMutex { - lock: AtomicU32, - recursion: Cell, -} - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), recursion: Cell::new(0) } - } - - pub unsafe fn init(&self) {} - - pub unsafe fn try_lock(&self) -> bool { - // Attempt to acquire the lock. - if let Err(old) = self.lock.compare_exchange( - abi::LOCK_UNLOCKED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - // If we fail to acquire the lock, it may be the case - // that we've already acquired it and may need to recurse. - if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 { - self.recursion.set(self.recursion.get() + 1); - true - } else { - false - } - } else { - // Success. - assert_eq!(self.recursion.get(), 0, "Mutex has invalid recursion count"); - true - } - } - - pub unsafe fn lock(&self) { - if !self.try_lock() { - // Call into the kernel to acquire a write lock. - let lock = &self.lock as *const AtomicU32; - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_WRLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: lock as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event = MaybeUninit::::uninit(); - let mut nevents = MaybeUninit::::uninit(); - // SAFE: The caller must to ensure that `event` and `nevents` are initialized. - let ret = - unsafe { abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()) }; - assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex"); - let event = event.assume_init(); - assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex"); - } - } - - pub unsafe fn unlock(&self) { - assert_eq!( - self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This mutex is locked by a different thread" - ); - - let r = self.recursion.get(); - if r > 0 { - self.recursion.set(r - 1); - } else if !self - .lock - .compare_exchange( - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - abi::LOCK_UNLOCKED.0, - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - // Lock is managed by kernelspace. Call into the kernel - // to unblock waiting threads. - let ret = abi::lock_unlock( - &self.lock as *const AtomicU32 as *mut abi::lock, - abi::scope::PRIVATE, - ); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex"); - } - } - - pub unsafe fn destroy(&self) { - assert_eq!( - self.lock.load(Ordering::Relaxed), - abi::LOCK_UNLOCKED.0, - "Attempted to destroy locked mutex" - ); - assert_eq!(self.recursion.get(), 0, "Recursion counter invalid"); - } -} diff --git a/library/std/src/sys/cloudabi/os.rs b/library/std/src/sys/cloudabi/os.rs deleted file mode 100644 index 326faaa852..0000000000 --- a/library/std/src/sys/cloudabi/os.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::ffi::CStr; -use crate::str; - -use libc::c_int; - -pub use crate::sys::cloudabi::shims::os::*; - -pub fn errno() -> i32 { - extern "C" { - #[thread_local] - static errno: c_int; - } - - unsafe { errno as i32 } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - // cloudlibc's strerror() is guaranteed to be thread-safe. There is - // thus no need to use strerror_r(). - str::from_utf8(unsafe { CStr::from_ptr(libc::strerror(errno)) }.to_bytes()).unwrap().to_owned() -} - -pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } -} diff --git a/library/std/src/sys/cloudabi/rwlock.rs b/library/std/src/sys/cloudabi/rwlock.rs deleted file mode 100644 index 508de8ba47..0000000000 --- a/library/std/src/sys/cloudabi/rwlock.rs +++ /dev/null @@ -1,215 +0,0 @@ -use crate::mem; -use crate::mem::MaybeUninit; -use crate::sync::atomic::{AtomicU32, Ordering}; -use crate::sys::cloudabi::abi; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -#[thread_local] -static mut RDLOCKS_ACQUIRED: u32 = 0; - -pub struct RWLock { - lock: AtomicU32, -} - -pub unsafe fn raw(r: &RWLock) -> &AtomicU32 { - &r.lock -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0) } - } - - pub unsafe fn try_read(&self) -> bool { - let mut old = abi::LOCK_UNLOCKED.0; - while let Err(cur) = - self.lock.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) - { - if (cur & abi::LOCK_WRLOCKED.0) != 0 { - // Another thread already has a write lock. - assert_ne!( - old & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "Attempted to acquire a read lock while holding a write lock" - ); - return false; - } else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 { - // Lock has threads waiting for the lock. Only acquire - // the lock if we have already acquired read locks. In - // that case, it is justified to acquire this lock to - // prevent a deadlock. - return false; - } - old = cur; - } - - RDLOCKS_ACQUIRED += 1; - true - } - - pub unsafe fn read(&self) { - if !self.try_read() { - // Call into the kernel to acquire a read lock. - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_RDLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: &self.lock as *const AtomicU32 as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event = MaybeUninit::::uninit(); - let mut nevents = MaybeUninit::::uninit(); - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock"); - let event = event.assume_init(); - assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire read lock"); - - RDLOCKS_ACQUIRED += 1; - } - } - - pub unsafe fn read_unlock(&self) { - // Perform a read unlock. We can do this in userspace, except when - // other threads are blocked and we are performing the last unlock. - // In that case, call into the kernel. - // - // Other threads may attempt to increment the read lock count, - // meaning that the call into the kernel could be spurious. To - // prevent this from happening, upgrade to a write lock first. This - // allows us to call into the kernel, having the guarantee that the - // lock value will not change in the meantime. - assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count"); - let mut old = 1; - loop { - if old == 1 | abi::LOCK_KERNEL_MANAGED.0 { - // Last read lock while threads are waiting. Attempt to upgrade - // to a write lock before calling into the kernel to unlock. - if let Err(cur) = self.lock.compare_exchange_weak( - old, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - old = cur; - } else { - // Call into the kernel to unlock. - let ret = abi::lock_unlock( - &self.lock as *const AtomicU32 as *mut abi::lock, - abi::scope::PRIVATE, - ); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); - break; - } - } else { - // No threads waiting or not the last read lock. Just decrement - // the read lock count. - assert_ne!(old & !abi::LOCK_KERNEL_MANAGED.0, 0, "This rwlock is not locked"); - assert_eq!( - old & abi::LOCK_WRLOCKED.0, - 0, - "Attempted to read-unlock a write-locked rwlock" - ); - if let Err(cur) = self.lock.compare_exchange_weak( - old, - old - 1, - Ordering::Acquire, - Ordering::Relaxed, - ) { - old = cur; - } else { - break; - } - } - } - - RDLOCKS_ACQUIRED -= 1; - } - - pub unsafe fn try_write(&self) -> bool { - // Attempt to acquire the lock. - if let Err(old) = self.lock.compare_exchange( - abi::LOCK_UNLOCKED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - // Failure. Crash upon recursive acquisition. - assert_ne!( - old & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "Attempted to recursive write-lock a rwlock", - ); - false - } else { - // Success. - true - } - } - - pub unsafe fn write(&self) { - if !self.try_write() { - // Call into the kernel to acquire a write lock. - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_WRLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: &self.lock as *const AtomicU32 as *mut abi::lock, - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event = MaybeUninit::::uninit(); - let mut nevents = MaybeUninit::::uninit(); - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock"); - let event = event.assume_init(); - assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire write lock"); - } - } - - pub unsafe fn write_unlock(&self) { - assert_eq!( - self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "This rwlock is not write-locked by this thread" - ); - - if !self - .lock - .compare_exchange( - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - abi::LOCK_UNLOCKED.0, - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - // Lock is managed by kernelspace. Call into the kernel - // to unblock waiting threads. - let ret = abi::lock_unlock( - &self.lock as *const AtomicU32 as *mut abi::lock, - abi::scope::PRIVATE, - ); - assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); - } - } - - pub unsafe fn destroy(&self) { - assert_eq!( - self.lock.load(Ordering::Relaxed), - abi::LOCK_UNLOCKED.0, - "Attempted to destroy locked rwlock" - ); - } -} diff --git a/library/std/src/sys/cloudabi/shims/args.rs b/library/std/src/sys/cloudabi/shims/args.rs deleted file mode 100644 index f5cf71caf6..0000000000 --- a/library/std/src/sys/cloudabi/shims/args.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::ffi::OsString; - -pub struct Args(()); - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - &[] - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - None - } - fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - 0 - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - None - } -} - -pub fn args() -> Args { - Args(()) -} diff --git a/library/std/src/sys/cloudabi/shims/env.rs b/library/std/src/sys/cloudabi/shims/env.rs deleted file mode 100644 index de165a864b..0000000000 --- a/library/std/src/sys/cloudabi/shims/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = "cloudabi"; - pub const OS: &str = "cloudabi"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} diff --git a/library/std/src/sys/cloudabi/shims/fs.rs b/library/std/src/sys/cloudabi/shims/fs.rs deleted file mode 100644 index ecb5b51ccc..0000000000 --- a/library/std/src/sys/cloudabi/shims/fs.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::ffi::OsString; -use crate::fmt; -use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; -use crate::path::{Path, PathBuf}; -use crate::sys::time::SystemTime; -use crate::sys::{unsupported, Void}; - -pub struct File(Void); - -pub struct FileAttr(Void); - -pub struct ReadDir(Void); - -pub struct DirEntry(Void); - -#[derive(Clone, Debug)] -pub struct OpenOptions {} - -pub struct FilePermissions(Void); - -pub struct FileType(Void); - -#[derive(Debug)] -pub struct DirBuilder {} - -impl FileAttr { - pub fn size(&self) -> u64 { - match self.0 {} - } - - pub fn perm(&self) -> FilePermissions { - match self.0 {} - } - - pub fn file_type(&self) -> FileType { - match self.0 {} - } - - pub fn modified(&self) -> io::Result { - match self.0 {} - } - - pub fn accessed(&self) -> io::Result { - match self.0 {} - } - - pub fn created(&self) -> io::Result { - match self.0 {} - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - match self.0 {} - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - match self.0 {} - } - - pub fn set_readonly(&mut self, _readonly: bool) { - match self.0 {} - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - match self.0 {} - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - match self.0 {} - } -} - -impl Eq for FilePermissions {} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - match self.0 {} - } - - pub fn is_file(&self) -> bool { - match self.0 {} - } - - pub fn is_symlink(&self) -> bool { - match self.0 {} - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - match self.0 {} - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - match self.0 {} - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - match self.0 {} - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - match self.0 {} - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - match self.0 {} - } - - pub fn file_name(&self) -> OsString { - match self.0 {} - } - - pub fn metadata(&self) -> io::Result { - match self.0 {} - } - - pub fn file_type(&self) -> io::Result { - match self.0 {} - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions {} - } - - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - match self.0 {} - } - - pub fn fsync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn datasync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn flush(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() -} - -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} -} - -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - -pub fn readlink(_p: &Path) -> io::Result { - unsupported() -} - -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn stat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/library/std/src/sys/cloudabi/shims/mod.rs b/library/std/src/sys/cloudabi/shims/mod.rs deleted file mode 100644 index b1b5f142f4..0000000000 --- a/library/std/src/sys/cloudabi/shims/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::io; - -pub mod args; -pub mod env; -pub mod fs; -pub mod net; -pub mod os; -#[path = "../../unix/path.rs"] -pub mod path; -pub mod pipe; -pub mod process; - -// This enum is used as the storage for a bunch of types which can't actually exist. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub enum Void {} - -pub fn unsupported() -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, "This function is not available on CloudABI.")) -} diff --git a/library/std/src/sys/cloudabi/shims/net.rs b/library/std/src/sys/cloudabi/shims/net.rs deleted file mode 100644 index 375aaab405..0000000000 --- a/library/std/src/sys/cloudabi/shims/net.rs +++ /dev/null @@ -1,326 +0,0 @@ -use crate::convert::TryFrom; -use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; -use crate::sys::{unsupported, Void}; -use crate::time::Duration; - -#[allow(unused_extern_crates)] -pub extern crate libc as netc; - -pub struct TcpStream(Void); - -impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { - unsupported() - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unsupported() - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn read_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn write_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn peer_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn nodelay(&self) -> io::Result { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub struct TcpListener(Void); - -impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { - unsupported() - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn only_v6(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub struct UdpSocket(Void); - -impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { - unsupported() - } - - pub fn peer_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn socket_addr(&self) -> io::Result { - match self.0 {} - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - match self.0 {} - } - - pub fn read_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn write_timeout(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn broadcast(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_loop_v4(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - match self.0 {} - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn multicast_loop_v6(&self) -> io::Result { - match self.0 {} - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} - } - - pub fn ttl(&self) -> io::Result { - match self.0 {} - } - - pub fn take_error(&self) -> io::Result> { - match self.0 {} - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn send(&self, _: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { - match self.0 {} - } -} - -impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub struct LookupHost(Void); - -impl LookupHost { - pub fn port(&self) -> u16 { - match self.0 {} - } -} - -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - match self.0 {} - } -} - -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &str) -> io::Result { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result { - unsupported() - } -} diff --git a/library/std/src/sys/cloudabi/shims/os.rs b/library/std/src/sys/cloudabi/shims/os.rs deleted file mode 100644 index 779e6d54b7..0000000000 --- a/library/std/src/sys/cloudabi/shims/os.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::error::Error as StdError; -use crate::ffi::{OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::iter; -use crate::path::{self, PathBuf}; -use crate::sys::{unsupported, Void}; - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub type Env = iter::Empty<(OsString, OsString)>; - -pub fn env() -> Env { - iter::empty() -} - -pub fn getenv(_: &OsStr) -> io::Result> { - Ok(None) -} - -pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - unsupported() -} - -pub fn unsetenv(_: &OsStr) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(&'a Void); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - match *self.0 {} - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on CloudABI yet".fmt(f) - } -} - -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on CloudABI yet" - } -} - -pub fn home_dir() -> Option { - None -} - -pub fn temp_dir() -> PathBuf { - PathBuf::from("/tmp") -} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn getpid() -> u32 { - 1 -} diff --git a/library/std/src/sys/cloudabi/shims/pipe.rs b/library/std/src/sys/cloudabi/shims/pipe.rs deleted file mode 100644 index 10d0925823..0000000000 --- a/library/std/src/sys/cloudabi/shims/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/cloudabi/shims/process.rs b/library/std/src/sys/cloudabi/shims/process.rs deleted file mode 100644 index 4702e5c549..0000000000 --- a/library/std/src/sys/cloudabi/shims/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/cloudabi/stack_overflow.rs b/library/std/src/sys/cloudabi/stack_overflow.rs deleted file mode 100644 index 9339b14373..0000000000 --- a/library/std/src/sys/cloudabi/stack_overflow.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![cfg_attr(test, allow(dead_code))] - -pub unsafe fn init() {} - -pub unsafe fn cleanup() {} diff --git a/library/std/src/sys/cloudabi/stdio.rs b/library/std/src/sys/cloudabi/stdio.rs deleted file mode 100644 index 7fec4731a4..0000000000 --- a/library/std/src/sys/cloudabi/stdio.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::io; -use crate::sys::cloudabi::abi; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub const fn new() -> Stdin { - Stdin(()) - } -} - -impl io::Read for Stdin { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Ok(0) - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout(()) - } -} - -impl io::Write for Stdout { - fn write(&mut self, _buf: &[u8]) -> io::Result { - Err(io::Error::new( - io::ErrorKind::BrokenPipe, - "Stdout is not connected to any output in this environment", - )) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr(()) - } -} - -impl io::Write for Stderr { - fn write(&mut self, _buf: &[u8]) -> io::Result { - Err(io::Error::new( - io::ErrorKind::BrokenPipe, - "Stderr is not connected to any output in this environment", - )) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(abi::errno::BADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn panic_output() -> Option { - Some(Stderr::new()) -} diff --git a/library/std/src/sys/cloudabi/thread.rs b/library/std/src/sys/cloudabi/thread.rs deleted file mode 100644 index a15dc8653e..0000000000 --- a/library/std/src/sys/cloudabi/thread.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::cmp; -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::cloudabi::abi; -use crate::sys::time::checked_dur2intervals; -use crate::time::Duration; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; - -pub struct Thread { - id: libc::pthread_t, -} - -// CloudABI has pthread_t as a pointer in which case we still want -// a thread to be Send/Sync -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box) -> io::Result { - let p = Box::into_raw(box p); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - - let stack_size = cmp::max(stack, min_stack_size(&attr)); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); - - let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); - // Note: if the thread creation fails and this assert fails, then p will - // be leaked. However, an alternative design could cause double-free - // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - - return if ret != 0 { - // The thread failed to start and as a result p was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. - drop(Box::from_raw(p)); - Err(io::Error::from_raw_os_error(ret)) - } else { - Ok(Thread { id: native }) - }; - - extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { - // Let's run some code. - Box::from_raw(main as *mut Box)(); - } - ptr::null_mut() - } - } - - pub fn yield_now() { - let ret = unsafe { abi::thread_yield() }; - debug_assert_eq!(ret, abi::errno::SUCCESS); - } - - pub fn set_name(_name: &CStr) { - // CloudABI has no way to set a thread name. - } - - pub fn sleep(dur: Duration) { - let timeout = - checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds"); - unsafe { - let subscription = abi::subscription { - type_: abi::eventtype::CLOCK, - union: abi::subscription_union { - clock: abi::subscription_clock { - clock_id: abi::clockid::MONOTONIC, - timeout, - ..mem::zeroed() - }, - }, - ..mem::zeroed() - }; - let mut event = mem::MaybeUninit::::uninit(); - let mut nevents = mem::MaybeUninit::::uninit(); - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()); - assert_eq!(ret, abi::errno::SUCCESS); - let event = event.assume_init(); - assert_eq!(event.error, abi::errno::SUCCESS); - } - } - - pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } - } -} - -impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } -} - -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - pub type Guard = !; - pub unsafe fn current() -> Option { - None - } - pub unsafe fn init() -> Option { - None - } -} - -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN -} diff --git a/library/std/src/sys/cloudabi/time.rs b/library/std/src/sys/cloudabi/time.rs deleted file mode 100644 index c209231cf8..0000000000 --- a/library/std/src/sys/cloudabi/time.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::mem; -use crate::sys::cloudabi::abi; -use crate::time::Duration; - -const NSEC_PER_SEC: abi::timestamp = 1_000_000_000; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant { - t: abi::timestamp, -} - -pub fn checked_dur2intervals(dur: &Duration) -> Option { - dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as abi::timestamp) -} - -impl Instant { - pub fn now() -> Instant { - unsafe { - let mut t: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let ret = abi::clock_time_get(abi::clockid::MONOTONIC, 0, t.as_mut_ptr()); - assert_eq!(ret, abi::errno::SUCCESS); - Instant { t: t.assume_init() } - } - } - - pub fn actually_monotonic() -> bool { - true - } - - pub const fn zero() -> Instant { - Instant { t: 0 } - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - let diff = self.t.checked_sub(other.t)?; - Some(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32)) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? }) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime { - t: abi::timestamp, -} - -impl SystemTime { - pub fn now() -> SystemTime { - unsafe { - let mut t: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let ret = abi::clock_time_get(abi::clockid::REALTIME, 0, t.as_mut_ptr()); - assert_eq!(ret, abi::errno::SUCCESS); - SystemTime { t: t.assume_init() } - } - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - if self.t >= other.t { - let diff = self.t - other.t; - Ok(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32)) - } else { - let diff = other.t - self.t; - Err(Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32)) - } - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime { t: self.t.checked_add(checked_dur2intervals(other)?)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime { t: self.t.checked_sub(checked_dur2intervals(other)?)? }) - } -} - -pub const UNIX_EPOCH: SystemTime = SystemTime { t: 0 }; diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index 829d4c943f..1807655e97 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -377,11 +377,11 @@ pub fn readlink(_p: &Path) -> io::Result { unsupported() } -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { unsupported() } -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { +pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index b4628b6491..d48d9cb0ef 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -32,9 +32,6 @@ cfg_if::cfg_if! { } else if #[cfg(windows)] { mod windows; pub use self::windows::*; - } else if #[cfg(target_os = "cloudabi")] { - mod cloudabi; - pub use self::cloudabi::*; } else if #[cfg(target_os = "hermit")] { mod hermit; pub use self::hermit::*; @@ -63,11 +60,10 @@ cfg_if::cfg_if! { // On unix we'll document what's already available #[stable(feature = "rust1", since = "1.0.0")] pub use self::ext as unix_ext; - } else if #[cfg(any(target_os = "cloudabi", - target_os = "hermit", + } else if #[cfg(any(target_os = "hermit", target_arch = "wasm32", all(target_vendor = "fortanix", target_env = "sgx")))] { - // On CloudABI and wasm right now the module below doesn't compile + // On wasm right now the module below doesn't compile // (missing things in `libc` which is empty) so just omit everything // with an empty module #[unstable(issue = "none", feature = "std_internals")] @@ -88,11 +84,10 @@ cfg_if::cfg_if! { #[allow(missing_docs)] #[stable(feature = "rust1", since = "1.0.0")] pub use self::ext as windows_ext; - } else if #[cfg(any(target_os = "cloudabi", - target_os = "hermit", + } else if #[cfg(any(target_os = "hermit", target_arch = "wasm32", all(target_vendor = "fortanix", target_env = "sgx")))] { - // On CloudABI and wasm right now the shim below doesn't compile, so + // On wasm right now the shim below doesn't compile, so // just omit it #[unstable(issue = "none", feature = "std_internals")] #[allow(missing_docs)] diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs index ffa234fccf..da899773db 100644 --- a/library/std/src/sys/sgx/abi/mem.rs +++ b/library/std/src/sys/sgx/abi/mem.rs @@ -12,6 +12,18 @@ pub(crate) unsafe fn rel_ptr_mut(offset: u64) -> *mut T { extern "C" { static ENCLAVE_SIZE: usize; + static HEAP_BASE: u64; + static HEAP_SIZE: usize; +} + +/// Returns the base memory address of the heap +pub(crate) fn heap_base() -> *const u8 { + unsafe { rel_ptr_mut(HEAP_BASE) } +} + +/// Returns the size of the heap +pub(crate) fn heap_size() -> usize { + unsafe { HEAP_SIZE } } // Do not remove inline: will result in relocation failure diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs index a0eb12c3d1..a5e4530347 100644 --- a/library/std/src/sys/sgx/abi/mod.rs +++ b/library/std/src/sys/sgx/abi/mod.rs @@ -36,20 +36,20 @@ unsafe extern "C" fn tcs_init(secondary: bool) { } // Try to atomically swap UNINIT with BUSY. The returned state can be: - match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) { + match RELOC_STATE.compare_exchange(UNINIT, BUSY, Ordering::Acquire, Ordering::Acquire) { // This thread just obtained the lock and other threads will observe BUSY - UNINIT => { + Ok(_) => { reloc::relocate_elf_rela(); RELOC_STATE.store(DONE, Ordering::Release); } // We need to wait until the initialization is done. - BUSY => { + Err(BUSY) => { while RELOC_STATE.load(Ordering::Acquire) == BUSY { core::hint::spin_loop(); } } // Initialization is done. - DONE => {} + Err(DONE) => {} _ => unreachable!(), } } diff --git a/library/std/src/sys/sgx/alloc.rs b/library/std/src/sys/sgx/alloc.rs index 4559ea7cd2..4aea28cb83 100644 --- a/library/std/src/sys/sgx/alloc.rs +++ b/library/std/src/sys/sgx/alloc.rs @@ -1,4 +1,7 @@ use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr; +use crate::sys::sgx::abi::mem as sgx_mem; +use core::sync::atomic::{AtomicBool, Ordering}; use super::waitqueue::SpinMutex; @@ -10,7 +13,48 @@ use super::waitqueue::SpinMutex; // dlmalloc.c from C to Rust. #[cfg_attr(test, linkage = "available_externally")] #[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"] -static DLMALLOC: SpinMutex = SpinMutex::new(dlmalloc::DLMALLOC_INIT); +static DLMALLOC: SpinMutex> = + SpinMutex::new(dlmalloc::Dlmalloc::new_with_allocator(Sgx {})); + +struct Sgx; + +unsafe impl dlmalloc::Allocator for Sgx { + /// Allocs system resources + fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) { + static INIT: AtomicBool = AtomicBool::new(false); + + // No ordering requirement since this function is protected by the global lock. + if !INIT.swap(true, Ordering::Relaxed) { + (sgx_mem::heap_base() as _, sgx_mem::heap_size(), 0) + } else { + (ptr::null_mut(), 0, 0) + } + } + + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + ptr::null_mut() + } + + fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { + false + } + + fn free(&self, _ptr: *mut u8, _size: usize) -> bool { + return false; + } + + fn can_release_part(&self, _flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + false + } + + fn page_size(&self) -> usize { + 0x1000 + } +} #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/sys/sgx/ext/io.rs index f79874a4ae..795a4d190c 100644 --- a/library/std/src/sys/sgx/ext/io.rs +++ b/library/std/src/sys/sgx/ext/io.rs @@ -25,8 +25,11 @@ pub trait AsRawFd { /// descriptor. #[unstable(feature = "sgx_platform", issue = "56975")] pub trait FromRawFd { + /// An associated type that contains relevant metadata for `Self`. + type Metadata: Default; + /// Constructs a new instance of `Self` from the given raw file - /// descriptor. + /// descriptor and metadata. /// /// This function **consumes ownership** of the specified file /// descriptor. The returned object will take responsibility for closing @@ -38,7 +41,7 @@ pub trait FromRawFd { /// accidentally allow violating this contract which can cause memory /// unsafety in code that relies on it being true. #[unstable(feature = "sgx_platform", issue = "56975")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self; } /// A trait to express the ability to consume an object and acquire ownership of @@ -71,18 +74,40 @@ impl AsRawFd for net::TcpListener { } } +/// Metadata for `TcpStream`. +#[derive(Debug, Clone, Default)] +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct TcpStreamMetadata { + /// Local address of the TCP stream + pub local_addr: Option, + /// Peer address of the TCP stream + pub peer_addr: Option, +} + impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + type Metadata = TcpStreamMetadata; + + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream { let fd = sys::fd::FileDesc::from_inner(fd); - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, None))) + let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); + net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, metadata.peer_addr))) } } +/// Metadata for `TcpListener`. +#[derive(Debug, Clone, Default)] +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct TcpListenerMetadata { + /// Local address of the TCP listener + pub local_addr: Option, +} + impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + type Metadata = TcpListenerMetadata; + + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener { let fd = sys::fd::FileDesc::from_inner(fd); - let socket = sys::net::Socket::from_inner(fd); + let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket)) } } diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index 666a157b09..3dd8267921 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -37,9 +37,9 @@ impl TryIntoInner for Socket { } } -impl FromInner for Socket { - fn from_inner(inner: FileDesc) -> Socket { - Socket { inner: Arc::new(inner), local_addr: None } +impl FromInner<(FileDesc, Option)> for Socket { + fn from_inner((inner, local_addr): (FileDesc, Option)) -> Socket { + Socket { inner: Arc::new(inner), local_addr } } } diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs index d99ce895da..9140041c58 100644 --- a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs @@ -42,7 +42,7 @@ impl SpinMutex { #[inline(always)] pub fn try_lock(&self) -> Option> { - if !self.lock.compare_and_swap(false, true, Ordering::Acquire) { + if self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_ok() { Some(SpinMutexGuard { mutex: self }) } else { None diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 66bbc1c585..ba75b9bac8 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -841,7 +841,7 @@ impl DirEntryExt for fs::DirEntry { /// Creates a new symbolic link on the filesystem. /// -/// The `dst` path will be a symbolic link pointing to the `src` path. +/// The `link` path will be a symbolic link pointing to the `original` path. /// /// # Examples /// @@ -854,8 +854,8 @@ impl DirEntryExt for fs::DirEntry { /// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink(src.as_ref(), dst.as_ref()) +pub fn symlink, Q: AsRef>(original: P, link: Q) -> io::Result<()> { + sys::fs::symlink(original.as_ref(), link.as_ref()) } /// Unix-specific extensions to [`fs::DirBuilder`]. diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs deleted file mode 100644 index 3d2366554b..0000000000 --- a/library/std/src/sys/unix/ext/net.rs +++ /dev/null @@ -1,1768 +0,0 @@ -//! Unix-specific networking functionality. - -#![stable(feature = "unix_socket", since = "1.10.0")] - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] -#[allow(non_camel_case_types)] -mod libc { - pub use libc::c_int; - pub type socklen_t = u32; - pub struct sockaddr; - #[derive(Clone)] - pub struct sockaddr_un; -} - -use crate::ascii; -use crate::ffi::OsStr; -use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; -use crate::mem; -use crate::net::{self, Shutdown}; -use crate::os::unix::ffi::OsStrExt; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::path::Path; -use crate::sys::net::Socket; -use crate::sys::{self, cvt}; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; -use crate::time::Duration; - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -use crate::os::unix::ucred; - -#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -pub use ucred::UCred; - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -))] -use libc::MSG_NOSIGNAL; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -)))] -const MSG_NOSIGNAL: libc::c_int = 0x0; - -fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base -} - -unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); - addr.sun_family = libc::AF_UNIX as libc::sa_family_t; - - let bytes = path.as_os_str().as_bytes(); - - if bytes.contains(&0) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "paths may not contain interior null bytes", - )); - } - - if bytes.len() >= addr.sun_path.len() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "path must be shorter than SUN_LEN", - )); - } - for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct - - let mut len = sun_path_offset(&addr) + bytes.len(); - match bytes.get(0) { - Some(&0) | None => {} - Some(_) => len += 1, - } - Ok((addr, len as libc::socklen_t)) -} - -enum AddressKind<'a> { - Unnamed, - Pathname(&'a Path), - Abstract(&'a [u8]), -} - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - fn new(f: F) -> io::Result - where - F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket", - )); - } - - Ok(SocketAddr { addr, len }) - } - - /// Returns `true` if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// Ok(()) - /// } - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { true } else { false } - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// Ok(()) - /// } - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } - } - - fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - sun_path_offset(&self.addr); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut stream = UnixStream::connect("/path/to/my/socket")?; -/// stream.write_all(b"hello world")?; -/// let mut response = String::new(); -/// stream.read_to_string(&mut response)?; -/// println!("{}", response); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - inner(path.as_ref()) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Gets the peer credentials for this Unix domain socket. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(peer_credentials_unix_socket)] - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" - ))] - pub fn peer_cred(&self) -> io::Result { - ucred::peer_cred(self) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UdpSocket::bind("127.0.0.1:34254")?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - io::Read::read_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - io::Read::is_read_vectored(&&*self) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - io::Write::write_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - inner(path.as_ref()) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: crate::os::unix::net::UnixStream - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// This will result in the `accept` operation becoming nonblocking, - /// i.e., immediately returning from their calls. If the IO operation is - /// successful, `Ok` is returned and no further action is required. If the - /// IO operation could not be completed and needs to be retried, an error - /// with kind [`io::ErrorKind::WouldBlock`] is returned. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/tmp/sock")?; - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming(&self) -> Incoming<'_> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -/// A Unix datagram socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixDatagram; -/// -/// fn main() -> std::io::Result<()> { -/// let socket = UnixDatagram::bind("/path/to/my/socket")?; -/// socket.send_to(b"hello world", "/path/to/other/socket")?; -/// let mut buf = [0; 100]; -/// let (count, address) = socket.recv_from(&mut buf)?; -/// println!("socket {:?} sent {:?}", address, &buf[..count]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixDatagram(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixDatagram { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixDatagram"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixDatagram { - /// Creates a Unix datagram socket bound to the given path. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't bind: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - - Ok(socket) - } - } - inner(path.as_ref()) - } - - /// Creates a Unix Datagram socket which is not bound to any address. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::unbound() { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok(UnixDatagram(inner)) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixDatagrams`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let (sock1, sock2) = match UnixDatagram::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok((UnixDatagram(i1), UnixDatagram(i2))) - } - - /// Connects the socket to the specified address. - /// - /// The [`send`] method may be used to send data to the specified address. - /// [`recv`] and [`recv_from`] will only receive data from that address. - /// - /// [`send`]: UnixDatagram::send - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// match sock.connect("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return Err(e) - /// } - /// }; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; - - Ok(()) - } - } - inner(self, path.as_ref()) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixDatagram` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one side will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let sock_copy = sock.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixDatagram) - } - - /// Returns the address of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let addr = sock.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the address of this socket's peer. - /// - /// The [`connect`] method will connect the socket to a peer. - /// - /// [`connect`]: UnixDatagram::connect - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/path/to/the/socket")?; - /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - fn recv_from_flags( - &self, - buf: &mut [u8], - flags: libc::c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = libc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - flags, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read and the address from - /// whence the data came. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf = vec![0; 10]; - /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; - /// println!("received {} bytes from {:?}", size, sender); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, 0) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - /// Sends data on the socket to the specified address. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(libc::sendto( - *d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len, - ))?; - Ok(count as usize) - } - } - inner(self, buf, path.as_ref()) - } - - /// Sends data on the socket to the socket's peer. - /// - /// The peer address may be set by the `connect` method, and this method - /// will return an error if the socket has not already been connected. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] - /// is passed to this method. - /// - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`send`]: UnixDatagram::send - /// [`send_to`]: UnixDatagram::send_to - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shut down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } - - /// Receives a single datagram message on the socket, without removing it from the - /// queue. On success, returns the number of bytes read and the origin. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. - /// - /// Do not use this function to implement busy waiting, instead use `libc::poll` to - /// synchronize IO events on one or more sockets. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, libc::MSG_PEEK) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixDatagram { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixDatagram { - unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixDatagram { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/sys/unix/ext/net/addr.rs new file mode 100644 index 0000000000..1f9036242e --- /dev/null +++ b/library/std/src/sys/unix/ext/net/addr.rs @@ -0,0 +1,226 @@ +use crate::ffi::OsStr; +use crate::os::unix::ffi::OsStrExt; +use crate::path::Path; +use crate::sys::cvt; +use crate::{ascii, fmt, io, mem}; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +#[allow(non_camel_case_types)] +mod libc { + pub use libc::c_int; + pub type socklen_t = u32; + pub struct sockaddr; + #[derive(Clone)] + pub struct sockaddr_un; +} + +fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { + // Work with an actual instance of the type since using a null pointer is UB + let base = addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base +} + +pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + let bytes = path.as_os_str().as_bytes(); + + if bytes.contains(&0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "paths may not contain interior null bytes", + )); + } + + if bytes.len() >= addr.sun_path.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { + *dst = *src as libc::c_char; + } + // null byte for pathname addresses is already there because we zeroed the + // struct + + let mut len = sun_path_offset(&addr) + bytes.len(); + match bytes.get(0) { + Some(&0) | None => {} + Some(_) => len += 1, + } + Ok((addr, len as libc::socklen_t)) +} + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +struct AsciiEscaped<'a>(&'a [u8]); + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct SocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, +} + +impl SocketAddr { + pub(super) fn new(f: F) -> io::Result + where + F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, + { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as libc::socklen_t; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + + pub(super) fn from_parts( + addr: libc::sockaddr_un, + mut len: libc::socklen_t, + ) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address + } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket", + )); + } + + Ok(SocketAddr { addr, len }) + } + + /// Returns `true` if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// Ok(()) + /// } + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + if let AddressKind::Unnamed = self.address() { true } else { false } + } + + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// Ok(()) + /// } + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } + } + + fn address(&self) -> AddressKind<'_> { + let len = self.len as usize - sun_path_offset(&self.addr); + let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs new file mode 100644 index 0000000000..0964b6335a --- /dev/null +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -0,0 +1,664 @@ +use super::{sockaddr_un, SocketAddr}; +use crate::convert::TryFrom; +use crate::io::{self, IoSliceMut}; +use crate::marker::PhantomData; +use crate::mem::{size_of, zeroed}; +use crate::os::unix::io::RawFd; +use crate::path::Path; +#[cfg(target_os = "android")] +use crate::ptr::eq; +use crate::ptr::read_unaligned; +use crate::slice::from_raw_parts; +use crate::sys::net::Socket; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))] +#[allow(non_camel_case_types)] +mod libc { + pub use libc::c_int; + pub struct ucred; + pub struct cmsghdr; + pub type pid_t = i32; + pub type gid_t = u32; + pub type uid_t = u32; +} + +pub(super) fn recv_vectored_with_ancillary_from( + socket: &Socket, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result<(usize, bool, io::Result)> { + unsafe { + let mut msg_name: libc::sockaddr_un = zeroed(); + + let mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = size_of::() as libc::socklen_t; + msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_iovlen = bufs.len() as libc::size_t; + msg.msg_controllen = ancillary.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t; + } + } + + let count = socket.recv_msg(&mut msg)?; + + ancillary.length = msg.msg_controllen as usize; + ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC; + + let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC; + let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen); + + Ok((count, truncated, addr)) + } +} + +pub(super) fn send_vectored_with_ancillary_to( + socket: &Socket, + path: Option<&Path>, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result { + unsafe { + let (mut msg_name, msg_namelen) = + if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; + + let mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = msg_namelen; + msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_iovlen = bufs.len() as libc::size_t; + msg.msg_controllen = ancillary.length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.length as libc::socklen_t; + } + } + + ancillary.truncated = false; + + socket.send_msg(&mut msg) + } +} + +fn add_to_ancillary_data( + buffer: &mut [u8], + length: &mut usize, + source: &[T], + cmsg_level: libc::c_int, + cmsg_type: libc::c_int, +) -> bool { + let source_len = if let Some(source_len) = source.len().checked_mul(size_of::()) { + if let Ok(source_len) = u32::try_from(source_len) { + source_len + } else { + return false; + } + } else { + return false; + }; + + unsafe { + let additional_space = libc::CMSG_SPACE(source_len) as usize; + + let new_length = if let Some(new_length) = additional_space.checked_add(*length) { + new_length + } else { + return false; + }; + + if new_length > buffer.len() { + return false; + } + + buffer[*length..new_length].fill(0); + + *length = new_length; + + let mut msg: libc::msghdr = zeroed(); + msg.msg_control = buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = *length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = *length as libc::socklen_t; + } + } + + let mut cmsg = libc::CMSG_FIRSTHDR(&msg); + let mut previous_cmsg = cmsg; + while !cmsg.is_null() { + previous_cmsg = cmsg; + cmsg = libc::CMSG_NXTHDR(&msg, cmsg); + cfg_if::cfg_if! { + // Android return the same pointer if it is the last cmsg. + // Therefore, check it if the previous pointer is the same as the current one. + if #[cfg(target_os = "android")] { + if cmsg == previous_cmsg { + break; + } + } + } + } + + if previous_cmsg.is_null() { + return false; + } + + (*previous_cmsg).cmsg_level = cmsg_level; + (*previous_cmsg).cmsg_type = cmsg_type; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t; + } + } + + let data = libc::CMSG_DATA(previous_cmsg).cast(); + + libc::memcpy(data, source.as_ptr().cast(), source_len as usize); + } + true +} + +struct AncillaryDataIter<'a, T> { + data: &'a [u8], + phantom: PhantomData, +} + +impl<'a, T> AncillaryDataIter<'a, T> { + /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message. + /// + /// # Safety + /// + /// `data` must contain a valid control message. + unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { + AncillaryDataIter { data, phantom: PhantomData } + } +} + +impl<'a, T> Iterator for AncillaryDataIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + if size_of::() <= self.data.len() { + unsafe { + let unit = read_unaligned(self.data.as_ptr().cast()); + self.data = &self.data[size_of::()..]; + Some(unit) + } + } else { + None + } + } +} + +/// Unix credential. +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +#[derive(Clone)] +pub struct SocketCred(libc::ucred); + +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +impl SocketCred { + /// Create a Unix credential struct. + /// + /// PID, UID and GID is set to 0. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn new() -> SocketCred { + SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) + } + + /// Set the PID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_pid(&mut self, pid: libc::pid_t) { + self.0.pid = pid; + } + + /// Get the current PID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn get_pid(&self) -> libc::pid_t { + self.0.pid + } + + /// Set the UID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_uid(&mut self, uid: libc::uid_t) { + self.0.uid = uid; + } + + /// Get the current UID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn get_uid(&self) -> libc::uid_t { + self.0.uid + } + + /// Set the GID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_gid(&mut self, gid: libc::gid_t) { + self.0.gid = gid; + } + + /// Get the current GID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn get_gid(&self) -> libc::gid_t { + self.0.gid + } +} + +/// This control message contains file descriptors. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`. +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); + +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +impl<'a> Iterator for ScmRights<'a> { + type Item = RawFd; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +/// This control message contains unix credentials. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); + +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +impl<'a> Iterator for ScmCredentials<'a> { + type Item = SocketCred; + + fn next(&mut self) -> Option { + Some(SocketCred(self.0.next()?)) + } +} + +/// The error type which is returned from parsing the type a control message. +#[non_exhaustive] +#[derive(Debug)] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub enum AncillaryError { + Unknown { cmsg_level: i32, cmsg_type: i32 }, +} + +/// This enum represent one control message of variable type. +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub enum AncillaryData<'a> { + ScmRights(ScmRights<'a>), + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + ScmCredentials(ScmCredentials<'a>), +} + +impl<'a> AncillaryData<'a> { + /// Create a `AncillaryData::ScmRights` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_RIGHTS`. + unsafe fn as_rights(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_rights = ScmRights(ancillary_data_iter); + AncillaryData::ScmRights(scm_rights) + } + + /// Create a `AncillaryData::ScmCredentials` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + unsafe fn as_credentials(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_credentials = ScmCredentials(ancillary_data_iter); + AncillaryData::ScmCredentials(scm_credentials) + } + + fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { + unsafe { + cfg_if::cfg_if! { + if #[cfg(any( + target_os = "android", + all(target_os = "linux", target_env = "gnu"), + all(target_os = "linux", target_env = "uclibc"), + ))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t; + } + } + let data_len = (*cmsg).cmsg_len - cmsg_len_zero; + let data = libc::CMSG_DATA(cmsg).cast(); + let data = from_raw_parts(data, data_len as usize); + + match (*cmsg).cmsg_level { + libc::SOL_SOCKET => match (*cmsg).cmsg_type { + libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), + #[cfg(any(target_os = "android", target_os = "linux",))] + libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), + cmsg_type => { + Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) + } + }, + cmsg_level => { + Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type }) + } + } + } + } +} + +/// This struct is used to iterate through the control messages. +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub struct Messages<'a> { + buffer: &'a [u8], + current: Option<&'a libc::cmsghdr>, +} + +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +impl<'a> Iterator for Messages<'a> { + type Item = Result, AncillaryError>; + + fn next(&mut self) -> Option { + unsafe { + let mut msg: libc::msghdr = zeroed(); + msg.msg_control = self.buffer.as_ptr() as *mut _; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = self.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = self.buffer.len() as libc::socklen_t; + } + } + + let cmsg = if let Some(current) = self.current { + libc::CMSG_NXTHDR(&msg, current) + } else { + libc::CMSG_FIRSTHDR(&msg) + }; + + let cmsg = cmsg.as_ref()?; + cfg_if::cfg_if! { + // Android return the same pointer if it is the last cmsg. + // Therefore, check it if the previous pointer is the same as the current one. + if #[cfg(target_os = "android")] { + if let Some(current) = self.current { + if eq(current, cmsg) { + return None; + } + } + } + } + + self.current = Some(cmsg); + let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg); + Some(ancillary_result) + } + } +} + +/// A Unix socket Ancillary data struct. +/// +/// # Example +/// ```no_run +/// #![feature(unix_socket_ancillary_data)] +/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; +/// use std::io::IoSliceMut; +/// +/// fn main() -> std::io::Result<()> { +/// let sock = UnixStream::connect("/tmp/sock")?; +/// +/// let mut fds = [0; 8]; +/// let mut ancillary_buffer = [0; 128]; +/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); +/// +/// let mut buf = [1; 8]; +/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; +/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; +/// +/// for ancillary_result in ancillary.messages() { +/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { +/// for fd in scm_rights { +/// println!("receive file descriptor: {}", fd); +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +#[derive(Debug)] +pub struct SocketAncillary<'a> { + buffer: &'a mut [u8], + length: usize, + truncated: bool, +} + +impl<'a> SocketAncillary<'a> { + /// Create an ancillary data with the given buffer. + /// + /// # Example + /// + /// ```no_run + /// # #![allow(unused_mut)] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::SocketAncillary; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn new(buffer: &'a mut [u8]) -> Self { + SocketAncillary { buffer, length: 0, truncated: false } + } + + /// Returns the capacity of the buffer. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn capacity(&self) -> usize { + self.buffer.len() + } + + /// Returns the number of used bytes. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn len(&self) -> usize { + self.length + } + + /// Returns the iterator of the control messages. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn messages(&self) -> Messages<'_> { + Messages { buffer: &self.buffer[..self.length], current: None } + } + + /// Is `true` if during a recv operation the ancillary was truncated. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// + /// println!("Is truncated: {}", ancillary.truncated()); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn truncated(&self) -> bool { + self.truncated + } + + /// Add file descriptors to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no file descriptors was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_RIGHTS`. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::os::unix::io::AsRawFd; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&[sock.as_raw_fd()][..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + fds, + libc::SOL_SOCKET, + libc::SCM_RIGHTS, + ) + } + + /// Add credentials to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no credentials was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. + /// + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + creds, + libc::SOL_SOCKET, + libc::SCM_CREDENTIALS, + ) + } + + /// Clears the ancillary data, removing all values. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut fds1 = [0; 8]; + /// let mut fds2 = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// + /// ancillary.clear(); + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn clear(&mut self) { + self.length = 0; + self.truncated = false; + } +} diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs new file mode 100644 index 0000000000..0f532c47c8 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -0,0 +1,897 @@ +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; +use super::{sockaddr_un, SocketAddr}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use crate::io::IoSliceMut; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; +use crate::{fmt, io}; + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +)))] +const MSG_NOSIGNAL: libc::c_int = 0x0; + +/// A Unix datagram socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixDatagram; +/// +/// fn main() -> std::io::Result<()> { +/// let socket = UnixDatagram::bind("/path/to/my/socket")?; +/// socket.send_to(b"hello world", "/path/to/other/socket")?; +/// let mut buf = [0; 100]; +/// let (count, address) = socket.recv_from(&mut buf)?; +/// println!("socket {:?} sent {:?}", address, &buf[..count]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixDatagram(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixDatagram { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixDatagram"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixDatagram { + /// Creates a Unix datagram socket bound to the given path. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't bind: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + unsafe { + let socket = UnixDatagram::unbound()?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + + Ok(socket) + } + } + + /// Creates a Unix Datagram socket which is not bound to any address. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::unbound() { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn unbound() -> io::Result { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok(UnixDatagram(inner)) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixDatagrams`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let (sock1, sock2) = match UnixDatagram::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok((UnixDatagram(i1), UnixDatagram(i2))) + } + + /// Connects the socket to the specified address. + /// + /// The [`send`] method may be used to send data to the specified address. + /// [`recv`] and [`recv_from`] will only receive data from that address. + /// + /// [`send`]: UnixDatagram::send + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(&self, path: P) -> io::Result<()> { + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?; + } + Ok(()) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixDatagram` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one side will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixDatagram) + } + + /// Returns the address of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the address of this socket's peer. + /// + /// The [`connect`] method will connect the socket to a peer. + /// + /// [`connect`]: UnixDatagram::connect + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/path/to/the/socket")?; + /// + /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = libc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read and the address from + /// whence the data came. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf = vec![0; 10]; + /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; + /// println!("received {} bytes from {:?}", size, sender); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, 0) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let mut buf = vec![0; 10]; + /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn recv_vectored_with_ancillary_from( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool, SocketAddr)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + let addr = addr?; + + Ok((count, truncated, addr)) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read and if the data was truncated. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + addr?; + + Ok((count, truncated)) + } + + /// Sends data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; + + let count = cvt(libc::sendto( + *self.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &addr as *const _ as *const _, + len, + ))?; + Ok(count as usize) + } + } + + /// Sends data on the socket to the socket's peer. + /// + /// The peer address may be set by the `connect` method, and this method + /// will return an error if the socket has not already been connected. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/some/sock").expect("Couldn't connect"); + /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + /// Sends data and ancillary data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn send_vectored_with_ancillary_to>( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + path: P, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] + /// is passed to this method. + /// + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`send`]: UnixDatagram::send + /// [`send_to`]: UnixDatagram::send_to + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_passcred(true).expect("set_passcred function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixDatagram::set_passcred + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// if let Ok(Some(err)) = sock.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shut down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixDatagram { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixDatagram { + unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { + UnixDatagram(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixDatagram { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs new file mode 100644 index 0000000000..9803c6e274 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -0,0 +1,319 @@ +use super::{sockaddr_un, SocketAddr, UnixStream}; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{fmt, io, mem}; + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: crate::os::unix::net::UnixStream + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = SocketAddr::from_parts(storage, len)?; + Ok((UnixStream(sock), addr)) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// This will result in the `accept` operation becoming nonblocking, + /// i.e., immediately returning from their calls. If the IO operation is + /// successful, `Ok` is returned and no further action is required. If the + /// IO operation could not be completed and needs to be retried, an error + /// with kind [`io::ErrorKind::WouldBlock`] is returned. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/tmp/sock")?; + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming(&self) -> Incoming<'_> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs new file mode 100644 index 0000000000..3088ffb5e5 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -0,0 +1,54 @@ +//! Unix-specific networking functionality + +#![stable(feature = "unix_socket", since = "1.10.0")] + +mod addr; +#[doc(cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +)))] +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +mod ancillary; +mod datagram; +mod listener; +mod raw_fd; +mod stream; +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::addr::*; +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub use self::ancillary::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::datagram::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::listener::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::raw_fd::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::stream::*; diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs new file mode 100644 index 0000000000..c42fee4c73 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/raw_fd.rs @@ -0,0 +1,40 @@ +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::{net, sys}; + +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + let socket = sys::net::Socket::from_inner(fd); + net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs new file mode 100644 index 0000000000..9fe6b85837 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -0,0 +1,673 @@ +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; +use super::{sockaddr_un, SocketAddr}; +use crate::fmt; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// fn main() -> std::io::Result<()> { +/// let mut stream = UnixStream::connect("/path/to/my/socket")?; +/// stream.write_all(b"hello world")?; +/// let mut response = String::new(); +/// stream.read_to_string(&mut response)?; +/// println!("{}", response); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(pub(super) Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; + Ok((UnixStream(i1), UnixStream(i2))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peer_credentials_unix_socket)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UdpSocket::bind("127.0.0.1:34254")?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_passcred(true).expect("Couldn't set passcred"); + /// Ok(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixStream::set_passcred + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + + Ok(count) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::Read::read_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + io::Read::is_read_vectored(&&*self) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + io::Write::write_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index ee73a6ed53..97a016904b 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -1,11 +1,30 @@ +use super::*; use crate::io::prelude::*; -use crate::io::{self, ErrorKind}; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use crate::iter::FromIterator; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use crate::os::unix::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; use crate::time::Duration; -use super::*; - macro_rules! or_panic { ($e:expr) => { match $e { @@ -452,3 +471,170 @@ fn test_unix_datagram_peek_from() { assert_eq!(size, 11); assert_eq!(msg, &buf[..]); } + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +#[test] +fn test_send_vectored_fds_unix_stream() { + let (s1, s2) = or_panic!(UnixStream::pair()); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..])); + + let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + unreachable!("must be ScmRights"); + } +} + +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[test] +fn test_send_vectored_with_ancillary_to_unix_datagram() { + fn getpid() -> libc::pid_t { + unsafe { libc::getpid() } + } + + fn getuid() -> libc::uid_t { + unsafe { libc::getuid() } + } + + fn getgid() -> libc::gid_t { + unsafe { libc::getgid() } + } + + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + or_panic!(bsock2.set_passcred(true)); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + let mut cred1 = SocketCred::new(); + cred1.set_pid(getpid()); + cred1.set_uid(getuid()); + cred1.set_gid(getgid()); + assert!(ancillary1.add_creds(&[cred1.clone()][..])); + + let usize = + or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated, _addr) = + or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2)); + assert_eq!(ancillary2.truncated(), false); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmCredentials(scm_credentials) = + ancillary_data_vec.pop().unwrap().unwrap() + { + let cred_vec = Vec::from_iter(scm_credentials); + assert_eq!(cred_vec.len(), 1); + assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); + assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); + assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); + } else { + unreachable!("must be ScmCredentials"); + } +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +#[test] +fn test_send_vectored_with_ancillary_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..])); + + or_panic!(bsock1.connect(&path2)); + let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated) = + or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + unreachable!("must be ScmRights"); + } +} diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index ed7516c7f2..1b4c18d3d8 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -28,15 +28,12 @@ pub struct UCred { #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::impl_linux::peer_cred; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] +#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] pub use self::impl_bsd::peer_cred; +#[cfg(any(target_os = "macos", target_os = "ios",))] +pub use self::impl_mac::peer_cred; + #[cfg(any(target_os = "linux", target_os = "android"))] pub mod impl_linux { use super::UCred; @@ -73,13 +70,7 @@ pub mod impl_linux { } } -#[cfg(any( - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd" -))] +#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] pub mod impl_bsd { use super::UCred; use crate::io; @@ -95,3 +86,41 @@ pub mod impl_bsd { } } } + +#[cfg(any(target_os = "macos", target_os = "ios",))] +pub mod impl_mac { + use super::UCred; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + use crate::{io, mem}; + use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL}; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + let mut cred = UCred { uid: 1, gid: 1, pid: None }; + unsafe { + let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); + + if ret != 0 { + return Err(io::Error::last_os_error()); + } + + let mut pid: pid_t = 1; + let mut pid_size = mem::size_of::() as socklen_t; + + let ret = getsockopt( + socket.as_raw_fd(), + SOL_LOCAL, + LOCAL_PEERPID, + &mut pid as *mut pid_t as *mut c_void, + &mut pid_size, + ); + + if ret == 0 && pid_size as usize == mem::size_of::() { + cred.pid = Some(pid); + Ok(cred) + } else { + Err(io::Error::last_os_error()) + } + } + } +} diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs index 451b534b26..42d79418cf 100644 --- a/library/std/src/sys/unix/ext/ucred/tests.rs +++ b/library/std/src/sys/unix/ext/ucred/tests.rs @@ -1,5 +1,5 @@ use crate::os::unix::net::UnixStream; -use libc::{getegid, geteuid}; +use libc::{getegid, geteuid, getpid}; #[test] #[cfg(any( @@ -23,3 +23,16 @@ fn test_socket_pair() { assert_eq!(cred_a.uid, uid); assert_eq!(cred_a.gid, gid); } + +#[test] +#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))] +fn test_socket_pair_pids(arg: Type) -> RetType { + // Create two connected sockets and get their peer credentials. + let (sock_a, sock_b) = UnixStream::pair().unwrap(); + let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); + + // On supported platforms (see the cfg above), the credentials should always include the PID. + let pid = unsafe { getpid() }; + assert_eq!(cred_a.pid, Some(pid)); + assert_eq!(cred_b.pid, Some(pid)); +} diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index d3a279a235..821851a6c6 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -12,6 +12,11 @@ use crate::sys_common::AsInner; use libc::{c_int, c_void}; #[derive(Debug)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] pub struct FileDesc { fd: c_int, } @@ -63,7 +68,9 @@ const fn max_iov() -> usize { impl FileDesc { pub fn new(fd: c_int) -> FileDesc { - FileDesc { fd } + assert_ne!(fd, -1i32); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { FileDesc { fd } } } pub fn raw(&self) -> c_int { diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs index a932043cbc..c9520485c3 100644 --- a/library/std/src/sys/unix/fd/tests.rs +++ b/library/std/src/sys/unix/fd/tests.rs @@ -3,7 +3,7 @@ use core::mem::ManuallyDrop; #[test] fn limit_vector_count() { - let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); + let stdout = ManuallyDrop::new(unsafe { FileDesc { fd: 1 } }); let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); assert!(stdout.write_vectored(&bufs).is_ok()); } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index f3dd1558f1..d1b0ad9e5f 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1071,28 +1071,28 @@ pub fn readlink(p: &Path) -> io::Result { } } -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?; +pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + let original = cstr(original)?; + let link = cstr(link)?; + cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) })?; Ok(()) } -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; +pub fn link(original: &Path, link: &Path) -> io::Result<()> { + let original = cstr(original)?; + let link = cstr(link)?; cfg_if::cfg_if! { if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] { // VxWorks, Redox, and old versions of Android lack `linkat`, so use // `link` instead. POSIX leaves it implementation-defined whether // `link` follows symlinks, so rely on the `symlink_hard_link` test // in library/std/src/fs/tests.rs to check the behavior. - cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?; + cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; } else { // Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives // us a flag to specify how symlinks should be handled. Pass 0 as // the flags argument, meaning don't follow symlinks. - cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?; + cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; } } Ok(()) @@ -1204,88 +1204,20 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { #[cfg(any(target_os = "linux", target_os = "android"))] pub fn copy(from: &Path, to: &Path) -> io::Result { - use crate::cmp; - use crate::sync::atomic::{AtomicBool, Ordering}; - - // Kernel prior to 4.5 don't have copy_file_range - // We store the availability in a global to avoid unnecessary syscalls - static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(false); - - unsafe fn copy_file_range( - fd_in: libc::c_int, - off_in: *mut libc::loff_t, - fd_out: libc::c_int, - off_out: *mut libc::loff_t, - len: libc::size_t, - flags: libc::c_uint, - ) -> libc::c_long { - libc::syscall(libc::SYS_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags) - } - let (mut reader, reader_metadata) = open_from(from)?; let max_len = u64::MAX; let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; - let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); - let mut written = 0u64; - while written < max_len { - let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64) as usize; - let copy_result = unsafe { - // We actually don't have to adjust the offsets, - // because copy_file_range adjusts the file offset automatically - cvt(copy_file_range( - reader.as_raw_fd(), - ptr::null_mut(), - writer.as_raw_fd(), - ptr::null_mut(), - bytes_to_copy, - 0, - )) - }; - if let Err(ref copy_err) = copy_result { - match copy_err.raw_os_error() { - Some(libc::ENOSYS | libc::EPERM | libc::EOPNOTSUPP) => { - HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); - } - _ => {} - } - } - copy_result - } else { - Err(io::Error::from_raw_os_error(libc::ENOSYS)) - }; - match copy_result { - Ok(0) if written == 0 => { - // fallback to work around several kernel bugs where copy_file_range will fail to - // copy any bytes and return 0 instead of an error if - // - reading virtual files from the proc filesystem which appear to have 0 size - // but are not empty. noted in coreutils to affect kernels at least up to 5.6.19. - // - copying from an overlay filesystem in docker. reported to occur on fedora 32. - return io::copy(&mut reader, &mut writer); - } - Ok(0) => return Ok(written), // reached EOF - Ok(ret) => written += ret as u64, - Err(err) => { - match err.raw_os_error() { - Some( - libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP, - ) => { - // Try fallback io::copy if either: - // - Kernel version is < 4.5 (ENOSYS) - // - Files are mounted on different fs (EXDEV) - // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP) - // - copy_file_range is disallowed, for example by seccomp (EPERM) - // - copy_file_range cannot be used with pipes or device nodes (EINVAL) - assert_eq!(written, 0); - return io::copy(&mut reader, &mut writer); - } - _ => return Err(err), - } - } - } + use super::kernel_copy::{copy_regular_files, CopyResult}; + + match copy_regular_files(reader.as_raw_fd(), writer.as_raw_fd(), max_len) { + CopyResult::Ended(bytes) => Ok(bytes), + CopyResult::Error(e, _) => Err(e), + CopyResult::Fallback(written) => match io::copy::generic_copy(&mut reader, &mut writer) { + Ok(bytes) => Ok(bytes + written), + Err(e) => Err(e), + }, } - Ok(written) } #[cfg(any(target_os = "macos", target_os = "ios"))] diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs new file mode 100644 index 0000000000..200dbf06ff --- /dev/null +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -0,0 +1,676 @@ +//! This module contains specializations that can offload `io::copy()` operations on file descriptor +//! containing types (`File`, `TcpStream`, etc.) to more efficient syscalls than `read(2)` and `write(2)`. +//! +//! Specialization is only applied to wholly std-owned types so that user code can't observe +//! that the `Read` and `Write` traits are not used. +//! +//! Since a copy operation involves a reader and writer side where each can consist of different types +//! and also involve generic wrappers (e.g. `Take`, `BufReader`) it is not practical to specialize +//! a single method on all possible combinations. +//! +//! Instead readers and writers are handled separately by the `CopyRead` and `CopyWrite` specialization +//! traits and then specialized on by the `Copier::copy` method. +//! +//! `Copier` uses the specialization traits to unpack the underlying file descriptors and +//! additional prerequisites and constraints imposed by the wrapper types. +//! +//! Once it has obtained all necessary pieces and brought any wrapper types into a state where they +//! can be safely bypassed it will attempt to use the `copy_file_range(2)`, +//! `sendfile(2)` or `splice(2)` syscalls to move data directly between file descriptors. +//! Since those syscalls have requirements that cannot be fully checked in advance and +//! gathering additional information about file descriptors would require additional syscalls +//! anyway it simply attempts to use them one after another (guided by inaccurate hints) to +//! figure out which one works and and falls back to the generic read-write copy loop if none of them +//! does. +//! Once a working syscall is found for a pair of file descriptors it will be called in a loop +//! until the copy operation is completed. +//! +//! Advantages of using these syscalls: +//! +//! * fewer context switches since reads and writes are coalesced into a single syscall +//! and more bytes are transferred per syscall. This translates to higher throughput +//! and fewer CPU cycles, at least for sufficiently large transfers to amortize the initial probing. +//! * `copy_file_range` creates reflink copies on CoW filesystems, thus moving less data and +//! consuming less disk space +//! * `sendfile` and `splice` can perform zero-copy IO under some circumstances while +//! a naive copy loop would move every byte through the CPU. +//! +//! Drawbacks: +//! +//! * copy operations smaller than the default buffer size can under some circumstances, especially +//! on older kernels, incur more syscalls than the naive approach would. As mentioned above +//! the syscall selection is guided by hints to minimize this possibility but they are not perfect. +//! * optimizations only apply to std types. If a user adds a custom wrapper type, e.g. to report +//! progress, they can hit a performance cliff. +//! * complexity + +use crate::cmp::min; +use crate::convert::TryInto; +use crate::fs::{File, Metadata}; +use crate::io::copy::generic_copy; +use crate::io::{ + BufRead, BufReader, BufWriter, Error, Read, Result, StderrLock, StdinLock, StdoutLock, Take, + Write, +}; +use crate::mem::ManuallyDrop; +use crate::net::TcpStream; +use crate::os::unix::fs::FileTypeExt; +use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use crate::os::unix::net::UnixStream; +use crate::process::{ChildStderr, ChildStdin, ChildStdout}; +use crate::ptr; +use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; +use crate::sys::cvt; + +#[cfg(test)] +mod tests; + +pub(crate) fn copy_spec( + read: &mut R, + write: &mut W, +) -> Result { + let copier = Copier { read, write }; + SpecCopy::copy(copier) +} + +/// This type represents either the inferred `FileType` of a `RawFd` based on the source +/// type from which it was extracted or the actual metadata +/// +/// The methods on this type only provide hints, due to `AsRawFd` and `FromRawFd` the inferred +/// type may be wrong. +enum FdMeta { + /// We obtained the FD from a type that can contain any type of `FileType` and queried the metadata + /// because it is cheaper than probing all possible syscalls (reader side) + Metadata(Metadata), + Socket, + Pipe, + /// We don't have any metadata, e.g. because the original type was `File` which can represent + /// any `FileType` and we did not query the metadata either since it did not seem beneficial + /// (writer side) + NoneObtained, +} + +impl FdMeta { + fn maybe_fifo(&self) -> bool { + match self { + FdMeta::Metadata(meta) => meta.file_type().is_fifo(), + FdMeta::Socket => false, + FdMeta::Pipe => true, + FdMeta::NoneObtained => true, + } + } + + fn potential_sendfile_source(&self) -> bool { + match self { + // procfs erronously shows 0 length on non-empty readable files. + // and if a file is truly empty then a `read` syscall will determine that and skip the write syscall + // thus there would be benefit from attempting sendfile + FdMeta::Metadata(meta) + if meta.file_type().is_file() && meta.len() > 0 + || meta.file_type().is_block_device() => + { + true + } + _ => false, + } + } + + fn copy_file_range_candidate(&self) -> bool { + match self { + // copy_file_range will fail on empty procfs files. `read` can determine whether EOF has been reached + // without extra cost and skip the write, thus there is no benefit in attempting copy_file_range + FdMeta::Metadata(meta) if meta.is_file() && meta.len() > 0 => true, + FdMeta::NoneObtained => true, + _ => false, + } + } +} + +struct CopyParams(FdMeta, Option); + +struct Copier<'a, 'b, R: Read + ?Sized, W: Write + ?Sized> { + read: &'a mut R, + write: &'b mut W, +} + +trait SpecCopy { + fn copy(self) -> Result; +} + +impl SpecCopy for Copier<'_, '_, R, W> { + default fn copy(self) -> Result { + generic_copy(self.read, self.write) + } +} + +impl SpecCopy for Copier<'_, '_, R, W> { + fn copy(self) -> Result { + let (reader, writer) = (self.read, self.write); + let r_cfg = reader.properties(); + let w_cfg = writer.properties(); + + // before direct operations on file descriptors ensure that all source and sink buffers are empty + let mut flush = || -> crate::io::Result { + let bytes = reader.drain_to(writer, u64::MAX)?; + // BufWriter buffered bytes have already been accounted for in earlier write() calls + writer.flush()?; + Ok(bytes) + }; + + let mut written = 0u64; + + if let (CopyParams(input_meta, Some(readfd)), CopyParams(output_meta, Some(writefd))) = + (r_cfg, w_cfg) + { + written += flush()?; + let max_write = reader.min_limit(); + + if input_meta.copy_file_range_candidate() && output_meta.copy_file_range_candidate() { + let result = copy_regular_files(readfd, writefd, max_write); + result.update_take(reader); + + match result { + CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Error(e, _) => return Err(e), + CopyResult::Fallback(bytes) => written += bytes, + } + } + + // on modern kernels sendfile can copy from any mmapable type (some but not all regular files and block devices) + // to any writable file descriptor. On older kernels the writer side can only be a socket. + // So we just try and fallback if needed. + // If current file offsets + write sizes overflow it may also fail, we do not try to fix that and instead + // fall back to the generic copy loop. + if input_meta.potential_sendfile_source() { + let result = sendfile_splice(SpliceMode::Sendfile, readfd, writefd, max_write); + result.update_take(reader); + + match result { + CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Error(e, _) => return Err(e), + CopyResult::Fallback(bytes) => written += bytes, + } + } + + if input_meta.maybe_fifo() || output_meta.maybe_fifo() { + let result = sendfile_splice(SpliceMode::Splice, readfd, writefd, max_write); + result.update_take(reader); + + match result { + CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Error(e, _) => return Err(e), + CopyResult::Fallback(0) => { /* use the fallback below */ } + CopyResult::Fallback(_) => { + unreachable!("splice should not return > 0 bytes on the fallback path") + } + } + } + } + + // fallback if none of the more specialized syscalls wants to work with these file descriptors + match generic_copy(reader, writer) { + Ok(bytes) => Ok(bytes + written), + err => err, + } + } +} + +#[rustc_specialization_trait] +trait CopyRead: Read { + /// Implementations that contain buffers (i.e. `BufReader`) must transfer data from their internal + /// buffers into `writer` until either the buffers are emptied or `limit` bytes have been + /// transferred, whichever occurs sooner. + /// If nested buffers are present the outer buffers must be drained first. + /// + /// This is necessary to directly bypass the wrapper types while preserving the data order + /// when operating directly on the underlying file descriptors. + fn drain_to(&mut self, _writer: &mut W, _limit: u64) -> Result { + Ok(0) + } + + /// Updates `Take` wrappers to remove the number of bytes copied. + fn taken(&mut self, _bytes: u64) {} + + /// The minimum of the limit of all `Take<_>` wrappers, `u64::MAX` otherwise. + /// This method does not account for data `BufReader` buffers and would underreport + /// the limit of a `Take>>` type. Thus its result is only valid + /// after draining the buffers via `drain_to`. + fn min_limit(&self) -> u64 { + u64::MAX + } + + /// Extracts the file descriptor and hints/metadata, delegating through wrappers if necessary. + fn properties(&self) -> CopyParams; +} + +#[rustc_specialization_trait] +trait CopyWrite: Write { + /// Extracts the file descriptor and hints/metadata, delegating through wrappers if necessary. + fn properties(&self) -> CopyParams; +} + +impl CopyRead for &mut T +where + T: CopyRead, +{ + fn drain_to(&mut self, writer: &mut W, limit: u64) -> Result { + (**self).drain_to(writer, limit) + } + + fn taken(&mut self, bytes: u64) { + (**self).taken(bytes); + } + + fn min_limit(&self) -> u64 { + (**self).min_limit() + } + + fn properties(&self) -> CopyParams { + (**self).properties() + } +} + +impl CopyWrite for &mut T +where + T: CopyWrite, +{ + fn properties(&self) -> CopyParams { + (**self).properties() + } +} + +impl CopyRead for File { + fn properties(&self) -> CopyParams { + CopyParams(fd_to_meta(self), Some(self.as_raw_fd())) + } +} + +impl CopyRead for &File { + fn properties(&self) -> CopyParams { + CopyParams(fd_to_meta(*self), Some(self.as_raw_fd())) + } +} + +impl CopyWrite for File { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + } +} + +impl CopyWrite for &File { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + } +} + +impl CopyRead for TcpStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyRead for &TcpStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyWrite for TcpStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyWrite for &TcpStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyRead for UnixStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyRead for &UnixStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyWrite for UnixStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyWrite for &UnixStream { + fn properties(&self) -> CopyParams { + // avoid the stat syscall since we can be fairly sure it's a socket + CopyParams(FdMeta::Socket, Some(self.as_raw_fd())) + } +} + +impl CopyWrite for ChildStdin { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::Pipe, Some(self.as_raw_fd())) + } +} + +impl CopyRead for ChildStdout { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::Pipe, Some(self.as_raw_fd())) + } +} + +impl CopyRead for ChildStderr { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::Pipe, Some(self.as_raw_fd())) + } +} + +impl CopyRead for StdinLock<'_> { + fn drain_to(&mut self, writer: &mut W, outer_limit: u64) -> Result { + let buf_reader = self.as_mut_buf(); + let buf = buf_reader.buffer(); + let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))]; + let bytes_drained = buf.len(); + writer.write_all(buf)?; + buf_reader.consume(bytes_drained); + + Ok(bytes_drained as u64) + } + + fn properties(&self) -> CopyParams { + CopyParams(fd_to_meta(self), Some(self.as_raw_fd())) + } +} + +impl CopyWrite for StdoutLock<'_> { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + } +} + +impl CopyWrite for StderrLock<'_> { + fn properties(&self) -> CopyParams { + CopyParams(FdMeta::NoneObtained, Some(self.as_raw_fd())) + } +} + +impl CopyRead for Take { + fn drain_to(&mut self, writer: &mut W, outer_limit: u64) -> Result { + let local_limit = self.limit(); + let combined_limit = min(outer_limit, local_limit); + let bytes_drained = self.get_mut().drain_to(writer, combined_limit)?; + // update limit since read() was bypassed + self.set_limit(local_limit - bytes_drained); + + Ok(bytes_drained) + } + + fn taken(&mut self, bytes: u64) { + self.set_limit(self.limit() - bytes); + self.get_mut().taken(bytes); + } + + fn min_limit(&self) -> u64 { + min(Take::limit(self), self.get_ref().min_limit()) + } + + fn properties(&self) -> CopyParams { + self.get_ref().properties() + } +} + +impl CopyRead for BufReader { + fn drain_to(&mut self, writer: &mut W, outer_limit: u64) -> Result { + let buf = self.buffer(); + let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))]; + let bytes = buf.len(); + writer.write_all(buf)?; + self.consume(bytes); + + let remaining = outer_limit - bytes as u64; + + // in case of nested bufreaders we also need to drain the ones closer to the source + let inner_bytes = self.get_mut().drain_to(writer, remaining)?; + + Ok(bytes as u64 + inner_bytes) + } + + fn taken(&mut self, bytes: u64) { + self.get_mut().taken(bytes); + } + + fn min_limit(&self) -> u64 { + self.get_ref().min_limit() + } + + fn properties(&self) -> CopyParams { + self.get_ref().properties() + } +} + +impl CopyWrite for BufWriter { + fn properties(&self) -> CopyParams { + self.get_ref().properties() + } +} + +fn fd_to_meta(fd: &T) -> FdMeta { + let fd = fd.as_raw_fd(); + let file: ManuallyDrop = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) }); + match file.metadata() { + Ok(meta) => FdMeta::Metadata(meta), + Err(_) => FdMeta::NoneObtained, + } +} + +pub(super) enum CopyResult { + Ended(u64), + Error(Error, u64), + Fallback(u64), +} + +impl CopyResult { + fn update_take(&self, reader: &mut impl CopyRead) { + match *self { + CopyResult::Fallback(bytes) + | CopyResult::Ended(bytes) + | CopyResult::Error(_, bytes) => reader.taken(bytes), + } + } +} + +/// Invalid file descriptor. +/// +/// Valid file descriptors are guaranteed to be positive numbers (see `open()` manpage) +/// while negative values are used to indicate errors. +/// Thus -1 will never be overlap with a valid open file. +const INVALID_FD: RawFd = -1; + +/// Linux-specific implementation that will attempt to use copy_file_range for copy offloading. +/// As the name says, it only works on regular files. +/// +/// Callers must handle fallback to a generic copy loop. +/// `Fallback` may indicate non-zero number of bytes already written +/// if one of the files' cursor +`max_len` would exceed u64::MAX (`EOVERFLOW`). +pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult { + use crate::cmp; + + const NOT_PROBED: u8 = 0; + const UNAVAILABLE: u8 = 1; + const AVAILABLE: u8 = 2; + + // Kernel prior to 4.5 don't have copy_file_range + // We store the availability in a global to avoid unnecessary syscalls + static HAS_COPY_FILE_RANGE: AtomicU8 = AtomicU8::new(NOT_PROBED); + + syscall! { + fn copy_file_range( + fd_in: libc::c_int, + off_in: *mut libc::loff_t, + fd_out: libc::c_int, + off_out: *mut libc::loff_t, + len: libc::size_t, + flags: libc::c_uint + ) -> libc::ssize_t + } + + match HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) { + NOT_PROBED => { + // EPERM can indicate seccomp filters or an immutable file. + // To distinguish these cases we probe with invalid file descriptors which should result in EBADF if the syscall is supported + // and some other error (ENOSYS or EPERM) if it's not available + let result = unsafe { + cvt(copy_file_range(INVALID_FD, ptr::null_mut(), INVALID_FD, ptr::null_mut(), 1, 0)) + }; + + if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(libc::EBADF))) { + HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed); + } else { + HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed); + return CopyResult::Fallback(0); + } + } + UNAVAILABLE => return CopyResult::Fallback(0), + _ => {} + }; + + let mut written = 0u64; + while written < max_len { + let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64); + // cap to 1GB chunks in case u64::MAX is passed as max_len and the file has a non-zero seek position + // this allows us to copy large chunks without hitting EOVERFLOW, + // unless someone sets a file offset close to u64::MAX - 1GB, in which case a fallback would be required + let bytes_to_copy = cmp::min(bytes_to_copy as usize, 0x4000_0000usize); + let copy_result = unsafe { + // We actually don't have to adjust the offsets, + // because copy_file_range adjusts the file offset automatically + cvt(copy_file_range(reader, ptr::null_mut(), writer, ptr::null_mut(), bytes_to_copy, 0)) + }; + + match copy_result { + Ok(0) if written == 0 => { + // fallback to work around several kernel bugs where copy_file_range will fail to + // copy any bytes and return 0 instead of an error if + // - reading virtual files from the proc filesystem which appear to have 0 size + // but are not empty. noted in coreutils to affect kernels at least up to 5.6.19. + // - copying from an overlay filesystem in docker. reported to occur on fedora 32. + return CopyResult::Fallback(0); + } + Ok(0) => return CopyResult::Ended(written), // reached EOF + Ok(ret) => written += ret as u64, + Err(err) => { + return match err.raw_os_error() { + // when file offset + max_length > u64::MAX + Some(libc::EOVERFLOW) => CopyResult::Fallback(written), + Some( + libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP, + ) => { + // Try fallback io::copy if either: + // - Kernel version is < 4.5 (ENOSYS¹) + // - Files are mounted on different fs (EXDEV) + // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP) + // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM) + // - copy_file_range cannot be used with pipes or device nodes (EINVAL) + // + // ¹ these cases should be detected by the initial probe but we handle them here + // anyway in case syscall interception changes during runtime + assert_eq!(written, 0); + CopyResult::Fallback(0) + } + _ => CopyResult::Error(err, written), + }; + } + } + } + CopyResult::Ended(written) +} + +#[derive(PartialEq)] +enum SpliceMode { + Sendfile, + Splice, +} + +/// performs splice or sendfile between file descriptors +/// Does _not_ fall back to a generic copy loop. +fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> CopyResult { + static HAS_SENDFILE: AtomicBool = AtomicBool::new(true); + static HAS_SPLICE: AtomicBool = AtomicBool::new(true); + + syscall! { + fn splice( + srcfd: libc::c_int, + src_offset: *const i64, + dstfd: libc::c_int, + dst_offset: *const i64, + len: libc::size_t, + flags: libc::c_int + ) -> libc::ssize_t + } + + match mode { + SpliceMode::Sendfile if !HAS_SENDFILE.load(Ordering::Relaxed) => { + return CopyResult::Fallback(0); + } + SpliceMode::Splice if !HAS_SPLICE.load(Ordering::Relaxed) => { + return CopyResult::Fallback(0); + } + _ => (), + } + + let mut written = 0u64; + while written < len { + // according to its manpage that's the maximum size sendfile() will copy per invocation + let chunk_size = crate::cmp::min(len - written, 0x7ffff000_u64) as usize; + + let result = match mode { + SpliceMode::Sendfile => { + cvt(unsafe { libc::sendfile(writer, reader, ptr::null_mut(), chunk_size) }) + } + SpliceMode::Splice => cvt(unsafe { + splice(reader, ptr::null_mut(), writer, ptr::null_mut(), chunk_size, 0) + }), + }; + + match result { + Ok(0) => break, // EOF + Ok(ret) => written += ret as u64, + Err(err) => { + return match err.raw_os_error() { + Some(libc::ENOSYS | libc::EPERM) => { + // syscall not supported (ENOSYS) + // syscall is disallowed, e.g. by seccomp (EPERM) + match mode { + SpliceMode::Sendfile => HAS_SENDFILE.store(false, Ordering::Relaxed), + SpliceMode::Splice => HAS_SPLICE.store(false, Ordering::Relaxed), + } + assert_eq!(written, 0); + CopyResult::Fallback(0) + } + Some(libc::EINVAL) => { + // splice/sendfile do not support this particular file descriptor (EINVAL) + assert_eq!(written, 0); + CopyResult::Fallback(0) + } + Some(os_err) if mode == SpliceMode::Sendfile && os_err == libc::EOVERFLOW => { + CopyResult::Fallback(written) + } + _ => CopyResult::Error(err, written), + }; + } + } + } + CopyResult::Ended(written) +} diff --git a/library/std/src/sys/unix/kernel_copy/tests.rs b/library/std/src/sys/unix/kernel_copy/tests.rs new file mode 100644 index 0000000000..77369cdd35 --- /dev/null +++ b/library/std/src/sys/unix/kernel_copy/tests.rs @@ -0,0 +1,252 @@ +use crate::fs::OpenOptions; +use crate::io; +use crate::io::Result; +use crate::io::SeekFrom; +use crate::io::{BufRead, Read, Seek, Write}; +use crate::os::unix::io::AsRawFd; +use crate::sys_common::io::test::tmpdir; + +#[test] +fn copy_specialization() -> Result<()> { + use crate::io::{BufReader, BufWriter}; + + let tmp_path = tmpdir(); + let source_path = tmp_path.join("copy-spec.source"); + let sink_path = tmp_path.join("copy-spec.sink"); + + let result: Result<()> = try { + let mut source = crate::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(&source_path)?; + source.write_all(b"abcdefghiklmnopqr")?; + source.seek(SeekFrom::Start(8))?; + let mut source = BufReader::with_capacity(8, source.take(5)); + source.fill_buf()?; + assert_eq!(source.buffer(), b"iklmn"); + source.get_mut().set_limit(6); + source.get_mut().get_mut().seek(SeekFrom::Start(1))?; // "bcdefg" + let mut source = source.take(10); // "iklmnbcdef" + + let mut sink = crate::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(&sink_path)?; + sink.write_all(b"000000")?; + let mut sink = BufWriter::with_capacity(5, sink); + sink.write_all(b"wxyz")?; + assert_eq!(sink.buffer(), b"wxyz"); + + let copied = crate::io::copy(&mut source, &mut sink)?; + assert_eq!(copied, 10, "copy obeyed limit imposed by Take"); + assert_eq!(sink.buffer().len(), 0, "sink buffer was flushed"); + assert_eq!(source.limit(), 0, "outer Take was exhausted"); + assert_eq!(source.get_ref().buffer().len(), 0, "source buffer should be drained"); + assert_eq!( + source.get_ref().get_ref().limit(), + 1, + "inner Take allowed reading beyond end of file, some bytes should be left" + ); + + let mut sink = sink.into_inner()?; + sink.seek(SeekFrom::Start(0))?; + let mut copied = Vec::new(); + sink.read_to_end(&mut copied)?; + assert_eq!(&copied, b"000000wxyziklmnbcdef"); + }; + + let rm1 = crate::fs::remove_file(source_path); + let rm2 = crate::fs::remove_file(sink_path); + + result.and(rm1).and(rm2) +} + +#[bench] +fn bench_file_to_file_copy(b: &mut test::Bencher) { + const BYTES: usize = 128 * 1024; + let temp_path = tmpdir(); + let src_path = temp_path.join("file-copy-bench-src"); + let mut src = crate::fs::OpenOptions::new() + .create(true) + .truncate(true) + .read(true) + .write(true) + .open(src_path) + .unwrap(); + src.write(&vec![0u8; BYTES]).unwrap(); + + let sink_path = temp_path.join("file-copy-bench-sink"); + let mut sink = crate::fs::OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(sink_path) + .unwrap(); + + b.bytes = BYTES as u64; + b.iter(|| { + src.seek(SeekFrom::Start(0)).unwrap(); + sink.seek(SeekFrom::Start(0)).unwrap(); + assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap()); + }); +} + +#[bench] +fn bench_file_to_socket_copy(b: &mut test::Bencher) { + const BYTES: usize = 128 * 1024; + let temp_path = tmpdir(); + let src_path = temp_path.join("pipe-copy-bench-src"); + let mut src = OpenOptions::new() + .create(true) + .truncate(true) + .read(true) + .write(true) + .open(src_path) + .unwrap(); + src.write(&vec![0u8; BYTES]).unwrap(); + + let sink_drainer = crate::net::TcpListener::bind("localhost:0").unwrap(); + let mut sink = crate::net::TcpStream::connect(sink_drainer.local_addr().unwrap()).unwrap(); + let mut sink_drainer = sink_drainer.accept().unwrap().0; + + crate::thread::spawn(move || { + let mut sink_buf = vec![0u8; 1024 * 1024]; + loop { + sink_drainer.read(&mut sink_buf[..]).unwrap(); + } + }); + + b.bytes = BYTES as u64; + b.iter(|| { + src.seek(SeekFrom::Start(0)).unwrap(); + assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap()); + }); +} + +#[bench] +fn bench_file_to_uds_copy(b: &mut test::Bencher) { + const BYTES: usize = 128 * 1024; + let temp_path = tmpdir(); + let src_path = temp_path.join("uds-copy-bench-src"); + let mut src = OpenOptions::new() + .create(true) + .truncate(true) + .read(true) + .write(true) + .open(src_path) + .unwrap(); + src.write(&vec![0u8; BYTES]).unwrap(); + + let (mut sink, mut sink_drainer) = crate::os::unix::net::UnixStream::pair().unwrap(); + + crate::thread::spawn(move || { + let mut sink_buf = vec![0u8; 1024 * 1024]; + loop { + sink_drainer.read(&mut sink_buf[..]).unwrap(); + } + }); + + b.bytes = BYTES as u64; + b.iter(|| { + src.seek(SeekFrom::Start(0)).unwrap(); + assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap()); + }); +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +#[bench] +fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) { + use super::CopyResult; + use crate::io::ErrorKind; + use crate::process::{ChildStdin, ChildStdout}; + use crate::sys_common::FromInner; + + let (read_end, write_end) = crate::sys::pipe::anon_pipe().unwrap(); + + let mut read_end = ChildStdout::from_inner(read_end); + let write_end = ChildStdin::from_inner(write_end); + + let acceptor = crate::net::TcpListener::bind("localhost:0").unwrap(); + let mut remote_end = crate::net::TcpStream::connect(acceptor.local_addr().unwrap()).unwrap(); + + let local_end = crate::sync::Arc::new(acceptor.accept().unwrap().0); + + // the data flow in this benchmark: + // + // socket(tx) local_source + // remote_end (write) +--------> (splice to) + // write_end + // + + // | + // | pipe + // v + // read_end + // remote_end (read) <---------+ (splice to) * + // socket(rx) local_end + // + // * benchmark loop using io::copy + + crate::thread::spawn(move || { + let mut sink_buf = vec![0u8; 1024 * 1024]; + remote_end.set_nonblocking(true).unwrap(); + loop { + match remote_end.write(&mut sink_buf[..]) { + Err(err) if err.kind() == ErrorKind::WouldBlock => {} + Ok(_) => {} + err => { + err.expect("write failed"); + } + }; + match remote_end.read(&mut sink_buf[..]) { + Err(err) if err.kind() == ErrorKind::WouldBlock => {} + Ok(_) => {} + err => { + err.expect("read failed"); + } + }; + } + }); + + // check that splice works, otherwise the benchmark would hang + let probe = super::sendfile_splice( + super::SpliceMode::Splice, + local_end.as_raw_fd(), + write_end.as_raw_fd(), + 1, + ); + + match probe { + CopyResult::Ended(1) => { + // splice works + } + _ => { + eprintln!("splice failed, skipping benchmark"); + return; + } + } + + let local_source = local_end.clone(); + crate::thread::spawn(move || { + loop { + super::sendfile_splice( + super::SpliceMode::Splice, + local_source.as_raw_fd(), + write_end.as_raw_fd(), + u64::MAX, + ); + } + }); + + const BYTES: usize = 128 * 1024; + b.bytes = BYTES as u64; + b.iter(|| { + assert_eq!( + BYTES as u64, + io::copy(&mut (&mut read_end).take(BYTES as u64), &mut &*local_end).unwrap() + ); + }); +} diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index b28c6d85b7..f8a5ee8996 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -51,6 +51,8 @@ pub mod fd; pub mod fs; pub mod futex; pub mod io; +#[cfg(any(target_os = "linux", target_os = "android"))] +pub mod kernel_copy; #[cfg(target_os = "l4re")] mod l4re; pub mod memchr; @@ -234,3 +236,55 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { pub fn abort_internal() -> ! { unsafe { libc::abort() } } + +cfg_if::cfg_if! { + if #[cfg(target_os = "android")] { + #[link(name = "dl")] + #[link(name = "log")] + #[link(name = "gcc")] + extern "C" {} + } else if #[cfg(target_os = "freebsd")] { + #[link(name = "execinfo")] + #[link(name = "pthread")] + extern "C" {} + } else if #[cfg(target_os = "netbsd")] { + #[link(name = "pthread")] + #[link(name = "rt")] + extern "C" {} + } else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] { + #[link(name = "pthread")] + extern "C" {} + } else if #[cfg(target_os = "solaris")] { + #[link(name = "socket")] + #[link(name = "posix4")] + #[link(name = "pthread")] + #[link(name = "resolv")] + extern "C" {} + } else if #[cfg(target_os = "illumos")] { + #[link(name = "socket")] + #[link(name = "posix4")] + #[link(name = "pthread")] + #[link(name = "resolv")] + #[link(name = "nsl")] + // Use libumem for the (malloc-compatible) allocator + #[link(name = "umem")] + extern "C" {} + } else if #[cfg(target_os = "macos")] { + #[link(name = "System")] + // res_init and friends require -lresolv on macOS/iOS. + // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html + #[link(name = "resolv")] + extern "C" {} + } else if #[cfg(target_os = "ios")] { + #[link(name = "System")] + #[link(name = "objc")] + #[link(name = "Security", kind = "framework")] + #[link(name = "Foundation", kind = "framework")] + #[link(name = "resolv")] + extern "C" {} + } else if #[cfg(target_os = "fuchsia")] { + #[link(name = "zircon")] + #[link(name = "fdio")] + extern "C" {} + } +} diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 378d690f8b..7198a2f08d 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -275,6 +275,20 @@ impl Socket { self.recv_from_with_flags(buf, 0) } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { + let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; + Ok(n as usize) + } + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_with_flags(buf, MSG_PEEK) } @@ -292,6 +306,20 @@ impl Socket { self.0.is_write_vectored() } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { + let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; + Ok(n as usize) + } + pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { @@ -351,6 +379,17 @@ impl Socket { Ok(raw != 0) } + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) + } + + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn passcred(&self) -> io::Result { + let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; + Ok(passcred != 0) + } + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index eed6fbf13b..38ddb41700 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -25,10 +25,19 @@ mod imp { use crate::io::Read; #[cfg(any(target_os = "linux", target_os = "android"))] - fn getrandom(buf: &mut [u8]) -> libc::c_long { - unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK) + fn getrandom(buf: &mut [u8]) -> libc::ssize_t { + // A weak symbol allows interposition, e.g. for perf measurements that want to + // disable randomness for consistency. Otherwise, we'll try a raw syscall. + // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) + syscall! { + fn getrandom( + buffer: *mut libc::c_void, + length: libc::size_t, + flags: libc::c_uint + ) -> libc::ssize_t } + + unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) } } #[cfg(not(any(target_os = "linux", target_os = "android")))] diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index f4b33a00f7..e93a4972ca 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -24,7 +24,7 @@ use crate::ffi::CStr; use crate::marker; use crate::mem; -use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::atomic::{self, AtomicUsize, Ordering}; macro_rules! weak { (fn $name:ident($($t:ty),*) -> $ret:ty) => ( @@ -47,15 +47,49 @@ impl Weak { pub fn get(&self) -> Option { assert_eq!(mem::size_of::(), mem::size_of::()); unsafe { - if self.addr.load(Ordering::SeqCst) == 1 { - self.addr.store(fetch(self.name), Ordering::SeqCst); - } - match self.addr.load(Ordering::SeqCst) { + // Relaxed is fine here because we fence before reading through the + // pointer (see the comment below). + match self.addr.load(Ordering::Relaxed) { + 1 => self.initialize(), 0 => None, - addr => Some(mem::transmute_copy::(&addr)), + addr => { + let func = mem::transmute_copy::(&addr); + // The caller is presumably going to read through this value + // (by calling the function we've dlsymed). This means we'd + // need to have loaded it with at least C11's consume + // ordering in order to be guaranteed that the data we read + // from the pointer isn't from before the pointer was + // stored. Rust has no equivalent to memory_order_consume, + // so we use an acquire fence (sorry, ARM). + // + // Now, in practice this likely isn't needed even on CPUs + // where relaxed and consume mean different things. The + // symbols we're loading are probably present (or not) at + // init, and even if they aren't the runtime dynamic loader + // is extremely likely have sufficient barriers internally + // (possibly implicitly, for example the ones provided by + // invoking `mprotect`). + // + // That said, none of that's *guaranteed*, and so we fence. + atomic::fence(Ordering::Acquire); + Some(func) + } } } } + + // Cold because it should only happen during first-time initalization. + #[cold] + unsafe fn initialize(&self) -> Option { + let val = fetch(self.name); + // This synchronizes with the acquire fence in `get`. + self.addr.store(val, Ordering::Release); + + match val { + 0 => None, + addr => Some(mem::transmute_copy::(&addr)), + } + } } unsafe fn fetch(name: &str) -> usize { @@ -66,7 +100,7 @@ unsafe fn fetch(name: &str) -> usize { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize } -#[cfg(not(target_os = "linux"))] +#[cfg(not(any(target_os = "linux", target_os = "android")))] macro_rules! syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name: $t),*) -> $ret { @@ -84,7 +118,7 @@ macro_rules! syscall { ) } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "android"))] macro_rules! syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name:$t),*) -> $ret { @@ -92,10 +126,18 @@ macro_rules! syscall { // (not paths). use libc::*; - syscall( - concat_idents!(SYS_, $name), - $($arg_name as c_long),* - ) as $ret + weak! { fn $name($($t),*) -> $ret } + + // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` + // interposition, but if it's not found just use a raw syscall. + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + syscall( + concat_idents!(SYS_, $name), + $($arg_name),* + ) as $ret + } } ) } diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index faa53b6a74..4271d9b334 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -279,7 +279,7 @@ pub fn readlink(_p: &Path) -> io::Result { unsupported() } -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 93a92b49cf..120b9f59f1 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -549,19 +549,19 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result { } } -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let (dst, dst_file) = open_parent(dst)?; - dst.symlink(osstr2str(src.as_ref())?, osstr2str(dst_file.as_ref())?) +pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + let (link, link_file) = open_parent(link)?; + link.symlink(osstr2str(original.as_ref())?, osstr2str(link_file.as_ref())?) } -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let (src, src_file) = open_parent(src)?; - let (dst, dst_file) = open_parent(dst)?; - src.link( +pub fn link(original: &Path, link: &Path) -> io::Result<()> { + let (original, original_file) = open_parent(original)?; + let (link, link_file) = open_parent(link)?; + original.link( wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, - osstr2str(src_file.as_ref())?, - &dst, - osstr2str(dst_file.as_ref())?, + osstr2str(original_file.as_ref())?, + &link, + osstr2str(link_file.as_ref())?, ) } diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs index b61a787226..ef0ca3dd47 100644 --- a/library/std/src/sys/wasm/alloc.rs +++ b/library/std/src/sys/wasm/alloc.rs @@ -18,7 +18,7 @@ use crate::alloc::{GlobalAlloc, Layout, System}; -static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT; +static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new(); #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { diff --git a/library/std/src/sys/wasm/mutex_atomics.rs b/library/std/src/sys/wasm/mutex_atomics.rs index 479182ffa4..5ff0ec052b 100644 --- a/library/std/src/sys/wasm/mutex_atomics.rs +++ b/library/std/src/sys/wasm/mutex_atomics.rs @@ -138,7 +138,7 @@ impl ReentrantMutex { self.owner.swap(0, SeqCst); // SAFETY: the caller must gurantee that `self.ptr()` is valid i32. unsafe { - wasm32::atomic_notify(self.ptr() as *mut i32, 1); + wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1); } // wake up one waiter, if any } ref mut n => *n -= 1, diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 657421e3fa..2b1bc92dc8 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -31,6 +31,8 @@ pub type WORD = u16; pub type CHAR = c_char; pub type ULONG_PTR = usize; pub type ULONG = c_ulong; +pub type NTSTATUS = LONG; +pub type ACCESS_MASK = DWORD; pub type LPBOOL = *mut BOOL; pub type LPBYTE = *mut BYTE; @@ -285,6 +287,8 @@ pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008; +pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -1085,3 +1089,46 @@ compat_fn! { panic!("rwlocks not available") } } +compat_fn! { + "api-ms-win-core-synch-l1-2-0": + pub fn WaitOnAddress( + Address: LPVOID, + CompareAddress: LPVOID, + AddressSize: SIZE_T, + dwMilliseconds: DWORD + ) -> BOOL { + panic!("WaitOnAddress not available") + } + pub fn WakeByAddressSingle(Address: LPVOID) -> () { + // If this api is unavailable, there cannot be anything waiting, because + // WaitOnAddress would've panicked. So it's fine to do nothing here. + } +} + +compat_fn! { + "ntdll": + pub fn NtCreateKeyedEvent( + KeyedEventHandle: LPHANDLE, + DesiredAccess: ACCESS_MASK, + ObjectAttributes: LPVOID, + Flags: ULONG + ) -> NTSTATUS { + panic!("keyed events not available") + } + pub fn NtReleaseKeyedEvent( + EventHandle: HANDLE, + Key: LPVOID, + Alertable: BOOLEAN, + Timeout: PLARGE_INTEGER + ) -> NTSTATUS { + panic!("keyed events not available") + } + pub fn NtWaitForKeyedEvent( + EventHandle: HANDLE, + Key: LPVOID, + Alertable: BOOLEAN, + Timeout: PLARGE_INTEGER + ) -> NTSTATUS { + panic!("keyed events not available") + } +} diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index 3f25f05e1b..e9588e2975 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -34,6 +34,7 @@ macro_rules! compat_fn { )*) => ($( $(#[$meta])* pub mod $symbol { + #[allow(unused_imports)] use super::*; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::mem; @@ -90,6 +91,7 @@ macro_rules! compat_fn { } } + $(#[$meta])* pub use $symbol::call as $symbol; )*) } diff --git a/library/std/src/sys/windows/ext/fs.rs b/library/std/src/sys/windows/ext/fs.rs index e0615f2d33..b20eafb4d5 100644 --- a/library/std/src/sys/windows/ext/fs.rs +++ b/library/std/src/sys/windows/ext/fs.rs @@ -519,7 +519,7 @@ impl FileTypeExt for fs::FileType { /// Creates a new file symbolic link on the filesystem. /// -/// The `dst` path will be a file symbolic link pointing to the `src` +/// The `link` path will be a file symbolic link pointing to the `original` /// path. /// /// # Examples @@ -533,13 +533,13 @@ impl FileTypeExt for fs::FileType { /// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink_file, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), false) +pub fn symlink_file, Q: AsRef>(original: P, link: Q) -> io::Result<()> { + sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false) } /// Creates a new directory symlink on the filesystem. /// -/// The `dst` path will be a directory symbolic link pointing to the `src` +/// The `link` path will be a directory symbolic link pointing to the `original` /// path. /// /// # Examples @@ -553,6 +553,6 @@ pub fn symlink_file, Q: AsRef>(src: P, dst: Q) -> io::Resul /// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink_dir, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), true) +pub fn symlink_dir, Q: AsRef>(original: P, link: Q) -> io::Result<()> { + sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true) } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index cdbfac267b..307a47678c 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -759,13 +759,13 @@ pub fn readlink(path: &Path) -> io::Result { file.readlink() } -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - symlink_inner(src, dst, false) +pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + symlink_inner(original, link, false) } -pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { - let src = to_u16s(src)?; - let dst = to_u16s(dst)?; +pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> { + let original = to_u16s(original)?; + let link = to_u16s(link)?; let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the @@ -773,8 +773,8 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { // added to dwFlags to opt into this behaviour. let result = cvt(unsafe { c::CreateSymbolicLinkW( - dst.as_ptr(), - src.as_ptr(), + link.as_ptr(), + original.as_ptr(), flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, ) as c::BOOL }); @@ -782,7 +782,9 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) { // Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, // so if we encounter ERROR_INVALID_PARAMETER, retry without that flag. - cvt(unsafe { c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL })?; + cvt(unsafe { + c::CreateSymbolicLinkW(link.as_ptr(), original.as_ptr(), flags) as c::BOOL + })?; } else { return Err(err); } @@ -791,15 +793,15 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { } #[cfg(not(target_vendor = "uwp"))] -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = to_u16s(src)?; - let dst = to_u16s(dst)?; - cvt(unsafe { c::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) })?; +pub fn link(original: &Path, link: &Path) -> io::Result<()> { + let original = to_u16s(original)?; + let link = to_u16s(link)?; + cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?; Ok(()) } #[cfg(target_vendor = "uwp")] -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { +pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { return Err(io::Error::new(io::ErrorKind::Other, "hard link are not supported on UWP")); } @@ -883,8 +885,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } #[allow(dead_code)] -pub fn symlink_junction, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { - symlink_junction_inner(src.as_ref(), dst.as_ref()) +pub fn symlink_junction, Q: AsRef>( + original: P, + junction: Q, +) -> io::Result<()> { + symlink_junction_inner(original.as_ref(), junction.as_ref()) } // Creating a directory junction on windows involves dealing with reparse @@ -893,7 +898,7 @@ pub fn symlink_junction, Q: AsRef>(src: P, dst: Q) -> io::R // // http://www.flexhex.com/docs/articles/hard-links.phtml #[allow(dead_code)] -fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> { +fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { let d = DirBuilder::new(); d.mkdir(&junction)?; @@ -911,7 +916,7 @@ fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> { // FIXME: this conversion is very hacky let v = br"\??\"; let v = v.iter().map(|x| *x as u16); - for c in v.chain(target.as_os_str().encode_wide()) { + for c in v.chain(original.as_os_str().encode_wide()) { *buf.offset(i) = c; i += 1; } diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 8c19cc78b0..fcbff59dec 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -35,6 +35,7 @@ pub mod rwlock; pub mod thread; pub mod thread_local_dtor; pub mod thread_local_key; +pub mod thread_parker; pub mod time; cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { @@ -270,3 +271,17 @@ pub fn abort_internal() -> ! { } crate::intrinsics::abort(); } + +cfg_if::cfg_if! { + if #[cfg(target_vendor = "uwp")] { + #[link(name = "ws2_32")] + // For BCryptGenRandom + #[link(name = "bcrypt")] + extern "C" {} + } else { + #[link(name = "advapi32")] + #[link(name = "ws2_32")] + #[link(name = "userenv")] + extern "C" {} + } +} diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index fa51b006c3..d4cc56d4cb 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -123,9 +123,9 @@ impl Mutex { let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) }; inner.remutex.init(); let inner = Box::into_raw(inner); - match self.lock.compare_and_swap(0, inner as usize, Ordering::SeqCst) { - 0 => inner, - n => { + match self.lock.compare_exchange(0, inner as usize, Ordering::SeqCst, Ordering::SeqCst) { + Ok(_) => inner, + Err(n) => { Box::from_raw(inner).remutex.destroy(); n as *const _ } diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index dda3ed68cf..c10c0df4a3 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -8,15 +8,12 @@ mod tests; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; -// The unsafety here stems from converting between `&OsStr` and `&[u8]` -// and back. This is safe to do because (1) we only look at ASCII -// contents of the encoding and (2) new &OsStr values are produced -// only from ASCII-bounded slices of existing &OsStr values. -fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { - unsafe { mem::transmute(s) } -} -unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - mem::transmute(s) +// Safety: `bytes` must be a valid wtf8 encoded slice +#[inline] +unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr { + // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8, + // which is compatible with &[u8]. + mem::transmute(bytes) } #[inline] @@ -29,79 +26,116 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'\\' } -// In most DOS systems, it is not possible to have more than 26 drive letters. -// See . -pub fn is_valid_drive_letter(disk: u8) -> bool { - disk.is_ascii_alphabetic() -} - pub fn parse_prefix(path: &OsStr) -> Option> { use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC}; - let path = os_str_as_u8_slice(path); - - // \\ - if let Some(path) = path.strip_prefix(br"\\") { - // \\?\ - if let Some(path) = path.strip_prefix(br"?\") { - // \\?\UNC\server\share - if let Some(path) = path.strip_prefix(br"UNC\") { - let (server, share) = match get_first_two_components(path, is_verbatim_sep) { - Some((server, share)) => unsafe { - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)) - }, - None => (unsafe { u8_slice_as_os_str(path) }, OsStr::new("")), - }; - return Some(VerbatimUNC(server, share)); + if let Some(path) = strip_prefix(path, r"\\") { + // \\ + if let Some(path) = strip_prefix(path, r"?\") { + // \\?\ + if let Some(path) = strip_prefix(path, r"UNC\") { + // \\?\UNC\server\share + + let (server, path) = parse_next_component(path, true); + let (share, _) = parse_next_component(path, true); + + Some(VerbatimUNC(server, share)) } else { - // \\?\path - match path { - // \\?\C:\path - [c, b':', b'\\', ..] if is_valid_drive_letter(*c) => { - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } - // \\?\cat_pics - _ => { - let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); - let slice = &path[..idx]; - return Some(Verbatim(unsafe { u8_slice_as_os_str(slice) })); - } + let (prefix, _) = parse_next_component(path, true); + + // in verbatim paths only recognize an exact drive prefix + if let Some(drive) = parse_drive_exact(prefix) { + // \\?\C: + Some(VerbatimDisk(drive)) + } else { + // \\?\prefix + Some(Verbatim(prefix)) } } - } else if let Some(path) = path.strip_prefix(b".\\") { + } else if let Some(path) = strip_prefix(path, r".\") { // \\.\COM42 - let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len()); - let slice = &path[..idx]; - return Some(DeviceNS(unsafe { u8_slice_as_os_str(slice) })); - } - match get_first_two_components(path, is_sep_byte) { - Some((server, share)) if !server.is_empty() && !share.is_empty() => { + let (prefix, _) = parse_next_component(path, false); + Some(DeviceNS(prefix)) + } else { + let (server, path) = parse_next_component(path, false); + let (share, _) = parse_next_component(path, false); + + if !server.is_empty() && !share.is_empty() { // \\server\share - return Some(unsafe { UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)) }); + Some(UNC(server, share)) + } else { + // no valid prefix beginning with "\\" recognized + None } - _ => {} } - } else if let [c, b':', ..] = path { + } else if let Some(drive) = parse_drive(path) { // C: - if is_valid_drive_letter(*c) { - return Some(Disk(c.to_ascii_uppercase())); - } + Some(Disk(drive)) + } else { + // no prefix + None } - None } -/// Returns the first two path components with predicate `f`. -/// -/// The two components returned will be use by caller -/// to construct `VerbatimUNC` or `UNC` Windows path prefix. -/// -/// Returns [`None`] if there are no separators in path. -fn get_first_two_components(path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let idx = path.iter().position(|&x| f(x))?; - // Panic safe - // The max `idx+1` is `path.len()` and `path[path.len()..]` is a valid index. - let (first, path) = (&path[..idx], &path[idx + 1..]); - let idx = path.iter().position(|&x| f(x)).unwrap_or(path.len()); - let second = &path[..idx]; - Some((first, second)) +// Parses a drive prefix, e.g. "C:" and "C:\whatever" +fn parse_drive(prefix: &OsStr) -> Option { + // In most DOS systems, it is not possible to have more than 26 drive letters. + // See . + fn is_valid_drive_letter(drive: &u8) -> bool { + drive.is_ascii_alphabetic() + } + + match prefix.bytes() { + [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), + _ => None, + } +} + +// Parses a drive prefix exactly, e.g. "C:" +fn parse_drive_exact(prefix: &OsStr) -> Option { + // only parse two bytes: the drive letter and the drive separator + if prefix.len() == 2 { parse_drive(prefix) } else { None } +} + +fn strip_prefix<'a>(path: &'a OsStr, prefix: &str) -> Option<&'a OsStr> { + // `path` and `prefix` are valid wtf8 and utf8 encoded slices respectively, `path[prefix.len()]` + // is thus a code point boundary and `path[prefix.len()..]` is a valid wtf8 encoded slice. + match path.bytes().strip_prefix(prefix.as_bytes()) { + Some(path) => unsafe { Some(bytes_as_os_str(path)) }, + None => None, + } +} + +// Parse the next path component. +// +// Returns the next component and the rest of the path excluding the component and separator. +// Does not recognize `/` as a separator character if `verbatim` is true. +fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { + let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; + + match path.bytes().iter().position(|&x| separator(x)) { + Some(separator_start) => { + let mut separator_end = separator_start + 1; + + // a series of multiple separator characters is treated as a single separator, + // except in verbatim paths + while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end]) + { + separator_end += 1; + } + + let component = &path.bytes()[..separator_start]; + + // Panic safe + // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. + let path = &path.bytes()[separator_end..]; + + // Safety: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') + // is encoded in a single byte, therefore `bytes[separator_start]` and + // `bytes[separator_end]` must be code point boundaries and thus + // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. + unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) } + } + None => (path, OsStr::new("")), + } } diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs index fbac1dc1ca..9675da6ff8 100644 --- a/library/std/src/sys/windows/path/tests.rs +++ b/library/std/src/sys/windows/path/tests.rs @@ -1,21 +1,44 @@ use super::*; #[test] -fn test_get_first_two_components() { +fn test_parse_next_component() { assert_eq!( - get_first_two_components(br"server\share", is_verbatim_sep), - Some((&b"server"[..], &b"share"[..])), + parse_next_component(OsStr::new(r"server\share"), true), + (OsStr::new(r"server"), OsStr::new(r"share")) ); assert_eq!( - get_first_two_components(br"server\", is_verbatim_sep), - Some((&b"server"[..], &b""[..])) + parse_next_component(OsStr::new(r"server/share"), true), + (OsStr::new(r"server/share"), OsStr::new(r"")) ); assert_eq!( - get_first_two_components(br"\server\", is_verbatim_sep), - Some((&b""[..], &b"server"[..])) + parse_next_component(OsStr::new(r"server/share"), false), + (OsStr::new(r"server"), OsStr::new(r"share")) ); - assert_eq!(get_first_two_components(br"there are no separators here", is_verbatim_sep), None,); + assert_eq!( + parse_next_component(OsStr::new(r"server\"), false), + (OsStr::new(r"server"), OsStr::new(r"")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"\server\"), false), + (OsStr::new(r""), OsStr::new(r"server\")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"servershare"), false), + (OsStr::new(r"servershare"), OsStr::new("")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"server/\//\/\\\\/////\/share"), false), + (OsStr::new(r"server"), OsStr::new(r"share")) + ); + + assert_eq!( + parse_next_component(OsStr::new(r"server\\\\\\\\\\\\\\share"), true), + (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share")) + ); } diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs index 82901871e7..065365e557 100644 --- a/library/std/src/sys/windows/thread_local_key.rs +++ b/library/std/src/sys/windows/thread_local_key.rs @@ -1,4 +1,4 @@ -use crate::mem; +use crate::mem::ManuallyDrop; use crate::ptr; use crate::sync::atomic::AtomicPtr; use crate::sync::atomic::Ordering::SeqCst; @@ -110,30 +110,14 @@ struct Node { next: *mut Node, } -#[cfg(miri)] -extern "Rust" { - /// Miri-provided extern function to mark the block `ptr` points to as a "root" - /// for some static memory. This memory and everything reachable by it is not - /// considered leaking even if it still exists when the program terminates. - /// - /// `ptr` has to point to the beginning of an allocated block. - fn miri_static_root(ptr: *const u8); -} - unsafe fn register_dtor(key: Key, dtor: Dtor) { - let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() }); + let mut node = ManuallyDrop::new(Box::new(Node { key, dtor, next: ptr::null_mut() })); let mut head = DTORS.load(SeqCst); loop { node.next = head; - match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) { - Ok(_) => { - #[cfg(miri)] - miri_static_root(&*node as *const _ as *const u8); - - mem::forget(node); - return; - } + match DTORS.compare_exchange(head, &mut **node, SeqCst, SeqCst) { + Ok(_) => return, // nothing to drop, we successfully added the node to the list Err(cur) => head = cur, } } diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs new file mode 100644 index 0000000000..9e4c9aa0a5 --- /dev/null +++ b/library/std/src/sys/windows/thread_parker.rs @@ -0,0 +1,250 @@ +// Thread parker implementation for Windows. +// +// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+). +// This modern API is exactly the same as the futex syscalls the Linux thread +// parker uses. When These APIs are available, the implementation of this +// thread parker matches the Linux thread parker exactly. +// +// However, when the modern API is not available, this implementation falls +// back to NT Keyed Events, which are similar, but have some important +// differences. These are available since Windows XP. +// +// WaitOnAddress first checks the state of the thread parker to make sure it no +// WakeByAddressSingle calls can be missed between updating the parker state +// and calling the function. +// +// NtWaitForKeyedEvent does not have this option, and unconditionally blocks +// without checking the parker state first. Instead, NtReleaseKeyedEvent +// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for +// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed, +// but we need to be careful not to block unpark() if park_timeout() was woken +// up by a timeout instead of unpark(). +// +// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a +// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure +// a succesfully awoken park() was awoken by unpark() and not a +// NtReleaseKeyedEvent call from some other code, as these events are not only +// matched by the key (address of the parker (state)), but also by this HANDLE. +// We lazily allocate this handle the first time it is needed. +// +// The fast path (calling park() after unpark() was already called) and the +// possible states are the same for both implementations. This is used here to +// make sure the fast path does not even check which API to use, but can return +// right away, independent of the used API. Only the slow paths (which will +// actually block/wake a thread) check which API is available and have +// different implementations. +// +// Unfortunately, NT Keyed Events are an undocumented Windows API. However: +// - This API is relatively simple with obvious behaviour, and there are +// several (unofficial) articles documenting the details. [1] +// - `parking_lot` has been using this API for years (on Windows versions +// before Windows 8). [2] Many big projects extensively use parking_lot, +// such as servo and the Rust compiler itself. +// - It is the underlying API used by Windows SRW locks and Windows critical +// sections. [3] [4] +// - The source code of the implementations of Wine, ReactOs, and Windows XP +// are available and match the expected behaviour. +// - The main risk with an undocumented API is that it might change in the +// future. But since we only use it for older versions of Windows, that's not +// a problem. +// - Even if these functions do not block or wake as we expect (which is +// unlikely, see all previous points), this implementation would still be +// memory safe. The NT Keyed Events API is only used to sleep/block in the +// right place. +// +// [1]: http://www.locklessinc.com/articles/keyed_events/ +// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e +// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c +// [4]: Windows Internals, Part 1, ISBN 9780735671300 + +use crate::convert::TryFrom; +use crate::ptr; +use crate::sync::atomic::{ + AtomicI8, AtomicUsize, + Ordering::{Acquire, Relaxed, Release}, +}; +use crate::sys::{c, dur2timeout}; +use crate::time::Duration; + +pub struct Parker { + state: AtomicI8, +} + +const PARKED: i8 = -1; +const EMPTY: i8 = 0; +const NOTIFIED: i8 = 1; + +// Notes about memory ordering: +// +// Memory ordering is only relevant for the relative ordering of operations +// between different variables. Even Ordering::Relaxed guarantees a +// monotonic/consistent order when looking at just a single atomic variable. +// +// So, since this parker is just a single atomic variable, we only need to look +// at the ordering guarantees we need to provide to the 'outside world'. +// +// The only memory ordering guarantee that parking and unparking provide, is +// that things which happened before unpark() are visible on the thread +// returning from park() afterwards. Otherwise, it was effectively unparked +// before unpark() was called while still consuming the 'token'. +// +// In other words, unpark() needs to synchronize with the part of park() that +// consumes the token and returns. +// +// This is done with a release-acquire synchronization, by using +// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using +// Ordering::Acquire when reading this state in park() after waking up. +impl Parker { + pub fn new() -> Self { + Self { state: AtomicI8::new(EMPTY) } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park(&self) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + if c::WaitOnAddress::is_available() { + loop { + // Wait for something to happen, assuming it's still set to PARKED. + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE); + // Change NOTIFIED=>EMPTY but leave PARKED alone. + if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { + // Actually woken up by unpark(). + return; + } else { + // Spurious wake up. We loop to try again. + } + } + } else { + // Wait for unpark() to produce this event. + c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + // Note that we don't just write EMPTY, but use swap() to also + // include an acquire-ordered read to synchronize with unpark()'s + // release-ordered write. + self.state.swap(EMPTY, Acquire); + } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park_timeout(&self, timeout: Duration) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + if c::WaitOnAddress::is_available() { + // Wait for something to happen, assuming it's still set to PARKED. + c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout)); + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + // Note that we don't just write EMPTY, but use swap() to also + // include an acquire-ordered read to synchronize with unpark()'s + // release-ordered write. + if self.state.swap(EMPTY, Acquire) == NOTIFIED { + // Actually woken up by unpark(). + } else { + // Timeout or spurious wake up. + // We return either way, because we can't easily tell if it was the + // timeout or not. + } + } else { + // Need to wait for unpark() using NtWaitForKeyedEvent. + let handle = keyed_event_handle(); + + // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative + // values to indicate a relative time on the monotonic clock. + // This is documented here for the underlying KeWaitForSingleObject function: + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject + let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) { + Ok(t) => -t, + Err(_) => i64::MIN, + }; + + // Wait for unpark() to produce this event. + let unparked = + c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS; + + // Set the state back to EMPTY (from either PARKED or NOTIFIED). + let prev_state = self.state.swap(EMPTY, Acquire); + + if !unparked && prev_state == NOTIFIED { + // We were awoken by a timeout, not by unpark(), but the state + // was set to NOTIFIED, which means we *just* missed an + // unpark(), which is now blocked on us to wait for it. + // Wait for it to consume the event and unblock that thread. + c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut()); + } + } + } + + pub fn unpark(&self) { + // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and + // wake the thread in the first case. + // + // Note that even NOTIFIED=>NOTIFIED results in a write. This is on + // purpose, to make sure every unpark() has a release-acquire ordering + // with park(). + if self.state.swap(NOTIFIED, Release) == PARKED { + if c::WakeByAddressSingle::is_available() { + unsafe { + c::WakeByAddressSingle(self.ptr()); + } + } else { + // If we run NtReleaseKeyedEvent before the waiting thread runs + // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. + // If the waiting thread wakes up before we run NtReleaseKeyedEvent + // (e.g. due to a timeout), this blocks until we do wake up a thread. + // To prevent this thread from blocking indefinitely in that case, + // park_impl() will, after seeing the state set to NOTIFIED after + // waking up, call NtWaitForKeyedEvent again to unblock us. + unsafe { + c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); + } + } + } + } + + fn ptr(&self) -> c::LPVOID { + &self.state as *const _ as c::LPVOID + } +} + +fn keyed_event_handle() -> c::HANDLE { + const INVALID: usize = !0; + static HANDLE: AtomicUsize = AtomicUsize::new(INVALID); + match HANDLE.load(Relaxed) { + INVALID => { + let mut handle = c::INVALID_HANDLE_VALUE; + unsafe { + match c::NtCreateKeyedEvent( + &mut handle, + c::GENERIC_READ | c::GENERIC_WRITE, + ptr::null_mut(), + 0, + ) { + c::STATUS_SUCCESS => {} + r => panic!("Unable to create keyed event handle: error {}", r), + } + } + match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) { + Ok(_) => handle, + Err(h) => { + // Lost the race to another thread initializing HANDLE before we did. + // Closing our handle and using theirs instead. + unsafe { + c::CloseHandle(handle); + } + h as c::HANDLE + } + } + } + handle => handle as c::HANDLE, + } +} diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs index fecb732b91..1578a2de60 100644 --- a/library/std/src/sys_common/condvar/check.rs +++ b/library/std/src/sys_common/condvar/check.rs @@ -23,9 +23,9 @@ impl SameMutexCheck { } pub fn verify(&self, mutex: &MovableMutex) { let addr = mutex.raw() as *const mutex_imp::Mutex as usize; - match self.addr.compare_and_swap(0, addr, Ordering::SeqCst) { - 0 => {} // Stored the address - n if n == addr => {} // Lost a race to store the same address + match self.addr.compare_exchange(0, addr, Ordering::SeqCst, Ordering::SeqCst) { + Ok(_) => {} // Stored the address + Err(n) if n == addr => {} // Lost a race to store the same address _ => panic!("attempted to use a condition variable with two mutexes"), } } diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 234b257aa9..660f0e0df9 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -71,8 +71,7 @@ pub mod util; pub mod wtf8; cfg_if::cfg_if! { - if #[cfg(any(target_os = "cloudabi", - target_os = "l4re", + if #[cfg(any(target_os = "l4re", target_os = "hermit", feature = "restricted-std", all(target_arch = "wasm32", not(target_os = "emscripten")), diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 48ba4ddfc0..38ba0d2fbd 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -177,11 +177,8 @@ impl TryFrom<&str> for LookupHost { } // split the string by ':' and convert the second part to u16 - let mut parts_iter = s.rsplitn(2, ':'); - let port_str = try_opt!(parts_iter.next(), "invalid socket address"); - let host = try_opt!(parts_iter.next(), "invalid socket address"); + let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - (host, port).try_into() } } diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index dbcb7b3626..32cd564166 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -168,7 +168,7 @@ impl StaticKey { return key; } - // POSIX allows the key created here to be 0, but the compare_and_swap + // POSIX allows the key created here to be 0, but the compare_exchange // below relies on using 0 as a sentinel value to check who won the // race to set the shared TLS key. As far as I know, there is no // guaranteed value that cannot be returned as a posix_key_create key, @@ -186,11 +186,11 @@ impl StaticKey { key2 }; rtassert!(key != 0); - match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) { + match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) { // The CAS succeeded, so we've created the actual key - 0 => key as usize, + Ok(_) => key as usize, // If someone beat us to the punch, use their key instead - n => { + Err(n) => { imp::destroy(key); n } diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs index a5d4927dcc..0132743b24 100644 --- a/library/std/src/sys_common/thread_parker/futex.rs +++ b/library/std/src/sys_common/thread_parker/futex.rs @@ -49,7 +49,7 @@ impl Parker { // Wait for something to happen, assuming it's still set to PARKED. futex_wait(&self.state, PARKED, None); // Change NOTIFIED=>EMPTY and return in that case. - if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { + if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() { return; } else { // Spurious wake up. We loop to try again. diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 5e75ac65de..ba896bd676 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -6,6 +6,8 @@ cfg_if::cfg_if! { ))] { mod futex; pub use futex::Parker; + } else if #[cfg(windows)] { + pub use crate::sys::thread_parker::Parker; } else { mod generic; pub use generic::Parker; diff --git a/library/std/src/thread/available_concurrency.rs b/library/std/src/thread/available_concurrency.rs index 4e805e4f59..64a5f89890 100644 --- a/library/std/src/thread/available_concurrency.rs +++ b/library/std/src/thread/available_concurrency.rs @@ -70,7 +70,6 @@ cfg_if::cfg_if! { } } else if #[cfg(any( target_os = "android", - target_os = "cloudabi", target_os = "emscripten", target_os = "fuchsia", target_os = "ios", diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index fefaa77a2a..5d65f960fc 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -456,15 +456,15 @@ impl Builder { let my_packet: Arc>>> = Arc::new(UnsafeCell::new(None)); let their_packet = my_packet.clone(); - let (stdout, stderr) = crate::io::clone_io(); + let output_capture = crate::io::set_output_capture(None); + crate::io::set_output_capture(output_capture.clone()); let main = move || { if let Some(name) = their_thread.cname() { imp::Thread::set_name(name); } - crate::io::set_print(stdout); - crate::io::set_panic(stderr); + crate::io::set_output_capture(output_capture); // SAFETY: the stack guard passed is the one for the current thread. // This means the current thread's stack and the new thread's stack diff --git a/library/std/src/time.rs b/library/std/src/time.rs index e433f69a8b..89addae078 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -83,7 +83,6 @@ pub use core::time::Duration; /// /// | Platform | System call | /// |:---------:|:--------------------------------------------------------------------:| -/// | CloudABI | [clock_time_get (Monotonic Clock)] | /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | UNIX | [clock_gettime (Monotonic Clock)] | /// | Darwin | [mach_absolute_time] | @@ -97,7 +96,6 @@ pub use core::time::Duration; /// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#clock_time_get /// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime /// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html -/// [clock_time_get (Monotonic Clock)]: https://nuxi.nl/cloudabi/#clock_time_get /// /// **Disclaimer:** These system calls might change over time. /// @@ -161,7 +159,6 @@ pub struct Instant(time::Instant); /// /// | Platform | System call | /// |:---------:|:--------------------------------------------------------------------:| -/// | CloudABI | [clock_time_get (Realtime Clock)] | /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | UNIX | [clock_gettime (Realtime Clock)] | /// | Darwin | [gettimeofday] | @@ -169,7 +166,6 @@ pub struct Instant(time::Instant); /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | /// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | /// -/// [clock_time_get (Realtime Clock)]: https://nuxi.nl/cloudabi/#clock_time_get /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode /// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index c94fc41178..b095c2dde6 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -76,3 +76,65 @@ fn test_env_set_var() { assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); } + +#[test] +#[cfg_attr(not(any(unix, windows)), ignore, allow(unused))] +#[allow(deprecated)] +fn env_home_dir() { + use std::path::PathBuf; + + fn var_to_os_string(var: Result) -> Option { + match var { + Ok(var) => Some(OsString::from(var)), + Err(VarError::NotUnicode(var)) => Some(var), + _ => None, + } + } + + cfg_if::cfg_if! { + if #[cfg(unix)] { + let oldhome = var_to_os_string(var("HOME")); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + if cfg!(target_os = "android") { + assert!(home_dir().is_none()); + } else { + // When HOME is not set, some platforms return `None`, + // but others return `Some` with a default. + // Just check that it is not "/home/MountainView". + assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + } + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + } else if #[cfg(windows)] { + let oldhome = var_to_os_string(var("HOME")); + let olduserprofile = var_to_os_string(var("USERPROFILE")); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + assert!(home_dir().is_some()); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + + set_var("USERPROFILE", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + set_var("HOME", "/home/MountainView"); + set_var("USERPROFILE", "/home/PaloAlto"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); } + } + } +} diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index 8dd1a8ac0d..61a04c4672 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -54,42 +54,62 @@ fn powerpc64_linux() { #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn x86_all() { + // the below is the set of features we can test at runtime, but don't actually + // use to gate anything and are thus not part of the X86_ALLOWED_FEATURES list + + println!("abm: {:?}", is_x86_feature_detected!("abm")); // this is a synonym for lzcnt but we test it anyways + println!("mmx: {:?}", is_x86_feature_detected!("mmx")); + println!("tsc: {:?}", is_x86_feature_detected!("tsc")); + + // the below is in alphabetical order and matches + // the order of X86_ALLOWED_FEATURES in rustc_codegen_ssa's target_features.rs + + println!("adx: {:?}", is_x86_feature_detected!("adx")); println!("aes: {:?}", is_x86_feature_detected!("aes")); - println!("pcmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq")); + println!("avx: {:?}", is_x86_feature_detected!("avx")); + println!("avx2: {:?}", is_x86_feature_detected!("avx2")); + println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16")); + println!("avx512bitalg: {:?}", is_x86_feature_detected!("avx512bitalg")); + println!("avx512bw: {:?}", is_x86_feature_detected!("avx512bw")); + println!("avx512cd: {:?}", is_x86_feature_detected!("avx512cd")); + println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq")); + println!("avx512er: {:?}", is_x86_feature_detected!("avx512er")); + println!("avx512f: {:?}", is_x86_feature_detected!("avx512f")); + println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni")); + println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma")); + println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf")); + println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes")); + println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi")); + println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2")); + println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl")); + println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni")); + println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect")); + println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq")); + println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq")); + println!("bmi1: {:?}", is_x86_feature_detected!("bmi1")); + println!("bmi2: {:?}", is_x86_feature_detected!("bmi2")); + println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b")); + println!("f16c: {:?}", is_x86_feature_detected!("f16c")); + println!("fma: {:?}", is_x86_feature_detected!("fma")); + println!("fxsr: {:?}", is_x86_feature_detected!("fxsr")); + println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt")); + //println!("movbe: {:?}", is_x86_feature_detected!("movbe")); // movbe is unsupported as a target feature + println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq")); + println!("popcnt: {:?}", is_x86_feature_detected!("popcnt")); println!("rdrand: {:?}", is_x86_feature_detected!("rdrand")); println!("rdseed: {:?}", is_x86_feature_detected!("rdseed")); - println!("tsc: {:?}", is_x86_feature_detected!("tsc")); - println!("mmx: {:?}", is_x86_feature_detected!("mmx")); + println!("rtm: {:?}", is_x86_feature_detected!("rtm")); + println!("sha: {:?}", is_x86_feature_detected!("sha")); println!("sse: {:?}", is_x86_feature_detected!("sse")); println!("sse2: {:?}", is_x86_feature_detected!("sse2")); println!("sse3: {:?}", is_x86_feature_detected!("sse3")); - println!("ssse3: {:?}", is_x86_feature_detected!("ssse3")); println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1")); println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2")); println!("sse4a: {:?}", is_x86_feature_detected!("sse4a")); - println!("sha: {:?}", is_x86_feature_detected!("sha")); - println!("avx: {:?}", is_x86_feature_detected!("avx")); - println!("avx2: {:?}", is_x86_feature_detected!("avx2")); - println!("avx512f {:?}", is_x86_feature_detected!("avx512f")); - println!("avx512cd {:?}", is_x86_feature_detected!("avx512cd")); - println!("avx512er {:?}", is_x86_feature_detected!("avx512er")); - println!("avx512pf {:?}", is_x86_feature_detected!("avx512pf")); - println!("avx512bw {:?}", is_x86_feature_detected!("avx512bw")); - println!("avx512dq {:?}", is_x86_feature_detected!("avx512dq")); - println!("avx512vl {:?}", is_x86_feature_detected!("avx512vl")); - println!("avx512_ifma {:?}", is_x86_feature_detected!("avx512ifma")); - println!("avx512_vbmi {:?}", is_x86_feature_detected!("avx512vbmi")); - println!("avx512_vpopcntdq {:?}", is_x86_feature_detected!("avx512vpopcntdq")); - println!("fma: {:?}", is_x86_feature_detected!("fma")); - println!("bmi1: {:?}", is_x86_feature_detected!("bmi1")); - println!("bmi2: {:?}", is_x86_feature_detected!("bmi2")); - println!("abm: {:?}", is_x86_feature_detected!("abm")); - println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt")); + println!("ssse3: {:?}", is_x86_feature_detected!("ssse3")); println!("tbm: {:?}", is_x86_feature_detected!("tbm")); - println!("popcnt: {:?}", is_x86_feature_detected!("popcnt")); - println!("fxsr: {:?}", is_x86_feature_detected!("fxsr")); println!("xsave: {:?}", is_x86_feature_detected!("xsave")); + println!("xsavec: {:?}", is_x86_feature_detected!("xsavec")); println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt")); println!("xsaves: {:?}", is_x86_feature_detected!("xsaves")); - println!("xsavec: {:?}", is_x86_feature_detected!("xsavec")); } diff --git a/src/test/ui/sleep.rs b/library/std/tests/thread.rs similarity index 58% rename from src/test/ui/sleep.rs rename to library/std/tests/thread.rs index 3b3a4a4f32..754b264c6a 100644 --- a/src/test/ui/sleep.rs +++ b/library/std/tests/thread.rs @@ -1,18 +1,16 @@ -// run-pass -// ignore-emscripten no threads support - -use std::thread::{self, sleep}; -use std::time::Duration; use std::sync::{Arc, Mutex}; -use std::u64; +use std::thread; +use std::time::Duration; -fn main() { +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn sleep() { let finished = Arc::new(Mutex::new(false)); let t_finished = finished.clone(); thread::spawn(move || { - sleep(Duration::new(u64::MAX, 0)); + thread::sleep(Duration::new(u64::MAX, 0)); *t_finished.lock().unwrap() = true; }); - sleep(Duration::from_millis(100)); + thread::sleep(Duration::from_millis(100)); assert_eq!(*finished.lock().unwrap(), false); } diff --git a/library/stdarch/.github/workflows/main.yml b/library/stdarch/.github/workflows/main.yml index cadfc38300..fdae25c903 100644 --- a/library/stdarch/.github/workflows/main.yml +++ b/library/stdarch/.github/workflows/main.yml @@ -96,10 +96,11 @@ jobs: # Windows targets - x86_64-pc-windows-msvc + - i686-pc-windows-msvc # FIXME: Disassembly not implemented for the # following targets: # - x86_64-pc-windows-gnu: # - i686-pc-windows-gnu: - # - i686-pc-windows-msvc: + # - aarch64-pc-windows-msvc: include: - target: i686-unknown-linux-gnu @@ -137,6 +138,8 @@ jobs: os: macos-latest - target: x86_64-pc-windows-msvc os: windows-latest + - target: i686-pc-windows-msvc + os: windows-latest - target: i586-unknown-linux-gnu os: ubuntu-latest - target: x86_64-linux-android @@ -172,7 +175,7 @@ jobs: - name: Install Rust (macos) run: | curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly - echo "##[add-path]$HOME/.cargo/bin" + echo "$HOME/.cargo/bin" >> $GITHUB_PATH rustup update nightly --no-self-update rustup default nightly if: matrix.os == 'macos-latest' @@ -183,15 +186,15 @@ jobs: - run: cargo generate-lockfile # Configure some env vars based on matrix configuration - - run: echo "##[set-env name=NORUN]1" + - run: echo "NORUN=1" >> $GITHUB_ENV if: matrix.norun != '' || startsWith(matrix.target, 'thumb') || matrix.target == 'nvptx64-nvidia-cuda' - - run: echo "##[set-env name=STDARCH_TEST_EVERYTHING]1" + - run: echo "STDARCH_TEST_EVERYTHING=1" >> $GITHUB_ENV if: matrix.test_everything != '' - - run: echo "##[set-env name=RUSTFLAGS]${{ matrix.rustflags }}" + - run: echo "RUSTFLAGS=${{ matrix.rustflags }}" >> $GITHUB_ENV if: matrix.rustflags != '' - - run: echo "##[set-env name=STDARCH_DISABLE_ASSERT_INSTR]1" + - run: echo "STDARCH_DISABLE_ASSERT_INSTR=1" >> $GITHUB_ENV if: matrix.disable_assert_instr != '' - - run: echo "##[set-env name=NOSTD]1" + - run: echo "NOSTD=1" >> $GITHUB_ENV if: startsWith(matrix.target, 'thumb') || matrix.target == 'nvptx64-nvidia-cuda' # Windows & OSX go straight to `run.sh` ... diff --git a/library/stdarch/CONTRIBUTING.md b/library/stdarch/CONTRIBUTING.md index 85b7bb474f..ebccd73eac 100644 --- a/library/stdarch/CONTRIBUTING.md +++ b/library/stdarch/CONTRIBUTING.md @@ -6,17 +6,14 @@ probably want to check out the repository and make sure that tests pass for you: ``` $ git clone https://github.com/rust-lang/stdarch $ cd stdarch -$ cargo +nightly test +$ TARGET="" ci/run.sh ``` -To run codegen tests, run in release mode: +Where `` is the target triple as used by `rustup`, e.g. `x86_x64-unknown-linux-gnu` (without any preceding `nightly-` or similar). +Also remember that this repository requires the nightly channel of Rust! +The above tests do in fact require nightly rust to be the default on your system, to set that use `rustup default nightly` (and `rustup default stable` to revert). -``` -$ cargo +nightly test --release -p coresimd -``` - -Remember that this repository requires the nightly channel of Rust! If any of -the above steps don't work, [please let us know][new]! +If any of the above steps don't work, [please let us know][new]! Next up you can [find an issue][issues] to help out on, we've selected a few with the [`help wanted`][help] and [`impl-period`][impl] tags which could @@ -71,6 +68,21 @@ of the [Rust Book] describes the `rustdoc` syntax quite well. As always, feel fr to [join us on gitter][gitter] and ask us if you hit any snags, and thank you for helping to improve the documentation of `stdarch`! +# Alternative Testing Instructions + +It is generally recommended that you use `ci/run.sh` to run the tests. +However this might not work for you, e.g. if you are on Windows. + +In that case you can fall back to running `cargo +nightly test` and `cargo +nightly test --release -p core_arch` for testing the code generation. +Note that these require the nightly toolchain to be installed and for `rustc` to know about your target triple and its CPU. +In particular you need to set the `TARGET` environment variable as you would for `ci/run.sh`. +In addition you need to set `RUSTCFLAGS` (need the `C`) to indicate target features, e.g. `RUSTCFLAGS="-C -target-features=+avx2"`. +You can also set `-C -target-cpu=native` if you're "just" developing against your current CPU. + +Be warned that when you use these alternative instructions, [things may go less smoothly than they would with `ci/run.sh`][ci-run-good], e.g. instruction generation tests may fail because the disassembler named them differently, e.g. it may generate `vaesenc` instead of `aesenc` instructions despite them behaving the same. +Also these instructions execute less tests than would normally be done, so don't be surprised that when you eventually pull-request some errors may show up for tests not covered here. + + [new]: https://github.com/rust-lang/stdarch/issues/new [issues]: https://github.com/rust-lang/stdarch/issues [help]: https://github.com/rust-lang/stdarch/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22 @@ -78,3 +90,4 @@ to improve the documentation of `stdarch`! [vendor]: https://github.com/rust-lang/stdarch/issues/40 [Documentation as tests]: https://doc.rust-lang.org/book/first-edition/documentation.html#documentation-as-tests [Rust Book]: https://doc.rust-lang.org/book/first-edition +[ci-run-good]: https://github.com/rust-lang/stdarch/issues/931#issuecomment-711412126 diff --git a/library/stdarch/ci/run.sh b/library/stdarch/ci/run.sh index 2b7e51be3d..4f4eaa1cfc 100755 --- a/library/stdarch/ci/run.sh +++ b/library/stdarch/ci/run.sh @@ -13,6 +13,8 @@ set -ex RUSTFLAGS="$RUSTFLAGS -D warnings " case ${TARGET} in + *-pc-windows-msvc) + ;; # On 32-bit use a static relocation model which avoids some extra # instructions when dealing with static data, notably allowing some # instruction assertion checks to pass below the 20 instruction limit. If diff --git a/library/stdarch/crates/assert-instr-macro/build.rs b/library/stdarch/crates/assert-instr-macro/build.rs index 45a868441c..01ae79660e 100644 --- a/library/stdarch/crates/assert-instr-macro/build.rs +++ b/library/stdarch/crates/assert-instr-macro/build.rs @@ -6,7 +6,7 @@ fn main() { .ok() .and_then(|s| s.parse().ok()) .unwrap_or(0); - let profile = env::var("PROFILE").unwrap_or(String::new()); + let profile = env::var("PROFILE").unwrap_or_default(); if profile == "release" || opt_level >= 2 { println!("cargo:rustc-cfg=optimized"); } diff --git a/library/stdarch/crates/assert-instr-macro/src/lib.rs b/library/stdarch/crates/assert-instr-macro/src/lib.rs index 0c03e80653..7f2c9902e2 100644 --- a/library/stdarch/crates/assert-instr-macro/src/lib.rs +++ b/library/stdarch/crates/assert-instr-macro/src/lib.rs @@ -143,10 +143,6 @@ pub fn assert_instr( fn #assert_name() { #to_test - // Make sure that the shim is not removed by leaking it to unknown - // code: - unsafe { llvm_asm!("" : : "r"(#shim_name as usize) : "memory" : "volatile") }; - ::stdarch_test::assert(#shim_name as usize, stringify!(#shim_name), #instr); @@ -179,7 +175,7 @@ impl syn::parse::Parse for Invoc { continue; } if input.parse::().is_ok() { - instr.push_str("."); + instr.push('.'); continue; } if let Ok(s) = input.parse::() { diff --git a/library/stdarch/crates/core_arch/avx512bw.md b/library/stdarch/crates/core_arch/avx512bw.md new file mode 100644 index 0000000000..a9ce7d43e1 --- /dev/null +++ b/library/stdarch/crates/core_arch/avx512bw.md @@ -0,0 +1,558 @@ +